Pandas稀疏dataFrame到稀疏矩阵,而不在内存中生成密集矩阵

时间:2015-06-27 03:48:01

标签: python pandas scipy sparse-matrix

有没有办法从pandas.SparseDataFrame转换为scipy.sparse.csr_matrix,而不会在内存中生成密集矩阵?

scipy.sparse.csr_matrix(df.values)

无法正常工作,因为它会生成一个密集的矩阵,该矩阵会投射到csr_matrix

提前致谢!

6 个答案:

答案 0 :(得分:14)

Pandas 0.20.0 +:

截至2017年5月5日发布的pandas版本0.20.0,有一个单行:

from scipy import sparse


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

这使用新的to_coo() method

早期版本:

在Victor May的回答的基础上,这里的实施速度略快一些,但只有在整个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()

答案 1 :(得分:3)

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

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()

答案 2 :(得分:1)

自0.25版开始,SparseSeriesSparseDataFrame版本已弃用。现在,DataFrames支持Sparse Dtypes用于稀疏数据列。稀疏方法可通过sparse访问器使用,因此一线转换现在看起来像这样:

sparse_matrix = scipy.sparse.csr_matrix(df.sparse.to_coo())

答案 3 :(得分:0)

Pandas docs谈到实验性转换为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数据集需要多索引是有意义的。虽然数据帧可以表示表或2d数组。

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

答案 4 :(得分: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()

答案 5 :(得分:0)

编辑:此方法实际上在某个阶段具有密集表示,因此无法解决问题。

您应该能够以下列方式在pandas [1]中使用实验.to_coo()方法:

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

此方法不是采用DataFrame(行/列),而是在Series中使用MultiIndex行和列(这就是为什么需要.stack() } 方法)。这个Series MultiIndex需要SparseSeries,即使您的输入为SparseDataFrame.stack()也会返回常规Series。因此,您需要在调用.to_sparse()之前使用.to_coo()方法。

Series返回的.stack(),即使它不是SparseSeries,也只包含非空元素,因此它不应占用比稀疏版本更多的内存(在当类型为np.nan时,至少使用np.float

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