随机森林分类器.fit(): 值错误: 无法将字符串转换为浮点数

92

给定一个简单的 CSV 文件:

A,B,C
Hello,Hi,0
Hola,Bueno,1

显然,真实数据集比这个复杂得多,但这个数据集可以重现错误。我正在尝试构建一个随机森林分类器,代码如下:

cols = ['A','B','C']
col_types = {'A': str, 'B': str, 'C': int}
test = pd.read_csv('test.csv', dtype=col_types)

train_y = test['C'] == 1
train_x = test[cols]

clf_rf = RandomForestClassifier(n_estimators=50)
clf_rf.fit(train_x, train_y)

但是当我调用fit()函数时,我只得到了这个回溯(traceback):

ValueError: could not convert string to float: 'Bueno'

scikit-learn的版本为0.16.1。


如何将字符串列转换为因子类型,例如 df['zipcode'] = df['zipcode'].astype('category') - LeMarque
8个回答

106
在使用fit()之前,你需要进行一些编码工作。因为fit()不能接受字符串,但是你可以解决这个问题。
有几个类可用于此目的: 就我个人而言,我曾经在Stack Overflow上发布过几乎相同的问题。我想要一个可扩展的解决方案,但没有得到任何答案。我选择了OneHotEncoder来将所有字符串二元化。它非常有效,但如果有很多不同的字符串,矩阵会快速增长并需要更多内存。

7
谢谢。我最终使用DictVectorizer找到了解决方案。我有些惊讶,居然没有更好的处理这类问题的文档说明。如果我在这里有足够的声望值,我会点赞的。 - nilkn
1
在决策树中使用标签编码器可以吗?它不会判断1 < 2 < 3,等等吗? - haneulkim
@haneulkim 这不是正确的答案。而且一位有效编码也不是最优的,因为随机森林训练算法不知道如何在两个基数大于1的不同类别集之间进行分割(它只能在一个类别与其余类别之间进行分割),因此它不会最优地在这些特征上进行分割。截至本评论,sklearn中没有解决方案。请参见:stackoverflow.com/a/24715300/6238166 和这里:github.com/scikit-learn/scikit-learn/pull/12866 - Joe Silverstein

22

LabelEncoding适用于我(基本上,您必须按特征对数据进行编码)(mydata是一个字符串数据类型的2D数组):

myData=np.genfromtxt(filecsv, delimiter=",", dtype ="|a20" ,skip_header=1);

from sklearn import preprocessing
le = preprocessing.LabelEncoder()
for i in range(*NUMBER OF FEATURES*):
    myData[:,i] = le.fit_transform(myData[:,i])

19
我遇到了类似的问题,发现 pandas.get_dummies() 可以解决这个问题。具体来说,它会将分类数据的列拆分成布尔列集,每个输入列中每个唯一值都会有一个新列。在您的情况下,您需要用以下代码替换train_x = test[cols]
train_x = pandas.get_dummies(test[cols])

这将把train_x数据框转换为RandomForestClassifier可接受的以下形式:

   C  A_Hello  A_Hola  B_Bueno  B_Hi
0  0        1       0        0     1
1  1        0       1        1     0

你如何告诉RFC哪些是你的依赖变量? - Matthew Arthur

11

您不能将str传递给模型的fit()方法。如此处所述。

训练输入样本。内部将转换为dtype=np.float32,如果提供了稀疏矩阵,则为稀疏csc_matrix

尝试将数据转换为浮点数,并尝试使用LabelEncoder


5
哦,为什么有些例子明显使用字符串数据?我猜它们已经过时了或者什么的? - nilkn
例如:http://nbviewer.ipython.org/github/ofermend/IPython-notebooks/blob/master/blog-part-1.ipynb - nilkn
2
那么处理这个问题的规范方式是什么?我肯定不是第一个尝试使用scikit-learn来做这件事的人。 - nilkn

11

您不能使用 str 来适应这种类型的分类器。

例如,如果您有一个名为'grade'的特征列,其中有3个不同的等级:

A、B 和 C

您必须通过编码器将这些 str "A"、"B"、"C" 转换成矩阵,如下所示:

A = [1,0,0]

B = [0,1,0]

C = [0,0,1]

由于分类器无法将str解释为数字,因此需要进行翻译。

在scikit-learn中,可以使用inpreprocessing模块提供的OneHotEncoderLabelEncoder。但是OneHotEncoder不支持对字符串进行fit_transform()。 在转换过程中可能会出现"ValueError: could not convert string to float"。

您可以使用LabelEncoderstr转换为连续的数值,然后再使用OneHotEncoder进行转换。在Pandas数据框中,我必须对所有归类为dtype:object的数据进行编码。下面的代码适用于我,希望能对您有所帮助。

 from sklearn import preprocessing
    le = preprocessing.LabelEncoder()
    for column_name in train_data.columns:
        if train_data[column_name].dtype == object:
            train_data[column_name] = le.fit_transform(train_data[column_name])
        else:
            pass

7
OneHot编码标签编码的工作方式有重要区别:
  • 标签编码基本上会将您的字符串变量切换为int。在这种情况下,找到的第一个类将被编码为1,第二个为2,......但是这种编码会产生问题。

让我们以一个变量Animal = ["Dog", "Cat", "Turtle"]的例子来说明。

如果您对其使用标签编码,Animal将成为[1,2,3]。如果您将其解析到机器学习模型中,它将解释DogCat更接近,比Turtle更远(因为12之间的距离低于13之间的距离)。

标签编码实际上非常适用于具有自然顺序的变量。

例如,如果您有一个值Age = ["Child", "Teenager", "Young Adult", "Adult", "Old"]

那么使用标签编码就是完美的。 ChildTeenager更接近,而与Young Adult之间的距离更远。您的变量具有自然排序

  • OneHot编码(也可以通过pd.get_dummies进行)是当您的变量之间没有自然顺序时的最佳解决方案。

让我们回到先前的Animal = ["Dog", "Cat", "Turtle"]的例子。

它将创建与您遇到的类一样多的变量。在我的示例中,它将创建3个二进制变量:Dog,Cat和Turtle。然后,如果您有Animal =“Dog”,编码将使其成为Dog = 1,Cat = 0,Turtle = 0

然后您可以将此提交给您的模型,他将永远不会解释DogCat更接近Turtle

但是OneHot编码也有缺点。如果您有一个包含50种类别的分类变量

例如:Dog,Cat,Turtle,Fish,Monkey,...

那么它将创建50个二进制变量,这可能会引起复杂性问题。在这种情况下,您可以创建自己的类并手动更改变量

例如:将Turtle,Fish,Dolphin,Shark合并到名为海洋生物的同一类中,然后应用OneHot编码。


0

由于您的输入是字符串,因此您会收到值错误消息。使用CountVectorizer将数据集转换为稀疏矩阵并训练ml算法,您将获得结果。


嗨,Raghu。你可以尝试通过提供示例代码或示例输入输出来改进这个答案。这可以帮助提问者理解你的答案,这也是答案的最终目的。 - dsapalo
将数据分为测试集和训练集后: count_vectorizer = CountVectorizer() X_count = count_vectorizer.fit_transform(x_train) neigh=KNeighborsClassifier(n_neighbors=1,weights='uniform',algorithm='brute') neigh.fit(X_count ,y_train_bow) - raghu

-1

确实,一个独热编码器在这里可以很好地工作,将您想要的任何字符串和数值分类变量转换为1和0,这样随机森林就不会抱怨。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接