在pandas中有效地创建稀疏数据透视表?

nee*_*hiv 24 python scipy sparse-matrix pandas scikit-learn

我正在将具有两列(A和B)的记录列表转换为矩阵表示.我一直在使用pandas中的pivot函数,但结果却相当大.pandas是否支持转换为稀疏格式?我知道我可以转动它然后把它变成某种稀疏表示,但不像我想的那样优雅.我的最终目标是将其用作预测模型的输入.

或者,在熊猫之​​外是否存在某种稀疏枢轴能力?

编辑:这是一个非稀疏数据透视的示例

import pandas as pd
frame=pd.DataFrame()
frame['person']=['me','you','him','you','him','me']
frame['thing']=['a','a','b','c','d','d']
frame['count']=[1,1,1,1,1,1]

frame

  person thing  count
0     me     a      1
1    you     a      1
2    him     b      1
3    you     c      1
4    him     d      1
5     me     d      1

frame.pivot('person','thing')

        count            
thing       a   b   c   d
person                   
him       NaN   1 NaN   1
me          1 NaN NaN   1
you         1 NaN   1 NaN
Run Code Online (Sandbox Code Playgroud)

这创建了一个矩阵,可以包含所有可能的人和事物的组合,但它并不稀疏.

http://docs.scipy.org/doc/scipy/reference/sparse.html

稀疏矩阵占用的空间较少,因为它们可能意味着NaN或0之类的东西.如果我有一个非常大的数据集,这个旋转函数可以生成一个由于大量NaN或0而应该稀疏的矩阵.我希望通过生成一些稀疏的东西而不是创建一个密集矩阵然后将其转换为稀疏来节省大量空间/内存.

kha*_*mel 33

这是一种基于人和事物的数据和索引创建稀疏scipy矩阵的方法. person_u并且thing_u是表示要创建的数据透视表的行和列的唯一条目的列表.注意:这假设您的计数列已经包含您想要的值.

from scipy.sparse import csr_matrix

person_u = list(sort(frame.person.unique()))
thing_u = list(sort(frame.thing.unique()))

data = frame['count'].tolist()
row = frame.person.astype('category', categories=person_u).cat.codes
col = frame.thing.astype('category', categories=thing_u).cat.codes
sparse_matrix = csr_matrix((data, (row, col)), shape=(len(person_u), len(thing_u)))

>>> sparse_matrix 
<3x4 sparse matrix of type '<type 'numpy.int64'>'
    with 6 stored elements in Compressed Sparse Row format>

>>> sparse_matrix.todense()

matrix([[0, 1, 0, 1],
        [1, 0, 0, 1],
        [1, 0, 1, 0]])
Run Code Online (Sandbox Code Playgroud)

根据您的原始问题,scipy稀疏矩阵应该足以满足您的需求,但如果您希望拥有稀疏数据帧,则可以执行以下操作:

dfs=pd.SparseDataFrame([ pd.SparseSeries(sparse_matrix[i].toarray().ravel(), fill_value=0) 
                              for i in np.arange(sparse_matrix.shape[0]) ], index=person_u, columns=thing_u, default_fill_value=0)

>>> dfs
     a  b  c  d
him  0  1  0  1
me   1  0  0  1
you  1  0  1  0

>>> type(dfs)
pandas.sparse.frame.SparseDataFrame
Run Code Online (Sandbox Code Playgroud)


Aln*_*lam 8

@khammel先前发布的答案很有用,但不幸的是由于熊猫和Python的更改而不再起作用。以下应该产生相同的输出:

from scipy.sparse import csr_matrix
from pandas.api.types import CategoricalDtype

person_c = CategoricalDtype(sorted(frame.person.unique()), ordered=True)
thing_c = CategoricalDtype(sorted(frame.thing.unique()), ordered=True)

row = frame.person.astype(person_c).cat.codes
col = frame.thing.astype(thing_c).cat.codes
sparse_matrix = csr_matrix((frame["count"], (row, col)), \
                           shape=(person_c.categories.size, thing_c.categories.size))

>>> sparse_matrix
<3x4 sparse matrix of type '<class 'numpy.int64'>'
     with 6 stored elements in Compressed Sparse Row format>

>>> sparse_matrix.todense()
matrix([[0, 1, 0, 1],
        [1, 0, 0, 1],
        [1, 0, 1, 0]], dtype=int64)


dfs = pd.SparseDataFrame(sparse_matrix, \
                         index=person_c.categories, \
                         columns=thing_c.categories, \
                         default_fill_value=0)
>>> dfs
        a   b   c   d
 him    0   1   0   1
  me    1   0   0   1
 you    1   0   1   0
Run Code Online (Sandbox Code Playgroud)

主要变化是:

  • .astype()不再接受“类别”。您必须创建一个CategoricalDtype对象。
  • sort() 不再工作了

其他更改更肤浅:

  • 使用类别大小而不是唯一的Series对象的长度,只是因为我不想不必要地制作另一个对象
  • csr_matrixframe["count"])的数据输入不必是列表对象
  • 熊猫SparseDataFrame现在直接接受scipy.sparse对象

  • 从 Pandas 1.0.1 开始,您需要将 pd.SparseDataFrame() 替换为 pd.DataFrame.sparse.from_spmatrix()。请参阅:https://pandas.pydata.org/pandas-docs/stable/user_guide/sparse.html#migrating (4认同)