为 Scikit-Learn 向量化 Pandas 数据框
Posted
技术标签:
【中文标题】为 Scikit-Learn 向量化 Pandas 数据框【英文标题】:Vectorizing a Pandas dataframe for Scikit-Learn 【发布时间】:2013-11-30 05:36:26 【问题描述】:假设我在 Pandas 中有一个如下所示的数据框:
> my_dataframe
col1 col2
A foo
B bar
C something
A foo
A bar
B foo
其中行代表实例,列输入特征(不显示目标标签,但这将用于分类任务),即我试图用my_dataframe
构建X。
我怎样才能有效地使用例如矢量化它? DictVectorizer
?
我是否需要先将 DataFrame 中的每个条目都转换为字典? (这就是上面链接中的示例中完成的方式)。有没有更有效的方法来做到这一点?
【问题讨论】:
【参考方案1】:你绝对可以使用DictVectorizer
。因为DictVectorizer
需要一个可迭代的dict
类对象,您可以执行以下操作:
from sklearn.base import TransformerMixin
from sklearn.pipeline import make_pipeline
from sklearn.feature_extraction import DictVectorizer
class RowIterator(TransformerMixin):
""" Prepare dataframe for DictVectorizer """
def fit(self, X, y=None):
return self
def transform(self, X):
return (row for _, row in X.iterrows())
vectorizer = make_pipeline(RowIterator(), DictVectorizer())
# now you can use vectorizer as you might expect, e.g.
vectorizer.fit_transform(df)
【讨论】:
【参考方案2】:您想从包含分类(或简单的字符串)的 pandas DataFrame 构建设计矩阵,最简单的方法是使用 patsy,这是一个复制和扩展 R 公式功能的库。
使用您的示例,转换将是:
import pandas as pd
import patsy
my_df = pd.DataFrame('col1':['A', 'B', 'C', 'A', 'A', 'B'],
'col2':['foo', 'bar', 'something', 'foo', 'bar', 'foo'])
patsy.dmatrix('col1 + col2', data=my_df) # With added intercept
patsy.dmatrix('0 + col1 + col2', data=my_df) # Without added intercept
生成的设计矩阵只是带有一些额外信息的 NumPy 数组,可以直接在 scikit-learn 中使用。
添加截距的示例结果:
DesignMatrix with shape (6, 5)
Intercept col1[T.B] col1[T.C] col2[T.foo] col2[T.something]
1 0 0 1 0
1 1 0 0 0
1 0 1 0 1
1 0 0 1 0
1 0 0 0 0
1 1 0 1 0
Terms:
'Intercept' (column 0)
'col1' (columns 1:3)
'col2' (columns 3:5)
请注意,patsy 试图通过将A
和bar
的效果合并到截距中来避免多重共线性。这样,例如,col1[T.B]
预测变量应该被解释为 B
与归类为 A
的观察相关的附加效果。
【讨论】:
【参考方案3】:首先,我不知道您的示例数组中的哪些位置是特征,以及观察值在哪里。
其次,DictVectorizer
不保存数据,仅用于转换实用程序和元数据存储。转换后,它存储特征名称和映射。它返回一个 numpy 数组,用于进一步计算。 Numpy 数组(特征矩阵)大小等于features count
x number of observations
,其值等于观察的特征值。因此,如果您了解自己的观察结果和特征,则可以以任何其他方式创建此数组。
如果您希望 sklearn 为您执行此操作,则不必手动重建 dict,因为可以将 to_dict
应用于转置数据帧:
>>> df
col1 col2
0 A foo
1 B bar
2 C foo
3 A bar
4 A foo
5 B bar
>>> df.T.to_dict().values()
['col2': 'foo', 'col1': 'A', 'col2': 'bar', 'col1': 'B', 'col2': 'foo', 'col1': 'C', 'col2': 'bar', 'col1': 'A', 'col2': 'foo', 'col1': 'A', 'col2': 'bar', 'col1': 'B']
自 scikit-learn 0.13.0(2014 年 1 月 3 日)以来,to_dict()
方法有一个新参数 'records'
,因此现在您可以简单地使用此方法而无需额外操作:
>>> df = pandas.DataFrame('col1': ['A', 'B', 'C', 'A', 'A', 'B'], 'col2': ['foo', 'bar', 'foo', 'bar', 'foo', 'bar'])
>>> df
col1 col2
0 A foo
1 B bar
2 C foo
3 A bar
4 A foo
5 B bar
>>> df.to_dict('records')
['col2': 'foo', 'col1': 'A', 'col2': 'bar', 'col1': 'B', 'col2': 'foo', 'col1': 'C', 'col2': 'bar', 'col1': 'A', 'col2': 'foo', 'col1': 'A', 'col2': 'bar', 'col1': 'B']
【讨论】:
每一行是一个实例,即一个样本或观察值,每一列是一个特征类型。在上面的示例中,我有 6 个样本,每个样本都是二维的,即我的特征矩阵 X 的大小为 (6,2)。任务是对 X 中的每一列进行矢量化,因为它们包含文本条目并且不能直接输入到分类器或回归器中。 @user815423426 终于明白了。您可能想关注马特的回答或使用to_dict
来获取所需的字典(请参阅更新)【参考方案4】:
查看sklearn-pandas
,它提供了您正在寻找的内容。对应的 Github repo 是here。
【讨论】:
假设我有 40 列,我只想对几列进行矢量化,并将其余列保留在 DataFrame 中,这样我就可以将生成的 numpy 矩阵直接提供给 scikit-learn .这在 sklearn-pandas 中可行吗?我的意思是 sklearn-pandas 很好,但是当我调用 mapper.transform() 时,它只给我转换后的列,而不是所有列以及转换后的列。 只需column_stack
将转换后的特征和原始特征放在一起。类似:np.column_stack([mapper.transform(train), train[['c1', 'c2', ...]].values])
,其中np
是import numpy as np
您也可以在 sklearn DataFrameMapper
中使用 None
作为转换器,用于您想要保持不变的列。以上是关于为 Scikit-Learn 向量化 Pandas 数据框的主要内容,如果未能解决你的问题,请参考以下文章