我正在使用Python、numpy和scikit-learn。我有一组存储在SQL表中的键和值数据。我将其检索为返回的元组列表,格式为:[(id, value),...]
。每个id在列表中只出现一次,并且元组按id升序排列。我重复这个过程几次,因此我有多个key: value
对的列表。如下所示:
dataset = []for sample in samples: listOfTuplePairs = getDataFromSQL(sample) # 获取一个[(id, value),...]列表 dataset.append(listOfTuplePairs)
键在不同样本之间可能重复,每行可能长度不同。一个示例dataset
可能是这样的:
dataset = [[(1, 0.13), (2, 2.05)], [(2, 0.23), (4, 7.35), (5, 5.60)], [(2, 0.61), (3, 4.45)]]
可以看出,每行是一个样本,有些id(在本例中是2)在多个样本中出现。
问题:我想构建一个单一的(可能是稀疏的)numpy数组,适合用scikit-learn处理。每个样本中与特定键(id)相关的值应在同一“列”中对齐(如果这个术语正确的话),这样上面的示例矩阵将如下所示:
ids = 1 2 3 4 5 ------------------------------dataset = [(0.13, 2.05, null, null, null), (null, 0.23, null, 7.35, 5.60), (null, 0.61, 4.45, null, null)]
如您所见,我还希望从矩阵中去除id(尽管我需要保留一个id列表,以便我知道矩阵中的值对应什么)。每个初始的key: value
对列表可能包含数千行,并且可能有数千个样本,因此生成的矩阵可能非常大。请提供考虑速度(在Python的限制内)、内存效率和代码清晰度的答案。
非常感谢您提前提供的任何帮助。
回答:
这是一个基于NumPy的方法,用于创建一个以内存效率为重点的稀疏矩阵coo_matrix
–
from scipy.sparse import coo_matrix# 构建行IDslens = np.array([len(item) for item in dataset])shifts_arr = np.zeros(lens.sum(),dtype=int)shifts_arr[lens[:-1].cumsum()] = 1row = shifts_arr.cumsum()# 从dataset中提取值到NumPy数组arr = np.concatenate(dataset)# 获取用于列索引输出的唯一列IDcol = np.unique(arr[:,0],return_inverse=True)[1]# 确定输出形状out_shp = (row.max()+1,col.max()+1)# 最后使用行、列索引和arr的col-2创建一个稀疏矩阵sp_out = coo_matrix((arr[:,1],(row,col)), shape=out_shp)
请注意,如果IDs
应该是输出数组中的列号,您可以用类似这样的东西替换使用np.unique
来获取这些唯一ID –
col = (arr[:,0]-1).astype(int)
这应该能给我们带来很好的性能提升!
示例运行 –
In [264]: dataset = [[(1, 0.13), (2, 2.05)], ...: [(2, 0.23), (4, 7.35), (5, 5.60)], ...: [(2, 0.61), (3, 4.45)]]In [265]: sp_out.todense() # 使用.todense()显示输出Out[265]: matrix([[ 0.13, 2.05, 0. , 0. , 0. ], [ 0. , 0.23, 0. , 7.35, 5.6 ], [ 0. , 0.61, 4.45, 0. , 0. ]])