我想使用多个特征来训练朴素贝叶斯分类器,以分类’A’或’非A’。
我有三种不同类型值的特征:1) total_length – 正整数类型2) vowel-ratio – 小数/分数类型3) twoLetters_lastName – 包含多个两个字母字符串的数组
# coding=utf-8from nltk.corpus import namesimport nltkimport randomimport numpy as npimport pandas as pdfrom pandas import DataFrame, Seriesfrom sklearn.naive_bayes import GaussianNBimport sysreload(sys)sys.setdefaultencoding('utf-8')# Import data into pandasdata = pd.read_csv('XYZ.csv', header=0, encoding='utf-8', low_memory=False)df = DataFrame(data)# Randomize recordsdf = df.reindex(np.random.permutation(df.index))# Assign column into label Ydf_Y = df[df.AScan.notnull()][['AScan']].values # Labels are 'A' or 'non-A'#print df_Y# Assign column vector into attribute Xdf_X = df[df.AScan.notnull()][['total_length', 'vowel_ratio', 'twoLetters_lastName']].values#print df_X[0:10]# Incorporate X and Y into ML algorithmsclf = GaussianNB()clf.fit(df_X, df_Y)
df_Y如下所示:
[[u'non-A'] [u'A'] [u'non-A'] ..., [u'A'] [u'non-A'] [u'non-A']]
df_X如下所示:
[[9L 0.222222222 u"[u'ke', u'el', u'll', u'ly']"] [17L 0.41176470600000004 u"[u'ma', u'ar', u'rg', u'ga', u'ar', u'ri', u'is']"] [11L 0.454545455 u"[u'du', u'ub', u'bu', u'uc']"] [11L 0.454545455 u"[u'ma', u'ah', u'he', u'er']"] [15L 0.333333333 u"[u'ma', u'ag', u'ge', u'ee']"] [13L 0.307692308 u"[u'jo', u'on', u'ne', u'es']"] [12L 0.41666666700000005 u"[u'le', u'ef', u'f\\xe8', u'\\xe8v', u'vr', u're']"] [15L 0.26666666699999997 u"[u'ni', u'ib', u'bl', u'le', u'et', u'tt']"] [15L 0.333333333 u"[u'ki', u'in', u'ns', u'sa', u'al', u'll', u'la']"] [11L 0.363636364 u"[u'mc', u'cn', u'ne', u'ei', u'il']"]]
我遇到了以下错误:
E:\Program Files Extra\Python27\lib\site-packages\sklearn\naive_bayes.py:150: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel(). y = column_or_1d(y, warn=True)Traceback (most recent call last): File "C:werwer\wer\wer.py", line 32, in <module> clf.fit(df_X, df_Y) File "E:\Program Files Extra\Python27\lib\site-packages\sklearn\naive_bayes.py", line 163, in fit self.theta_[i, :] = np.mean(Xi, axis=0) File "E:\Program Files Extra\Python27\lib\site-packages\numpy\core\fromnumeric.py", line 2727, in mean out=out, keepdims=keepdims) File "E:\Program Files Extra\Python27\lib\site-packages\numpy\core\_methods.py", line 69, in _mean ret, rcount, out=ret, casting='unsafe', subok=False)TypeError: unsupported operand type(s) for /: 'unicode' and 'long'
我的理解是需要将特征转换为一个numpy数组作为特征向量,但我认为我准备的X向量可能不对,因为它包含了非常不同的值类型。
回答:
相关问题: 选择分类算法来分类名义和数值数据的混合 — 在使用Scikit-learn的朴素贝叶斯分类器中混合分类和连续数据
好的,有几件事需要注意。正如DalekSec指出的那样,最佳做法是将所有特征保持为一种类型,然后输入到像GaussianNB
这样的模型中。回溯信息显示,在拟合模型时,它试图将一个字符串(可能是像u"[u'ke', u'el', u'll', u'ly']"
这样的unicode字符串)除以一个整数。所以我们需要做的是将训练数据转换成sklearn可以使用的形式。我们可以通过几种方式来做到这一点,其中两种方式在这里由ogrisel详细描述。
-
我们可以将所有连续变量转换为分类变量。在我们的案例中,这意味着转换
total_length
(在某些情况下,你可能可以将其视为分类变量,但我们先不考虑这些)和vowel-ratio
。例如,你可以根据每个特征的百分位数将看到的值分成5个值:’非常小’、’小’、’中等’、’高’、’非常高’。据我所知,sk-learn中没有真正简单的方法,但自己做应该相当简单。你唯一需要改变的是,你应该使用MultinomialNB
而不是GaussianNB
,因为你将处理更适合用多项式分布而不是高斯分布来描述的特征。 -
我们可以将分类特征转换为数值特征以用于
GaussianNB
。我个人认为这是更直观的方法。基本上,当处理文本时,你需要弄清楚你想从文本中提取什么样的信息并传递给分类器。看起来你想提取不同两个字母姓氏的出现频率。通常我会问你是否拥有数据集中所有的姓氏,但由于每个姓氏只有两个字母,我们可以只存储所有可能的两个字母姓氏(包括带有重音符号的unicode字符),这对性能的影响最小。这里像sklearn的
CountVectorizer
可能会有用。假设你有数据中所有可能的两个字母姓氏组合,你可以直接使用它将twoLetter_lastname列中的一行转换为一个N维向量,该向量记录你行中每个唯一姓氏的出现次数。然后将这个新向量与你的其他两个特征组合成一个numpy数组。如果你没有所有可能的两个字母组合(包括带重音的),你应该考虑生成这个列表并将其作为’vocabulary’传递给CountVectorizer。这样你的分类器就知道如何处理所有可能的姓氏。如果你不处理所有情况,这不是世界末日,但任何新的未见过的两个字母对将在这个方案中被忽略。
在使用这些工具之前,你应该确保将你的姓氏列作为列表传递,而不是作为字符串,因为这可能会导致意外的行为。
你可以在这里阅读更多关于sklearn预处理的信息,以及更多关于
CountVectorizer
和其他由sklearn提供的文本特征提取工具的信息。我每天使用很多这些工具,并推荐它们用于基本的文本提取任务。网上也有很多教程和演示。你还可以寻找其他类型的表示方法,如二值化和独热编码。解决这个问题的方法有很多,主要取决于你的具体问题/需求。
当你能够将所有数据转换为一种形式或另一种形式后,你应该能够使用高斯或多项式NB分类器。至于你关于1D向量的错误,你打印了df_Y,它看起来像
[[u'non-A'] [u'A'] [u'non-A'] ..., [u'A'] [u'non-A'] [u'non-A']]
基本上,它期望这是一个平面列表,而不是一个列向量(一个一维列表的列表)。只需使用像numpy.reshape()或numpy.ravel()这样的命令相应地重塑它(考虑到你只处理一列,正如错误中提到的,numpy.ravel()可能会更合适)。