如何将Pandas组转换为SparseDataFrame

时间:2014-01-07 16:25:02

标签: python pandas

我有一个高(2743470行,2个cols)DataFrame,称之为df,带有以下列,整数索引:

| item | user |
| 1    | abc  |
| 15   | abc  |
| 3    | def  |

我知道总共有35605个可能的商品ID和53690个用户。我想要做的是将其转换为SparseDataFrame,每行代表一个用户,一列代表一个项目,当用户与原始表格中的项目相关联时,该值为1。

我已经尝试过一个小组,但在那一点上我无法弄清楚如何对其余的进行矢量化。我得到的最好的是以下内容:

ids = pandas.Index(df.item.drop_duplicates())
g = df.groupby('user')
arr = []
arr_i = []
for name, group in g:
    arr_i.append(name)
    s = pandas.Series({val: 1 for val in group.item}, index=ids).to_sparse()
    arr.append(s)
book_reads = pandas.SparseDataFrame(arr, index=arr_i)

但即使这样也失败了:

TypeError: ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''

我尝试将索引参数取出到SparseDataFrame,或者将其设置为一组整数而不是字符串,但无济于事。唯一有效的方法是首先制作一个常规的DataFrame,然后在其上调用to_sparse,但这会占用太多的内存。

有没有办法在仅使用稀疏数据结构的情况下对此操作进行矢量化?

更新

我还尝试伪造所有1的值列并进行旋转,但几乎立即得到内存错误,可能是因为pivot产生了一个密集的DataFrame。

3 个答案:

答案 0 :(得分:2)

我认为你不会有这个内存问题,因为最终的结果不会那么大(所以不会破坏堆栈)

In [14]: df.groupby('user')['item'].apply(lambda x: Series(1,index=x)).unstack()
Out[14]: 
      1   3   15
user            
abc    1 NaN   1
def  NaN   1 NaN

[2 rows x 3 columns]

答案 1 :(得分:1)

在将它们传递给SDF之前你不需要稀释系列,它会为你做(不确定你会避免内存错误):

>>> series = [pandas.Series({val: 1 for val in group.item}, index=ids) 
...              for name, group in g]
>>> idx = [name for name, _ in g]
>>> pandas.SparseDataFrame(series, index=idx, columns=ids)
     1   15  3
abc   1   1 NaN
def NaN NaN   1

答案 2 :(得分:0)

对于它的价值,这个简单的迭代代码在我的Mac上花费了大约30秒来构建我正在寻找的稀疏矩阵。这不是我的“我怎么用熊猫做的?”的答案。问题,但无论如何它可能是有用的。

mat = scipy.sparse.lil_matrix((len(users),max(ids)+1))
for i, (name, group) in enumerate(g):
    mat[i, group.item] = 1