如何将数据帧转换为具有混合列类型的稀疏矩阵?

时间:2017-01-09 12:07:44

标签: python pandas scipy scikit-learn sparse-matrix

我有以下格式的数据框:

df:

key   f1    f2
k1    10    a, b, c
k2    20    b, d
k3    15    NaN

列f2有一个单词作为值。我想将这个数据帧转换为稀疏矩阵,因为f2中的不同单词会运行到几千个。我期待的最终结果是以下格式:

key    f1  f2.a  f2.b  f2.c  f2.d
k1     10   1     1     1     0
k2     20   0     1     0     1
k3     15   0     0     0     0

我可以弄清楚如何在key和f2字段之外独立创建稀疏矩阵。我首先将列f2融化,因此我得到了以下数据帧:

df1:
key  f2
k1   a
k1   b
k1   c
k2   b
k2   d

然后我编码f2,并使用sklearn.preprocessing包中的LabelEncoder来编码f2。然后我创建一个稀疏矩阵,如下所示:

df1['trainrow'] = np.arrange(df1.shape[0])
sparse.csr_matrix((np.ones(df1.shape[0], (df1.trainrow, df1.f2_encoded)))

这通过对字段f2进行单热编码来创建稀疏矩阵。但我不确定如何将其与数字字段f1连接起来。

2 个答案:

答案 0 :(得分:2)

您可以将concatstr.get_dummiesadd_prefix

一起使用
df = pd.concat([df[['key','f1']], df.f2.str.get_dummies(sep=', ').add_prefix('f2.')], axis=1)
print (df)
  key  f1  f2.a  f2.b  f2.c  f2.d
0  k1  10     1     1     1     0
1  k2  20     0     1     0     1
2  k3  15     0     0     0     0

在非常大的不同值get_dummies非常慢,您可以使用自定义函数f

def f(category_list):
    n_categories = len(category_list)
    return pd.Series(dict(zip(category_list, [1]*n_categories)))

#remove NaN rows and create list of values by split
df1 = df.f2.dropna().str.split(', ').apply(f).add_prefix('f2.')
df2 = pd.concat([df[['key','f1']], df1], axis=1)
#replace NaN to 0 by position from 3.column to end of df
df2.iloc[:, 2: ] = df2.iloc[:, 2: ].fillna(0).astype(int)
print (df2)
  key  f1  f2.a  f2.b  f2.c  f2.d
0  k1  10     1     1     1     0
1  k2  20     0     1     0     1
2  k3  15     0     0     0     0

<强>计时

In [256]: %timeit s.str.get_dummies(sep=', ')
1 loop, best of 3: 1min 16s per loop

In [257]: %timeit (s.dropna().str.split(', ').apply(f).fillna(0).astype(int))
1 loop, best of 3: 2.95 s per loop

时间安排的代码

np.random.seed(100)
s = pd.DataFrame(np.random.randint(10000, size=(1000,1000))).astype(str).apply(', '.join, axis=1)
print (s)


df2 = s.str.get_dummies(sep=', ')
print (df2)

def f(category_list):
    n_categories = len(category_list)
    return pd.Series(dict(zip(category_list, [1]*n_categories)))

print (s.dropna().str.split(', ').apply(f).fillna(0).astype(int))

答案 1 :(得分:0)

我已经找到了解决这个问题的最佳方式,因此将其作为我未来参考的答案并为了其他人的利益而发布:

由于数据量巨大,我不得不使用稀疏矩阵。

第一步是将单词包转换为矢量化格式。我使用了CountVectorizer(感谢@MaxU),如下所示:

from sklearn.feature_extraction.text import CountVectorizer

vectorizer = CountVectorizer()
df2 = vectorizer.fit_transform(df['f2'].str.replace(' ',''))

我想忽略空格并使用逗号作为强制分隔符。我无法弄清楚如何做到这一点所以我已经替换了空格,否则矢量化器会在空格处分割单词。

这已经将df1创建为稀疏矩阵。

然后将另一个字段f1转换为不同的稀疏矩阵:

df1 = csr_matrix(df[['f1']].fillna(0))

然后使用hstack将这两者结合起来:     sparseDF = hstack((df1,df2),format ='csr')