2015-06-27 90 views
11

有没有办法将pandas.SparseDataFrame转换为scipy.sparse.csr_matrix,而不会在内存中生成一个密集的矩阵?熊猫稀疏dataFrame稀疏矩阵,没有在内存中生成一个密集的矩阵

scipy.sparse.csr_matrix(df.values) 

不起作用,因为它会生成一个致密的矩阵,投射到csr_matrix

提前致谢!有关实验转换

+0

运行此相反? http://stackoverflow.com/questions/17818783/populate-a-pandas-sparsedataframe-from-a-scipy-sparse-matrix – JohnE

回答

0

熊猫文档会谈SciPy的稀疏,SparseSeries.to_coo:

http://pandas-docs.github.io/pandas-docs-travis/sparse.html#interaction-with-scipy-sparse

================

编辑 - 这是多索引而不是数据帧的特殊功能。请参阅其他答案。请注意日期的差异。

============

作为0.20.0,有一个sdf.to_coo()和多指标ss.to_coo()。由于稀疏矩阵本质上是2D的,因此需要(有效)1d数据集的多索引是有意义的。而数据框可以表示一个表或二维数组。

当我第一次回答这个问题时,这个稀疏的数据框/系列功能是实验性的(2015年6月)。

+0

这只适用于'MultiIndex'-ed'SparseSeries',不适用于DataFrame。 –

+0

作为@eleanora提到,[现在确实有效](http://pandas-docs.github.io/pandas-docs-travis/generated/pandas.SparseDataFrame.to_coo.html#pandas.SparseDataFrame.to_coo)(as版本0.20.0,2017年5月5日发布)。 'sparse.csr_matrix(df.to_coo())'是可以实现这一功能的单线程。也许你应该编辑你的答案,以明确这一点? –

+0

也许我们应该接近主题日期? – hpaulj

0

下面是一个按列填充稀疏矩阵的解决方案(假设您可以将至少一列填充到内存中)。

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

def sparse_df_to_array(df): 
    """ Convert sparse dataframe to sparse array csr_matrix used by 
    scikit learn. """ 
    arr = lil_matrix(df.shape, dtype=np.float32) 
    for i, col in enumerate(df.columns): 
     ix = df[col] != 0 
     arr[np.where(ix), i] = df.ix[ix, col] 

    return arr.tocsr() 
3

@Marigold的答案可以做到这一点,但由于访问每列中的所有元素(包括零),它的速度很慢。在此基础上,我编写了以下快速n'脏代码,它在密度约为1%的1000x1000矩阵上运行速度提高了50倍。我的代码也适当地处理密集列。

def sparse_df_to_array(df): 
    num_rows = df.shape[0] 

    data = [] 
    row = [] 
    col = [] 

    for i, col_name in enumerate(df.columns): 
     if isinstance(df[col_name], pd.SparseSeries): 
      column_index = df[col_name].sp_index 
      if isinstance(column_index, BlockIndex): 
       column_index = column_index.to_int_index() 

      ix = column_index.indices 
      data.append(df[col_name].sp_values) 
      row.append(ix) 
      col.append(len(df[col_name].sp_values) * [i]) 
     else: 
      data.append(df[col_name].values) 
      row.append(np.array(range(0, num_rows))) 
      col.append(np.array(num_rows * [i])) 

    data_f = np.concatenate(data) 
    row_f = np.concatenate(row) 
    col_f = np.concatenate(col) 

    arr = coo_matrix((data_f, (row_f, col_f)), df.shape, dtype=np.float64) 
    return arr.tocsr() 
6

熊猫0.20.0+:

由于大熊猫版本0.20.0,2017年5月5日发布的,还有一个班轮此:

from scipy import sparse 


def sparse_df_to_csr(df): 
    return sparse.csr_matrix(df.to_coo()) 

这将使用新to_coo() method

早期版本:

大厦维克多五月的答案,这里有一个稍快的实现,但它仅适用,如果整个SparseDataFrame是稀疏的所有BlockIndex(注:若曾get_dummies创建的,这将是案件)。

编辑:我修改了这个,所以它可以使用非零填充值。 CSR没有本地非零填充值,因此您必须在外部记录它。

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

def sparse_BlockIndex_df_to_csr(df): 
    columns=df.columns 
    zipped_data = zip(*[(df[col].sp_values - df[col].fill_value, 
         df[col].sp_index.to_int_index().indices) 
         for col in columns]) 
    data, rows=map(list, zipped_data) 
    cols=[np.ones_like(a)*i for (i,a) in enumerate(data)] 
    data_f = np.concatenate(data) 
    rows_f = np.concatenate(rows) 
    cols_f = np.concatenate(cols) 
    arr = sparse.coo_matrix((data_f, (rows_f, cols_f)), 
          df.shape, dtype=np.float64) 
    return arr.tocsr() 
+0

如何使用'series.to_coo()'转换每列,并使用'sparse.bmat()'将它们加入到一个矩阵中? – hpaulj

+0

@hpaulj这听起来像一个明确的答案 - 你应该写出来! –

+0

进一步挖掘我发现Multiindex映射与我想到的简单列向量非常不同。它更像是“sklearn”人喜欢的特征矩阵。 – hpaulj

-1

EDIT:这种方法实际上是具有在某个阶段致密的显示,所以它并没有解决的问题。

您应该能够以下面的方式使用实验.to_coo()方法在大熊猫[1]:

df, idx_rows, idx_cols = df.stack().to_sparse().to_coo() 
df = df.tocsr() 

这种方法,而不是取DataFrame(行/列)它需要与行的SeriesMultiIndex中的列(这就是为什么您需要.stack()方法)。此SeriesMultiIndex需要为SparseSeries,即使您的输入为SparseDataFrame,.stack()也会返回常规Series。因此,在拨打.to_coo()之前,您需要使用.to_sparse()方法。

Series通过.stack()返回,即使它不是一个SparseSeries仅包含非空的元素,所以(当类型为np.float至少有np.nan)不应该采取更多的内存比稀疏的版本。

  1. http://pandas.pydata.org/pandas-docs/stable/sparse.html#interaction-with-scipy-sparse
+0

这种方法似乎很遗憾地使用了大量的内存。 – eleanora

+0

你是对的@eleanora,不知道我以前如何测试过它,但它看起来像内部这个方法有一个密集的数组内部表示,所以这个问题没有意义。对不起,错误的答案。 –

+0

现在看来这个工作。 'dataset = sparse.csr_matrix(df.to_coo())' – eleanora