【问题标题】:Pandas sparse dataFrame to sparse matrix, without generating a dense matrix in memoryPandas 将稀疏数据帧转为稀疏矩阵,无需在内存中生成密集矩阵
【发布时间】:2015-09-14 02:26:52
【问题描述】:

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

scipy.sparse.csr_matrix(df.values)

不起作用,因为它会生成一个密集矩阵,该矩阵被转换为csr_matrix

提前致谢!

【问题讨论】:

标签: python pandas scipy sparse-matrix


【解决方案1】:

从 Pandas 0.25 版开始,SparseSeriesSparseDataFrame 已弃用。 DataFrames 现在支持 Sparse Dtypes 用于具有稀疏数据的列。稀疏方法可通过sparse 访问器获得,因此转换单行现在看起来像这样:

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

【讨论】:

  • 一个后续问题是:如何高效地将具有大量值的分类列转换为Sparse Dtypespd.get_dummies(df, sparse = True) 需要很多时间。
【解决方案2】:

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

【讨论】:

  • 如何使用series.to_coo() 转换每一列,并使用sparse.bmat() 将它们连接成一个矩阵?
  • @hpaulj 这听起来像是一个独特的答案——你应该把它写下来!
  • 进一步挖掘我发现多索引映射与我想到的简单列向量非常不同。更像是sklearn人们喜欢的特征矩阵。
  • 现在看来可行。数据集 = sparse.csr_matrix(df.to_coo())
【解决方案3】:

Pandas 文档讨论了向 scipy sparse、SparseSeries.to_coo 的实验性转换:

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

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

edit - 这是来自多索引的特殊功能,而不是数据框。请参阅其他答案。请注意日期的差异。

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

从 0.20.0 开始,有一个 sdf.to_coo() 和一个多索引 ss.to_coo()。由于稀疏矩阵本质上是二维的,因此对(有效的)一维数据序列需要多索引是有意义的。虽然数据框可以表示表格或二维数组。

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

【讨论】:

  • 这仅适用于MultiIndex-ed SparseSeries,不适用于DataFrame。
  • 正如@eleanora 提到的,this does actually work now(截至 2017 年 5 月 5 日发布的版本 0.20.0)。 sparse.csr_matrix(df.to_coo()) 是一个可以解决问题的单行代码。也许你应该编辑你的答案以明确这一点?
  • 也许我们应该关闭已过时的主题?
  • 因为答案已经过时而关闭一个完全有效的问题是否很常见?我不认为这是一件事,而且总的来说这似乎是个坏主意。
  • 这将使我免于投票,因为我的答案不再有效。并不是说它真的很重要。 :)
【解决方案4】:

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

您应该可以通过以下方式在 pandas [1] 中使用实验性的.to_coo() 方法:

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()方法。

.stack()返回的Series,即使不是SparseSeries也只包含不为null的元素,所以它不应该比稀疏版本占用更多的内存(至少在np.nan的时候类型是np.float)。

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

【讨论】:

  • 这个方法似乎很可悲地使用了大量的内存。
  • 你是对的@eleanora,不知道我之前是如何测试它的,但看起来这个方法在内部有一个密集的数组内部表示,所以这个问题毫无意义。抱歉回答错误。
  • 现在看来可行。 dataset = sparse.csr_matrix(df.to_coo())
【解决方案5】:

@Marigold 的答案可以解决问题,但由于访问每列中的所有元素(包括零),它很慢。在此基础上,我编写了以下快速 n' 脏代码,它在 1000x1000 矩阵上以大约 1% 的密度运行大约快 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】:

    这是一个逐列填充稀疏矩阵的解决方案(假设您可以将至少一列放入内存)。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-19
      • 2023-04-10
      • 2021-11-25
      • 2017-07-02
      • 2016-02-01
      • 2016-08-03
      • 1970-01-01
      • 2016-09-19
      相关资源
      最近更新 更多