如何从pandas数据帧创建scipy稀疏矩阵?

时间:2016-05-07 02:57:19

标签: python numpy pandas matrix scipy

我正在寻找一种更好的方法来从scipy sparse matrix创建pandas dataframe

这是我目前拥有的伪代码

row = []; column = []; values = []
for each row of the dataframe
    for each column of the row
        add the row_id to row
        add the column_id to column
        add the value to values
sparse_matrix = sparse.coo_matrix((values, (row, column), shape=(max(row)+1,max(column)+1))

但我个人认为会有更好的办法。几乎起作用的是以下

dataframe.unstack().to_sparse().to_coo()

然而,这给了我三倍的(稀疏矩阵,列id和行id)。问题是我需要行id实际上是稀疏矩阵的一部分。

这是一个完整的例子。我有一个如下所示的数据框

          instructor_id  primary_department_id
id
4109           2093                    129
6633           2093                    129
6634           2094                    129
6635           2095                    129

如果我进行上面提到的操作,我会

ipdb> data = dataframe.unstack().to_sparse().to_coo()[0]
ipdb> data
<2x4 sparse matrix of type '<type 'numpy.int64'>'
    with 8 stored elements in COOrdinate format>
ipdb> print data
  (0, 0)    2093
  (0, 1)    2093
  (0, 2)    2094
  (0, 3)    2095
  (1, 0)    129
  (1, 1)    129
  (1, 2)    129
  (1, 3)    129

但我需要

ipdb> print data
  (4109, 0) 2093
  (6633, 0) 2093
  (6634, 0) 2094
  etc.

我愿意使用任何其他库或依赖项。

似乎有一个question that asks for the reverse operation,但我还没有找到解决方案。

2 个答案:

答案 0 :(得分:2)

我没有安装pandas,因此无法从数据框开始。但是我们假设我从dataframe中提取了一个numpy数组(不是像values这样的方法或属性吗?):

In [40]: D
Out[40]: 
array([[4109, 2093],    # could be other columns
       [6633, 2093],
       [6634, 2094],
       [6635, 2095]])

从中制作稀疏矩阵是直截了当的 - 我只需要提取或构造3个数组:

In [41]: M=sparse.coo_matrix((D[:,1], (D[:,0], np.zeros(D.shape[0]))),
   shape=(7000,1))

In [42]: M
Out[42]: 
<7000x1 sparse matrix of type '<class 'numpy.int32'>'
    with 4 stored elements in COOrdinate format>

In [43]: print(M)
  (4109, 0) 2093
  (6633, 0) 2093
  (6634, 0) 2094
  (6635, 0) 2095

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

推广到两个'数据'列

In [70]: D
Out[70]: 
array([[4109, 2093,  128],
       [6633, 2093,  129],
       [6634, 2094,  127],
       [6635, 2095,  126]])

In [76]: i,j,data=[],[],[]

In [77]: for col in range(1,D.shape[1]):
    i.extend(D[:,0])
    j.extend(np.zeros(D.shape[0],int)+(col-1))
    data.extend(D[:,col])
   ....:     

In [78]: i
Out[78]: [4109, 6633, 6634, 6635, 4109, 6633, 6634, 6635]

In [79]: j
Out[79]: [0, 0, 0, 0, 1, 1, 1, 1]

In [80]: data
Out[80]: [2093, 2093, 2094, 2095, 128, 129, 127, 126]

In [83]: M=sparse.coo_matrix((data,(i,j)),shape=(7000,D.shape[1]-1))

In [84]: M
Out[84]: 
<7000x2 sparse matrix of type '<class 'numpy.int32'>'
    with 8 stored elements in COOrdinate format>

In [85]: print(M)
  (4109, 0) 2093
  (6633, 0) 2093
  (6634, 0) 2094
  (6635, 0) 2095
  (4109, 1) 128
  (6633, 1) 129
  (6634, 1) 127
  (6635, 1) 126

我怀疑你也可以为每一列制作单独的矩阵,并将它们与sparse.bmat(块)机制结合起来,但我最熟悉coo格式。

请参阅 Compiling n submatrices into an NxN matrix in numpy

从子矩阵构建大型稀疏矩阵的另一个例子(这里它们重叠)。在那里,我找到了一种通过更快的阵列操作来连接块的方法。这可能是这样做的。但我怀疑在几列(以及extend多行)上的迭代是快速的。

使用bmat我可以构建相同的东西:

In [98]: I, J = D[:,0], np.zeros(D.shape[0],int)

In [99]: M1=sparse.coo_matrix((D[:,1],(I, J)), shape=(7000,1))
In [100]: M2=sparse.coo_matrix((D[:,2],(I, J)), shape=(7000,1))

In [101]: print(sparse.bmat([[M1,M2]]))
  (4109, 0) 2093
  (6633, 0) 2093
  (6634, 0) 2094
  (6635, 0) 2095
  (4109, 1) 128
  (6633, 1) 129
  (6634, 1) 127
  (6635, 1) 126

答案 1 :(得分:1)

一个简单的解决方案是:

import numpy as np
import pandas as pd
df = pd.DataFrame(data = [[2093, 129], [2093, 129], [2094, 129], [2095, 129]], index = [4109, 6633, 6634, 6635], columns = ['instructor_id', 'primary_department_id'])

from scipy.sparse import lil_matrix
sparse_matrix = lil_matrix((df.index.max()+1, len(df.columns)))
for k, column_name in enumerate(df.columns):
    sparse_matrix[df.index.values, np.full(len(df), k)] = df[column_name].values

如果您想使用压缩格式,可以直接转换它:

sparse_matrix = sparse_matrix.tocsc()