好的,我正在学习Andrew Ng的机器学习课程。目前我在阅读这一章,想尝试使用SKLearn和Python自己实现多项式朴素贝叶斯(见第12页底部)。Andrew提出了一种方法,其中每封邮件都被编码成这样
我们用
x_i
表示邮件中第i
个词的身份。因此,x_i
现在是一个整数,取值在{1, . . . , |V|}
之间,其中|V|
是我们词汇表(字典)的大小。一封包含n个词的邮件现在被表示为长度为n
的向量(x1, x2, . . . , xn)
,注意不同文档的n可能会变化。例如,如果一封邮件以“A NIPS . . . , ”
开头,那么x_1 = 1
(“a”
是字典中的第一个词),而x2 = 35000
(如果“nips”
是字典中的第35000个词)。
请看重点内容。
所以我也在Python中做了同样的事情。我有一个vocabulary
,它是一个包含502个词的列表,我对每封“邮件”进行了编码,使其与Andrew描述的方式相同,例如消息“this is sparta”被表示为[495, 296, 359]
,而“this is not sparta”被表示为[495, 296, 415, 359]
。
所以问题来了。
显然,SKLearn的MultinomialNB
要求输入具有统一的形状(我对此不是很确定,但目前我得到的错误是ValueError: setting an array element with a sequence.
,我认为这是因为输入向量的大小不一致)。
那么我的问题是,我如何使用MultinomialNB
处理不同长度的消息?这是可能的吗?我错过了什么?
这是我正在做的部分代码:
X = posts['wordsencoded'].valuesy = posts['highview'].valuesclf = MultinomialNB()clf.fit(X, y)MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True)print(clf.predict())
堆栈跟踪:
---------------------------------------------------------------------------ValueError Traceback (most recent call last)<ipython-input-933-dea987cd8603> in <module>() 3 y = posts['highview'].values 4 clf = MultinomialNB()----> 5 clf.fit(X, y) 6 MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True) 7 print(clf.predict())/usr/local/lib/python3.4/dist-packages/sklearn/naive_bayes.py in fit(self, X, y, sample_weight) 525 Returns self. 526 """--> 527 X, y = check_X_y(X, y, 'csr') 528 _, n_features = X.shape 529 /usr/local/lib/python3.4/dist-packages/sklearn/utils/validation.py in check_X_y(X, y, accept_sparse, dtype, order, copy, force_all_finite, ensure_2d, allow_nd, multi_output, ensure_min_samples, ensure_min_features, y_numeric, warn_on_dtype, estimator) 508 X = check_array(X, accept_sparse, dtype, order, copy, force_all_finite, 509 ensure_2d, allow_nd, ensure_min_samples,--> 510 ensure_min_features, warn_on_dtype, estimator) 511 if multi_output: 512 y = check_array(y, 'csr', force_all_finite=True, ensure_2d=False,/usr/local/lib/python3.4/dist-packages/sklearn/utils/validation.py in check_array(array, accept_sparse, dtype, order, copy, force_all_finite, ensure_2d, allow_nd, ensure_min_samples, ensure_min_features, warn_on_dtype, estimator) 371 force_all_finite) 372 else:--> 373 array = np.array(array, dtype=dtype, order=order, copy=copy) 374 375 if ensure_2d:ValueError: setting an array element with a sequence.
回答:
是的,你的想法是对的。你需要用固定长度的向量对每封邮件进行编码。这个向量称为词频向量,在你的例子中,每封训练集邮件都有一个502维的词频向量。
每个词频向量包含训练文件中502个字典词的频率。当然,你可能已经猜到其中大部分都会是零。例如:“this is not sparta not is this sparta”将被编码如下:[0,0,0,0,0,…….0,0,2,0,0,0,……,0,0,2,0,0,…0,0,2,0,0,……2,0,0,0,0,0,0]
这里,所有四个2分别位于502长度词频向量的第296、359、415和495个索引位置。
因此,将生成一个特征向量矩阵,其行表示训练集文件的数量,列表示字典中的502个词。索引‘ij’处的值将是字典中第j个词在第i个文件中的出现次数。
这种生成的邮件编码(特征向量矩阵)可以提供给MultinomialNB进行训练。
在预测类别之前,你还需要为测试邮件生成类似的502长度编码。
你可以使用以下博客在ling-spam数据集上轻松构建一个使用MultinomialNB的垃圾邮件过滤器分类器。该博客文章使用了sklearn和Python进行实现。
https://appliedmachinelearning.wordpress.com/2017/01/23/nlp-blog-post/