巨大的稀疏数据帧到 scipy 稀疏矩阵,无需密集变换

Posted

技术标签:

【中文标题】巨大的稀疏数据帧到 scipy 稀疏矩阵,无需密集变换【英文标题】:Huge sparse dataframe to scipy sparse matrix without dense transform 【发布时间】:2016-02-01 03:45:00 【问题描述】:

拥有超过 100 万行和 30 列的数据,其中一列是 user_id(超过 1500 个不同的用户)。 我想要对该专栏进行一次热编码并在 ML 算法(xgboost、FFM、scikit)中使用数据。但由于行数庞大且唯一用户值矩阵约为 100 万 X 1500,因此需要以稀疏格式执行此操作(否则数据会杀死所有 RAM)。

对我来说,通过 pandas DataFrame 处理数据很方便,现在它也支持稀疏格式:

df = pd.get_dummies(df, columns=['user_id', 'type'], sparse=True)

工作速度非常快,并且在 RAM 中的大小很小。但是为了使用 scikit 算法和 xgboost,有必要将数据帧转换为稀疏矩阵。

有没有办法做到这一点,而不是遍历列并将它们堆叠在一个 scipy 稀疏矩阵中? 我尝试了 df.as_matrix() 和 df.values,但首先将所有数据转换为密集的 MemoryError :(

附: 与为 xgboost 获取 DMatrix 相同

更新:

所以我发布下一个解决方案(将感谢优化建议):

 def sparse_df_to_saprse_matrix (sparse_df):
    index_list = sparse_df.index.values.tolist()
    matrix_columns = []
    sparse_matrix = None

    for column in sparse_df.columns:
        sps_series = sparse_df[column]
        sps_series.index = pd.MultiIndex.from_product([index_list, [column]])
        curr_sps_column, rows, cols = sps_series.to_coo()
        if sparse_matrix != None:
            sparse_matrix = sparse.hstack([sparse_matrix, curr_sps_column])
        else:
            sparse_matrix = curr_sps_column
        matrix_columns.extend(cols)

    return sparse_matrix, index_list, matrix_columns

以下代码允许获取稀疏数据帧:

one_hot_df = pd.get_dummies(df, columns=['user_id', 'type'], sparse=True)
full_sparse_df = one_hot_df.to_sparse(fill_value=0)

我创建了 110 万行 x 1150 列的稀疏矩阵。但在创建过程中,它仍然使用大量 RAM(我的 12Gb 在边缘约 10Gb)。

不知道为什么,因为生成的稀疏矩阵仅使用 300 Mb(从 HDD 加载后)。有什么想法吗?

【问题讨论】:

Pandas sparse dataFrame to sparse matrix, without generating a dense matrix in memory的可能重复 【参考方案1】:

我几个月前的回答有帮助吗?

Pandas sparse dataFrame to sparse matrix, without generating a dense matrix in memory

它被接受了,但我没有得到任何进一步的反馈。

我熟悉scipysparse 格式及其输入,但对pandas sparse 了解不多。

【讨论】:

会看,但我想它会像我描述的那样 - 遍历列并使用 to_coo 转换每个列,然后将 hstack 转换为结果稀疏矩阵。实验后将返回与帖子【参考方案2】:

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

one_hot_df = pd.get_dummies(df, columns=['user_id', 'type'], sparse=True)
one_hot_df, idx_rows, idx_cols = one_hot_df.stack().to_sparse().to_coo()

此方法不是采用DataFrame(行/列),而是采用SeriesMultiIndex 中的行和列(这就是您需要.stack() 方法的原因)。这个SeriesMultiIndex 必须是SparseSeries,即使你的输入是SparseDataFrame.stack() 也会返回一个常规的Series。所以,你需要在调用.to_coo()之前使用.to_sparse()方法。

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

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

【讨论】:

以上是关于巨大的稀疏数据帧到 scipy 稀疏矩阵,无需密集变换的主要内容,如果未能解决你的问题,请参考以下文章

如何计算 scipy 稀疏矩阵行列式而不将其变为密集?

Numpy/Scipy 稀疏与密集乘法

Numpy/scipy 加载巨大的稀疏矩阵以在 scikit-learn 中使用

优化 Scipy 稀疏矩阵

为啥 scipy 的稀疏 csr_matrix 的向量点积比 numpy 的密集数组慢?

scipy.sparse.linalg.spsolve Linux 系统上大型稀疏矩阵的令人惊讶的行为