将熊猫单列转换为Scipy稀疏矩阵

时间:2020-08-05 20:57:12

标签: pandas scipy sparse-matrix sklearn-pandas

我有一个这样的熊猫数据框:

     a                           other-columns
   0.3 0.2 0.0 0.0 0.0...        ....

我想将列a转换为SciPy稀疏CSR矩阵。 a是概率分布。我想进行转换而无需将a扩展为多列。

这是将a扩展为多列的幼稚解决方案:

  df = df.join(df['a'].str.split(expand = True).add_prefix('a')).drop(['a'], axis = 1)
  df_matrix = scipy.sparse.csr_matrix(df.values)

但是,我不想扩展为多列,因为它会占用大量内存。是否可以仅将a保留在1列中?

编辑(最小可复制示例):

 import pandas as pd
 from scipy.sparse import csr_matrix
 d = {'a': ['0.05 0.0', '0.2 0.0']}
 df = pd.DataFrame(data=d)
 df = df.join(df['a'].str.split(expand = True).add_prefix('a')).drop(['a'], axis = 1)
 df = df.astype(float)
 df_matrix = scipy.sparse.csr_matrix(df.values)
 df_matrix

输出:

 <2x2 sparse matrix of type '<class 'numpy.float64'>'
with 2 stored elements in Compressed Sparse Row format>

我想实现以上目标,但又不要分成多列。另外,在我的真实文件中,我有36个长度的字符串(用空格分隔)列和数百万行。确保所有行都包含36个空格。

2 个答案:

答案 0 :(得分:1)

您无需展开即可从列中获取密集数组:

In [179]: df = pd.DataFrame(data=d)                                                                  

例如

In [180]: np.array(df['a'].str.split().tolist(),float)                                               
Out[180]: 
array([[0.05, 0.  ],
       [0.2 , 0.  ]])

但是我怀疑这是否可以节省很多内存(尽管我对DataFrame内存使用只有粗略的了解。

您可以将每个字符串转换为稀疏矩阵:

In [190]: def foo(astr): 
     ...:     alist = astr.split() 
     ...:     arr = np.array(alist, float) 
     ...:     return sparse.coo_matrix(arr) 
                                                                                               
In [191]: alist = [foo(row) for row in df['a']]                                                      
In [192]: alist                                                                                      
Out[192]: 
[<1x2 sparse matrix of type '<class 'numpy.float64'>'
    with 1 stored elements in COOrdinate format>,
 <1x2 sparse matrix of type '<class 'numpy.float64'>'
    with 1 stored elements in COOrdinate format>]
In [193]: sparse.vstack(alist)                                                                       
Out[193]: 
<2x2 sparse matrix of type '<class 'numpy.float64'>'
    with 2 stored elements in COOrdinate format>

我尝试直接从coo中制作alist,但这并没有消除零。转换的次数也很多,但是如果足够稀疏(5%或更少),则可以节省大量内存(如果没有时间的话)。

sparse.vstack组合了来自组件矩阵的data,rows,cols值以定义新的coo矩阵。如果不是最快的话,这是组合稀疏矩阵的最直接方法。

好像我也可以使用apply

In [205]: df['a'].apply(foo)                                                                         
Out[205]: 
0      (0, 0)\t0.05
1       (0, 0)\t0.2
Name: a, dtype: object
In [206]: df['a'].apply(foo).values                                                                  
Out[206]: 
array([<1x2 sparse matrix of type '<class 'numpy.float64'>'
    with 1 stored elements in COOrdinate format>,
       <1x2 sparse matrix of type '<class 'numpy.float64'>'
    with 1 stored elements in COOrdinate format>], dtype=object)
In [207]: sparse.vstack(df['a'].apply(foo))                                                          
Out[207]: 
<2x2 sparse matrix of type '<class 'numpy.float64'>'
    with 2 stored elements in COOrdinate format>

答案 1 :(得分:1)

此外,在我的真实文件中,我有36个长度的字符串(用空格分隔)列和数百万行。确保所有行都包含36个空格。

Convert large csv to sparse matrix for use in sklearn

我不能高估你不应该做多少跟在这句话后面的事情。

import pandas as pd
import numpy as np
from scipy import sparse

df = pd.DataFrame({'a': ['0.05 0.0', '0.2 0.0'] * 100000})
chunksize = 10000

sparse_coo = []
for i in range(int(np.ceil(df.shape[0]/chunksize))):
    chunk = df.iloc[i * chunksize:min(i * chunksize +chunksize, df.shape[0]), :]
    sparse_coo.append(sparse.coo_matrix(chunk['a'].apply(lambda x: [float(y) for y in x.split()]).tolist()))

sparse_coo = sparse.vstack(sparse_coo)