首页 > 解决方案 > 如何提高使用来自迭代器的数据加载 ndarray 的效率?

问题描述

我有一个迭代器,其中包含 13,104,640 项三元组(i,j,value)i是行的索引,而表示j矩阵的列的索引。我还声明了一个所有项目都是一个的 2D ndarray。当我使用 for 循环加载带有迭代器中项目的 2D ndarray 时,时间消耗非常高。

如何提高使用该迭代器的项目加载 2D ndarray 的效率?

下面是我的 python3 代码的补丁:

nn = 5120
prxy_matrix = np.ones((nn, nn), dtype=float)
for i,j,p in iterator_A:
    prxy_matrix[i][j] = p
    prxy_matrix[j][i] = p

我可以使用一些矩阵操作,例如将数据作为一些块移动吗?

标签: pythonnumpy

解决方案


当您生成完整的上下三角形并可以控制元素的顺序时,最简单的方法是scipy.spatial.distance.squareform. squareform期望值逐行,与您从中获得的顺序相同itertools.combinations

从迭代器中获取数据的最快方法是np.fromiter

import numpy as np
from operator import itemgetter
from scipy.spatial.distance import squareform
import itertools as it

模拟数据源:

def source(n):
    for i,j in it.combinations(range(n),2):
        yield i,j,(i-j)/2

原始代码:

def OP():
    prxy_matrix = np.ones((nn, nn), dtype=float)
    for i,j,p in source(nn):
        prxy_matrix[i][j] = p
        prxy_matrix[j][i] = p
    return prxy_matrix

我的建议:

def pp():
    data = np.fromiter(map(itemgetter(2),source(nn)),float,(nn*(nn-1))//2)
    prxy_matrix = squareform(data)
    prxy_matrix.ravel()[::nn+1] = 1
    return prxy_matrix

这已经相当快了,但是我们在浪费时间创建和丢弃元组(坐标是多余的,所以我们甚至不读取它们)。由于您似乎可以控制生成器,因此请考虑仅生成数据:

def val_only(n):
    for i,j in it.combinations(range(n),2):
        yield (i-j)/2

def pp2():
    data = np.fromiter(val_only(nn),float,(nn*(nn-1))//2)
    prxy_matrix = squareform(data)
    prxy_matrix.ravel()[::nn+1] = 1
    return prxy_matrix

几个时间:

from timeit import timeit

nn = 1000
print(timeit(OP,number=10))
print(timeit(pp,number=10))
print(timeit(pp2,number=10))
# next three are to give a rough idea how much of the time is due to the iterator alone
print(timeit(lambda:all(source(nn)),number=10))
print(timeit(lambda:sum(val_only(nn)),number=10))
print(timeit(lambda:sum(it.chain.from_iterable(source(nn))),number=10))

产量:

3.4740988661069423
1.3367053079418838
0.7327171310316771
0.7123838479164988
0.5886694570071995
1.1725806428585202

推荐阅读