将 pandas 单列转换为 Scipy 稀疏矩阵

Convert pandas single column to Scipy Sparse Matrix

我有一个这样的 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 个长度的字符串(由 space 分隔)列和数百万行。可以肯定所有行将包含 36 spaces.

您可以在不展开的情况下从列中获取密集数组:

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>

我试图直接从 alist 生成 coo,但是没有 trim 出零。转换也一样多,但如果足够稀疏(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>

Also, in my real file, I have 36 length string (separated by space) columns and millions of rows. It is sure that all rows will contain 36 spaces.

我怎么强调都不应该做这句话后面的事情。

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)