【问题标题】:Using DictVectorizer with sklearn DecisionTreeClassifier将 DictVectorizer 与 sklearn DecisionTreeClassifier 一起使用
【发布时间】:2013-02-17 08:18:14
【问题描述】:

我尝试使用 python 和 sklearn 启动决策树。 工作方法是这样的:

import pandas as pd
from sklearn import tree

for col in set(train.columns):
    if train[col].dtype == np.dtype('object'):
        s = np.unique(train[col].values)
        mapping = pd.Series([x[0] for x in enumerate(s)], index = s)
        train_fea = train_fea.join(train[col].map(mapping))
    else:
        train_fea = train_fea.join(train[col])

dt = tree.DecisionTreeClassifier(min_samples_split=3,
                             compute_importances=True,max_depth=5)
dt.fit(train_fea, labels)

现在我尝试用 DictVectorizer 做同样的事情,但我的代码不起作用:

from sklearn.feature_extraction import DictVectorizer

vec = DictVectorizer(sparse=False)
train_fea = vec.fit_transform([dict(enumerate(sample)) for sample in train])

dt = tree.DecisionTreeClassifier(min_samples_split=3,
                             compute_importances=True,max_depth=5)
dt.fit(train_fea, labels)

最后一行出现错误:“ValueError:标签数=332448 与样本数=55 不匹配”。正如我从文档中了解到的那样,DictVectorize 旨在将名义特征转换为数字特征。我做错了什么?

已更正(感谢 ogrisel 推动我制作完整示例):

import pandas as pd
import numpy as np
from sklearn import tree

##################################
#  working example
train = pd.DataFrame({'a' : ['a', 'b', 'a'], 'd' : ['e', 'e', 'f'],
                  'b' : [0, 1, 1], 'c' : ['b', 'c', 'b']})
columns = set(train.columns)
columns.remove('b')
train_fea = train[['b']]

for col in columns:
    if train[col].dtype == np.dtype('object'):
        s = np.unique(train[col].values)
        mapping = pd.Series([x[0] for x in enumerate(s)], index = s)
        train_fea = train_fea.join(train[col].map(mapping))
    else:
        train_fea = train_fea.join(train[col])

dt = tree.DecisionTreeClassifier(min_samples_split=3,
                         compute_importances=True,max_depth=5)
dt.fit(train_fea, train['c'])

##########################################
# example with DictVectorizer and error

from sklearn.feature_extraction import DictVectorizer

vec = DictVectorizer(sparse=False)
train_fea = vec.fit_transform([dict(enumerate(sample)) for sample in train])

dt = tree.DecisionTreeClassifier(min_samples_split=3,
                         compute_importances=True,max_depth=5)
dt.fit(train_fea, train['c'])

在 ogrisel 的帮助下修复了最后的代码:

import pandas as pd
from sklearn import tree
from sklearn.feature_extraction import DictVectorizer
from sklearn import preprocessing

train = pd.DataFrame({'a' : ['a', 'b', 'a'], 'd' : ['e', 'x', 'f'],
                  'b' : [0, 1, 1], 'c' : ['b', 'c', 'b']})

# encode labels
labels = train[['c']]
le = preprocessing.LabelEncoder()
labels_fea = le.fit_transform(labels) 
# vectorize training data
del train['c']
train_as_dicts = [dict(r.iteritems()) for _, r in train.iterrows()]
train_fea = DictVectorizer(sparse=False).fit_transform(train_as_dicts)
# use decision tree
dt = tree.DecisionTreeClassifier()
dt.fit(train_fea, labels_fea)
# transform result
predictions = le.inverse_transform(dt.predict(train_fea).astype('I'))
predictions_as_dataframe = train.join(pd.DataFrame({"Prediction": predictions}))
print predictions_as_dataframe

一切正常

【问题讨论】:

  • 目前还不清楚sample的结构是什么。你的训练集中有多少样本?您能否在说明中打印此类示例的示例?
  • 已修复 - 我已添加示例代码
  • 谢谢我现在回答。

标签: python machine-learning scikit-learn


【解决方案1】:

枚举样本的方式没有意义。只需打印它们以使其明显:

>>> import pandas as pd
>>> train = pd.DataFrame({'a' : ['a', 'b', 'a'], 'd' : ['e', 'e', 'f'],
...                       'b' : [0, 1, 1], 'c' : ['b', 'c', 'b']})
>>> samples = [dict(enumerate(sample)) for sample in train]
>>> samples
[{0: 'a'}, {0: 'b'}, {0: 'c'}, {0: 'd'}]

现在这在语法上是一个 dicts 列表,但与您期望的完全不同。尝试这样做:

>>> train_as_dicts = [dict(r.iteritems()) for _, r in train.iterrows()]
>>> train_as_dicts
[{'a': 'a', 'c': 'b', 'b': 0, 'd': 'e'},
 {'a': 'b', 'c': 'c', 'b': 1, 'd': 'e'},
 {'a': 'a', 'c': 'b', 'b': 1, 'd': 'f'}]

这看起来好多了,现在让我们尝试对这些字典进行矢量化:

>>> from sklearn.feature_extraction import DictVectorizer

>>> vectorizer = DictVectorizer()
>>> vectorized_sparse = vectorizer.fit_transform(train_as_dicts)
>>> vectorized_sparse
<3x7 sparse matrix of type '<type 'numpy.float64'>'
    with 12 stored elements in Compressed Sparse Row format>

>>> vectorized_array = vectorized_sparse.toarray()
>>> vectorized_array
array([[ 1.,  0.,  0.,  1.,  0.,  1.,  0.],
       [ 0.,  1.,  1.,  0.,  1.,  1.,  0.],
       [ 1.,  0.,  1.,  1.,  0.,  0.,  1.]])

要获取每列的含义,请询问向量器:

>>> vectorizer.get_feature_names()
['a=a', 'a=b', 'b', 'c=b', 'c=c', 'd=e', 'd=f']

【讨论】:

  • ogrisel,非常感谢,它有效。但现在我无法收到我的标签了:)。为问题添加了工作代码。
  • 您能否将答案标记为已接受?它有助于跟踪用户尚未回答的问题。
  • 对于标签,直接将它们传递给DecisionTreeClassifier,不使用DictVectorizer:标签默认是分类的。
  • 奥利弗,谢谢你的回答!如果我不使用 DictVectorizer 我收到错误“ValueError:无法将字符串转换为浮点数:b”
  • 好吧对不起,对于标签,有些分类器直接接受字符串,其他的仍然需要手动通过LabelEncoder。将来 sklearn 中的所有分类器都应该在内部使用 LabelEncoder。
【解决方案2】:

vec.fit_transform 返回一个稀疏数组。而 IIRC DecisionTreeClassifier 不能很好地解决这个问题。

在传递给DecisionTreeClassifier之前尝试train_fea = train_fea.toarray()

【讨论】:

  • train 是一个数据框,train_fea 是一个 numpy.ndarray,所以如果我写 dt.fit(train_fea.toarray(), labels) 给我一个错误“AttributeError: 'numpy.ndarray' object没有属性'toarray'"
  • 如果你打印 train_fea 你有 3 行第一段代码和 4 行第二段代码
  • 如果我不使用 vec = DictVectorizer(sparse=False),你会是对的。在 'sparse=False' 的情况下,不需要添加 .toarray()。
猜你喜欢
  • 2015-11-19
  • 2020-10-10
  • 2019-05-02
  • 2013-12-11
  • 2014-02-03
  • 2016-04-02
  • 2021-12-26
  • 2020-07-14
相关资源
最近更新 更多