我有两个数组,我想计算一个巧合的列表/数组。也就是说,所有索引i,j的列表使得a [i] == b [j]。这是我现在的代码:
b = np.array([3, 5, 6, 4])
a = np.array([1, 2, 3, 4])
np.array([[i, j] for i in range(a.size) for j in range(b.size) if a[i] == b[j]])
是否有更快(也许是以numpy为动力)的方式来做到这一点?
答案 0 :(得分:2)
一种方法是使用np.in1d
-
m_a = np.in1d(a,b)
I = np.flatnonzero(m_a)
J = np.flatnonzero(np.in1d(b, a[m_a]))
示例输入,输出 -
In [367]: a
Out[367]: array([1, 2, 3, 4])
In [368]: b
Out[368]: array([3, 5, 6, 4])
In [370]: I
Out[370]: array([2, 3])
In [371]: J
Out[371]: array([0, 3])
另一种直接但记忆重要的方式是使用broadcasting
-
I,J = np.nonzero(a[:,None] == b)
对于输入数组中没有重复项的情况,我们可以使用np.searchsorted
。这里有两个变体 - 一个用于排序a
,另一个用于通用a
。
变体#1:对于已排序的a
-
idx = np.searchsorted(a, b)
idx[idx==a.size] = 0
mask = a[idx] == b
I = np.searchsorted(a,b[mask])
J = np.flatnonzero(mask)
变体#2:对于此通用变体案例,我们需要使用a
的argsort索引 -
sidx = a.argsort()
a_sort = a[sidx]
idx = np.searchsorted(a_sort, b)
idx[idx==a.size] = 0
mask = a_sort[idx] == b
I = sidx[np.searchsorted(a_sort,b[mask])]
J = np.flatnonzero(mask)
答案 1 :(得分:1)
numpy
解决方案可能正在使用函数numpy.argwhere(),该函数可用于查找符合给定条件的数组的索引。
ax = np.tensordot(a, np.ones(len(a)), axes = 0)
bx = np.tensordot(np.ones(len(b)), b, axes = 0)
np.argwhere(ax - bx == 0)
ax - bx
的零元素索引只是那些与a
和b
的相等元素对应的索引,因为有常量行rsp。张量产品的列相交'。不确定,这个解决方案是否更快。
答案 2 :(得分:1)
[已经解决了,但这里是时间]:
我已将您的解决方案与更多python列表方式以及建议的矩阵解决方案here进行了比较:(您需要从该矩阵中获取索引)。
import numpy as np
import random
import time
random.seed(12345)
b = [random.randint(0,100000) for i in range(10000)]
a = [random.randint(0,100000) for i in range(10000)]
为了获得更准确的计时(对于大型数据集),我创建了两个(伪)随机整数列表,其长度为1e5。
#List based approach
start_time = time.time()
c2 = [[i,j] for i in range(len(a)) for j in range(len(b)) if a[i] == b[j]]
print time.time() - start_time # t = 29.2776758671
b = np.array(a)
a = np.array(b)
#NumPy Array based approach
start_time = time.time()
c1 = np.array([[i, j] for i in range(a.size) for j in range(b.size) if a[i] == b[j]])
print time.time() - start_time # t = 46.374776125
虽然在不使用numpy数组的情况下需要稍微缩短,但它并不是一个巨大的时间差,但它仍然意味着大型矢量的计算时间相当长。
以巧合的形式创建中介解决方案
#Coincidence Matrix (NumPy) based approach
start_time = time.time()
c3 = (a[None,:] == b[:,None]).astype(int)
c3s = np.where(c3 == 1)
print time.time() - start_time # t = 0.857568979263
我还计划了之前发布的另一个解决方案,似乎是解决此问题的最快方法:
c4 = np.nonzero(a[:,None] == b)
# t = 0.399062156677
答案 3 :(得分:1)
基于dicts集和列表的(非常)快速解决方案,它在时间和空间上是线性的,无论数据是什么,是否重复,是否是大键。
a,b = np.random.randint(0,10**8,size=(2,10**4))
import collections
def default(a):
d=collections.defaultdict(list)
for k,v in enumerate(a):
d[v].append(k)
return d
def coincidences(a,b):
aa=default(a)
bb=default(b)
ab=set(aa.keys()) & set(bb.keys())
l=[]
for k in ab:
for i in aa[k]:
for j in bb[k]:
l.append((i,j))
return l
运行:
In [125]: %timeit coincidences(a,b)
10.6 ms ± 402 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Numpy只有在能够实现线性解决方案时才会获胜。
修改强>
等效的Pandas解决方案(相同时间):
def coincidences_pd(a,b):
aa=pd.DataFrame(list(range(len(a))),a)
bb=pd.DataFrame(list(range(len(b))),b)
return pd.merge(aa,bb,left_index=True,right_index=True)
In [219]: coincidences_pd(a,b)
Out[219]:
0_x 0_y
54025822 1752 8046
84735197 7301 2956