簡體   English   中英

將大量索引(從Pandas數據幀)加載到稀疏矩陣的快速方法?

[英]Fast way to load a lot of indexes (from a Pandas dataframe) into a sparse matrix?

我有一個帶有1.500.000行的大型Pandas數據框,其中一列包含帶有數字的列表。 你可以這樣想

df = pd.DataFrame({'lists' : [[0, 1, 2], [6, 7, 8], [3, 4, 5]]})

但更大。 最后我想要一個矩陣,看起來像這樣

[1, 1, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 1, 1, 1]
[0, 0, 0, 1, 1, 1, 0, 0, 0]

因此df的行索引是矩陣的行索引,列表中的數字是需要設置為True的列索引。

矩陣的形狀為1.500.000 x 30.000,但這會占用太多RAM,因此我使用lil_matrix()保存了矩陣,然后稍后可以成批地形成矩陣批次。

我現在這樣做的方式如下:

sparse_matrix = sparse.lil_matrix((1.500.000, 30.000), dtype=bool)
list_with_lists = df["lists"].tolist()
for i, list in enumerate(list_with_lists):
    for number in list:
        sparse_matrix[i, number] = True

它可以工作,但是要花幾分鍾,我真的希望有一個更快的方法,因為這會花費很多時間。 有誰知道更快的方法?

不確定scipy.sparse.lil_matrix如何工作,但請嘗試使用高級索引:

rows = np.arange(m.shape[0])[:, np.newaxis]
cols = df['lists'].tolist()
m[rows, cols] = 1

基本上,我們是說將此處找到的每個[row, column]對都設置為True 對於N * M矩陣, row看起來像[[1], [2], [3], ..., N] ,而cols是您的級數。

帶有測試用例

import pandas as pd
import numpy as np

df = pd.DataFrame({'lists' : [[0, 1, 2], [6, 7, 8], [3, 4, 5]]})

m = np.zeros((3, 9), dtype=bool)

rows = np.arange(m.shape[0])[:, np.newaxis]
cols = df['lists'].tolist()
m[rows, cols] = True

print(m.view(np.int8))

我懂了

[[1 1 1 0 0 0 0 0 0]
 [0 0 0 0 0 0 1 1 1]
 [0 0 0 1 1 1 0 0 0]]

您可以嘗試使用具有update功能的dok_matrix 您將需要准備一個表單列表((row_idx,col_idx),val)並將其傳遞給update函數。 在這里,我嘗試使用mapreduce以創建列表。

from itertools import chain
from scipy import sparse

df = pd.DataFrame({'lists' : [[0, 1, 2], [6, 7, 8], [3, 4, 5]]})
sparse_matrix = sparse.dok_matrix((1500000, 30000), dtype=bool)
list_with_lists = df["lists"].tolist()


update_list = chain.from_iterable(map(lambda l, r: [((r, i), 1) for i in l], 
                                      list_with_lists, 
                                      range(len(list_with_lists))))    

# update_list 
[((0, 0), 1),
 ((0, 1), 1),
 ((0, 2), 1),
 ((1, 6), 1),
 ((1, 7), 1),
 ((1, 8), 1),
 ((2, 3), 1),
 ((2, 4), 1),
 ((2, 5), 1)]

sparse_matrix.update(update_list)

定時

設定

from numpy.random import randint
df = pd.DataFrame({'lists' : [randint(0, 30000, 10) for i in range(10000)]})
list_with_lists = df["lists"].tolist()

在雙循環更新中使用lil_matrix

sparse_matrix = sparse.lil_matrix((1500000, 30000), dtype=bool)
%%timeit  # OP's original way of adding using lil_matrix
for i, list in enumerate(list_with_lists):
    for number in list:
        sparse_matrix[i, number] = True
635 ms ± 26.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

update使用dok_matrix

sparse_matrix = sparse.dok_matrix((1500000, 30000), dtype=bool)
%%timeit # updating using `update` function in dok_matrix
update_list = chain.from_iterable(map(lambda l, r: [((r, i), 1) for i in l], 
                              list_with_lists, 
                              range(len(list_with_lists))))    
sparse_matrix.update(update_list)
48.7 ms ± 6.84 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

但是, dok_matrix在其他矩陣運算中可能會變慢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM