2016-05-07 62 views
1

我在寻找一个更好的方式来创建一个从pandas dataframe一个scipy sparse matrix如何从熊猫数据框创建一个scipy稀疏矩阵?

这里是我目前有

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,但我还没有找到此操作的解决方案。

+1

“问题是我需要行ID实际上是稀疏矩阵的一部分” - 你能否明白你的意思是什么? –

+0

完整的工作示例程序可以帮助用硬编码的输入数据。我不确定为什么你想把一个完整的,密集的DataFrame变成一个稀疏矩阵 - 你确定要这么做吗?为什么? –

+0

你看过稀疏的熊猫版吗?最近有几个关于在scipy和sparse之间来回切换的问题。 http://pandas.pydata.org/pandas-docs/stable/sparse.html – hpaulj

回答

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 
+0

因此,对于更多的列,你会建议组合稀疏矩阵吗?或者我应该尝试像'M = sparse.coo_matrix((append(D [:,1],D [:2])(append(D [:,0],D [:,0]),append(np .zeros(D.shape [0])),np.ones(D.shape [0]))), shape =(7000,2))'? – kshikama

+0

我的意思是我需要它的任意数量的列,所以不会最终需要一个for循环,就像我在我原来的帖子中提出的那样? – kshikama

+0

我对2个数据列的概括是否有帮助? – hpaulj

0

一个简单的解决办法是:

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