[英]Fast way to access elements of a matrix or pandas dataframe from a list of coordinates
[英]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
函數。 在這里,我嘗試使用map
並reduce
以創建列表。
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.