使用分类数据构造稀疏矩阵

construct sparse matrix using categorical data

我有一个看起来像这样的数据:

numpy 数组:

[[a, abc],
[b, def],
[c, ghi],
[d, abc],
[a, ghi],
[e, fg],
[f, f76],
[b, f76]]

它就像一个用户-项目矩阵。 我想构建一个形状为 number_of_items、num_of_users 的稀疏矩阵,如果用户有 rated/bought 一个项目则为 1,如果没有则为 0。所以,对于上面的例子,shape 应该是 (5,6)。这只是一个例子,有成千上万的用户和成千上万的项目。

目前我正在使用两个 for 循环执行此操作。有什么 faster/pythonic 方法可以达到同样的目的吗?

期望的输出:

1,0,0,1,0,0
0,1,0,0,0,0
1,0,1,0,0,0
0,0,0,0,1,0
0,1,0,0,0,1

其中行数:abc,def,ghi,fg,f76 和列:a,b,c,d,e,f

这是我能想到的:

您需要小心,因为 np.unique 会在 return 对项目进行排序之前对它们进行排序,因此输出格式与您在问题中提供的格式略有不同。

此外,您需要将数组转换为元组列表,因为 ('a', 'abc') in [('a', 'abc'), ('b', 'def')] 会 return True,但 ['a', 'abc'] in [['a', 'abc'], ['b', 'def']] 不会。

A = np.array([
['a', 'abc'],
['b', 'def'],
['c', 'ghi'],
['d', 'abc'],
['a', 'ghi'],
['e', 'fg'],
['f', 'f76'],
['b', 'f76']])

customers = np.unique(A[:,0])
items = np.unique(A[:,1])
A = [tuple(a) for a in A]
combinations = it.product(customers, items)
C = np.array([b in A for b in combinations], dtype=int)
C.reshape((values.size, customers.size))
>> array(
  [[1, 0, 0, 0, 1, 0],
   [1, 1, 0, 0, 0, 0],
   [0, 0, 1, 1, 0, 0],
   [0, 0, 0, 0, 0, 1],
   [0, 0, 0, 1, 0, 0]])

这是我使用 pandas 的方法,如果效果更好请告诉我:

#create dataframe from your numpy array
x = pd.DataFrame(x, columns=['User', 'Item'])

#get rows and cols for your sparse dataframe    
cols = pd.unique(x['User']); ncols = cols.shape[0]
rows = pd.unique(x['Item']); nrows = rows.shape[0]

#initialize your sparse dataframe, 
#(this is not sparse, but you can check pandas support for sparse datatypes    
spdf = pd.DataFrame(np.zeros((nrow, ncol)), columns=cols, index=rows)    

#define apply function    
def hasUser(xx):
    spdf.ix[xx.name,  xx] = 1

#groupby and apply to create desired output dataframe    
g = x.groupby(by='Item', sort=False)
g['User'].apply(lambda xx: hasUser(xx))

这是上述代码的样本数据帧:

    spdf
    Out[71]: 
         a  b  c  d  e  f
    abc  1  0  0  1  0  0
    def  0  1  0  0  0  0
    ghi  1  0  1  0  0  0
    fg   0  0  0  0  1  0
    f76  0  1  0  0  0  1

    x
    Out[72]: 
      User Item
    0    a  abc
    1    b  def
    2    c  ghi
    3    d  abc
    4    a  ghi
    5    e   fg
    6    f  f76
    7    b  f76

Also, in case you want to make groupby apply function execution parallel , this question might be of help: Parallelize apply after pandas groupby

最简单的方法是将整数标签分配给用户和项目,并将它们作为坐标放入稀疏矩阵中,例如:

import numpy as np
from scipy import sparse

users, I = np.unique(user_item[:,0], return_inverse=True)
items, J = np.unique(user_item[:,1], return_inverse=True)

points = np.ones(len(user_item), int)
mat = sparse.coo_matrix(points, (I, J))

pandas.get_dummies 提供了将分类列转换为稀疏矩阵的更简单方法

import pandas as pd
#construct the data
x = pd.DataFrame([['a', 'abc'],['b', 'def'],['c' 'ghi'],
                 ['d', 'abc'],['a', 'ghi'],['e', 'fg'],
                 ['f', 'f76'],['b', 'f76']], 
                 columns = ['user','item'])
print(x)
#    user  item
# 0     a   abc
# 1     b   def
# 2     c   ghi
# 3     d   abc
# 4     a   ghi
# 5     e    fg
# 6     f   f76
# 7     b   f76
for col, col_data in x.iteritems():
    if str(col)=='item':
        col_data = pd.get_dummies(col_data, prefix = col)
        x = x.join(col_data)
print(x)
#    user  item  item_abc  item_def  item_f76  item_fg  item_ghi
# 0     a   abc         1         0         0        0         0
# 1     b   def         0         1         0        0         0
# 2     c   ghi         0         0         0        0         0
# 3     d   abc         1         0         0        0         0
# 4     a   ghi         0         0         0        0         1
# 5     e    fg         0         0         0        1         0
# 6     f   f76         0         0         1        0         0
# 7     b   f76         0         0         1        0         0