Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 枚举两个大数组的快速方法?_Python_Performance_Numpy_Enumerate - Fatal编程技术网

Python 枚举两个大数组的快速方法?

Python 枚举两个大数组的快速方法?,python,performance,numpy,enumerate,Python,Performance,Numpy,Enumerate,我有两个大数组要处理。但是让我们看看下面的简化例子来得到这样的想法: 我想查找data1中的元素是否与data2中的元素匹配,如果以新数组的形式找到匹配项[data1的索引,data2的索引],则返回data1和data2中的数组索引。例如,使用下面的一组数据1和数据2,程序将返回: data1 = [[1,1],[2,5],[623,781]] data2 = [[1,1], [161,74],[357,17],[1,1]] expected_output = [[0,0],[0,3]]

我有两个大数组要处理。但是让我们看看下面的简化例子来得到这样的想法:

我想查找data1中的元素是否与data2中的元素匹配,如果以新数组的形式找到匹配项[data1的索引,data2的索引],则返回data1和data2中的数组索引。例如,使用下面的一组数据1和数据2,程序将返回:

data1 = [[1,1],[2,5],[623,781]] 
data2 = [[1,1], [161,74],[357,17],[1,1]]
expected_output = [[0,0],[0,3]]
我目前的代码如下:

result = []
for index, item in enumerate(data1):
    for index2,item2 in enumerate(data2):
        if np.array_equal(item,item2):
            result.append([index,index2])
>>> result
[[0, 0], [0, 3]]

这个很好用。但是,我正在处理的实际两个阵列每个都有60万项。上面的代码将非常慢。有什么方法可以加快进程吗?

可能不是最快的,但简单且相当快:使用KDTrees:

>>> data1 = [[1,1],[2,5],[623,781]] 
>>> data2 = [[1,1], [161,74],[357,17],[1,1]]
>>>
>>> from operator import itemgetter
>>> from scipy.spatial import cKDTree as KDTree
>>>
>>> def intersect(a, b):
...     A = KDTree(a); B = KDTree(b); X = A.query_ball_tree(B, 0.5)
...     ai, bi = zip(*filter(itemgetter(1), enumerate(X)))
...     ai = np.repeat(ai, np.fromiter(map(len, bi), int, len(ai)))
...     bi = np.concatenate(bi)
...     return ai, bi
... 
>>> intersect(data1, data2)
(array([0, 0]), array([0, 3]))
两个伪数据集1000000对,每个需要3秒:


可能不是最快的,但简单且相当快:使用KDTrees:

>>> data1 = [[1,1],[2,5],[623,781]] 
>>> data2 = [[1,1], [161,74],[357,17],[1,1]]
>>>
>>> from operator import itemgetter
>>> from scipy.spatial import cKDTree as KDTree
>>>
>>> def intersect(a, b):
...     A = KDTree(a); B = KDTree(b); X = A.query_ball_tree(B, 0.5)
...     ai, bi = zip(*filter(itemgetter(1), enumerate(X)))
...     ai = np.repeat(ai, np.fromiter(map(len, bi), int, len(ai)))
...     bi = np.concatenate(bi)
...     return ai, bi
... 
>>> intersect(data1, data2)
(array([0, 0]), array([0, 3]))
两个伪数据集1000000对,每个需要3秒:

请注意,其他答案,使用字典检查精确匹配或使用KDTree检查epsilonclose匹配,都比这好得多,速度更快,内存效率更高

使用。如果两个数据数组各有N个和M个条目,则它将构成一个N×M的成对距离数组。如果可以将其放入RAM中,则很容易找到匹配的索引:

import numpy as np
from scipy.spatial.distance import cdist

# Generate some data that's very likely to have repeats    
a = np.random.randint(0, 100, (1000, 2))
b = np.random.randint(0, 100, (1000, 2))

# `cityblock` is likely the cheapest distance to calculate (no sqrt, etc.)
c = cdist(a, b, 'cityblock')

# And the indexes of all the matches:
aidx, bidx = np.nonzero(c == 0)

# sanity check:
print([(a[i], b[j]) for i,j in zip(aidx, bidx)])
上面打印出:

[(array([ 0, 84]), array([ 0, 84])),
 (array([50, 73]), array([50, 73])),
 (array([53, 86]), array([53, 86])),
 (array([96, 85]), array([96, 85])),
 (array([95, 18]), array([95, 18])),
 (array([ 4, 59]), array([ 4, 59])), ... ]
请注意,其他答案,使用字典检查精确匹配或使用KDTree检查epsilonclose匹配,都比这好得多,速度更快,内存效率更高

使用。如果两个数据数组各有N个和M个条目,则它将构成一个N×M的成对距离数组。如果可以将其放入RAM中,则很容易找到匹配的索引:

import numpy as np
from scipy.spatial.distance import cdist

# Generate some data that's very likely to have repeats    
a = np.random.randint(0, 100, (1000, 2))
b = np.random.randint(0, 100, (1000, 2))

# `cityblock` is likely the cheapest distance to calculate (no sqrt, etc.)
c = cdist(a, b, 'cityblock')

# And the indexes of all the matches:
aidx, bidx = np.nonzero(c == 0)

# sanity check:
print([(a[i], b[j]) for i,j in zip(aidx, bidx)])
上面打印出:

[(array([ 0, 84]), array([ 0, 84])),
 (array([50, 73]), array([50, 73])),
 (array([53, 86]), array([53, 86])),
 (array([96, 85]), array([96, 85])),
 (array([95, 18]), array([95, 18])),
 (array([ 4, 59]), array([ 4, 59])), ... ]

因为您的数据都是整数,所以可以使用字典哈希表,时间为0.55秒,与Paul的答案中的数据相同。这不一定会找到a和b之间配对的所有副本,也就是说,如果a和b本身包含重复项,那么可以很容易地对此进行修改,或者只在匹配项上进行第二次传递,以检查这些向量在数据中的其他出现情况

import numpy as np

def intersect1(a, b):
    a_d = {}
    for i, x in enumerate(a):
        a_d[x] = i
    for i, y in enumerate(b):
        if y in a_d:
            yield a_d[y], i

from time import perf_counter
a = list(tuple(x) for x in list(np.random.randint(0, 100000, (1000000, 2))))
b = list(tuple(x) for x in list(np.random.randint(0, 100000, (1000000, 2))))
t = perf_counter(); print(list(intersect1(a, b))); s = perf_counter()
print(s-t)

比较而言,Paul的答案在我的机器上需要2.46秒。

因为您的数据都是整数,所以可以使用字典哈希表,对于Paul答案中的相同数据,时间为0.55秒。这不一定会找到a和b之间配对的所有副本,也就是说,如果a和b本身包含重复项,那么可以很容易地对此进行修改,或者只在匹配项上进行第二次传递,以检查这些向量在数据中的其他出现情况

import numpy as np

def intersect1(a, b):
    a_d = {}
    for i, x in enumerate(a):
        a_d[x] = i
    for i, y in enumerate(b):
        if y in a_d:
            yield a_d[y], i

from time import perf_counter
a = list(tuple(x) for x in list(np.random.randint(0, 100000, (1000000, 2))))
b = list(tuple(x) for x in list(np.random.randint(0, 100000, (1000000, 2))))
t = perf_counter(); print(list(intersect1(a, b))); s = perf_counter()
print(s-t)

比较一下,Paul's在我的机器上的时间是2.46秒。

您的行有多长,条目是什么类型的?每行的长度是2。行中的条目是整数。该数组类似于data1=[[1,1]、[2,5]、[623781]、[164,75]、…],总共大约有60万行。对数组进行排序可以将复杂性降低到日志n上,或者您可以直接在NumPy中进行比较,而不是在Python中进行for循环。这些整数有多大?它们都是正数吗?如果你有足够的内存来存储每对距离,你应该能够使用。你的行有多长,条目是什么类型?每行的长度是2。行中的条目是整数。该数组类似于data1=[[1,1]、[2,5]、[623781]、[164,75]、…],总共大约有60万行。对数组进行排序可以将复杂性降低到日志n上,或者您可以直接在NumPy中进行比较,而不是在Python中进行for循环。这些整数有多大?它们都是正数吗?如果你有足够的内存来存储每对距离,你应该能够使用。这对float也适用,对吗?只需在randint的输出中添加0.5即可进行检查。是的,Python可以很好地散列浮点数列表。如果您希望浮点数之间完全相等,它应该是。不过,通常使用浮点数时,您希望在某个阈值内相等,然后使用KDTree或类似的方法会更好。您的答案不正确。尝试检查OP的数据集,您会发现。使用intersect1data2,data1。这是正确的。不同之处在于,我假设数据是一个进入的元组列表,而不是列表列表,因为列表是不可散列的。如果我将OP的数据集转换为元组列表,我会得到正确的答案。您是否尝试过intersect1data2,data1?不相交1数据1,数据2。这不是列表或元组的问题。这应该也适用于float,对吗?只需在randint的输出中添加0.5即可进行检查。是的,Python可以很好地散列浮点数列表。如果您希望浮点数之间完全相等,它应该是。不过,通常使用浮点数时,您希望在某个阈值内相等,然后使用KDTree或类似的方法会更好。您的答案不正确。尝试检查OP的数据集,您会发现。使用intersect1data2,data1。这是正确的。区别在于我的假设数据是一个元组列表
这不是列表列表,因为列表是不可散列的。如果我将OP的数据集转换为元组列表,我会得到正确的答案。您是否尝试过intersect1data2,data1?不相交1数据1,数据2。这不是列表或元组的问题。谢谢你的回答。我用假数据集试过了,效果很好。但是,当我尝试使用实际的数据集时,它会强制空闲shell重新启动。因为没有显示错误消息,所以不太确定背后的原因。@yukchingleung如果两个数据集中都有大量多重性的非唯一性,我可以想象的一件事就是内存。谢谢你的回答。我用假数据集试过了,效果很好。但是,当我尝试使用实际的数据集时,它会强制空闲shell重新启动。因为没有显示错误消息,所以不太确定背后的原因。@yukchingleung我可以想象的一件事是内存,如果两个数据集中都有大量的非唯一性。