I have a numpy array, for example:
a = np.array([[1,2],
[3,4],
[6,4],
[5,3],
[3,5]])
and I also have a set
b = set((1,2),(6,4),(9,9))
I want to find the index of vectors that exist in set b, here is
[0, 2]
but I use a for loop to implement this, is there a convinient way to do this job avoiding for loop? The for loop method I used:
record = []
for i in range(a.shape[0]):
if (a[i, 0], a[i, 1]) in b:
record.append(i)
答案 0 :(得分:1)
You can use filter:
In [8]: a = np.array([[1,2],
[3,4],
[6,4],
[5,3],
[3,5]])
In [9]: b = {(1,2),(6,4)}
In [10]: filter(lambda x: tuple(a[x]) in b, range(len(a)))
Out[10]: [0, 2]
答案 1 :(得分:1)
首先,将该集转换为NumPy数组 -
b_arr = np.array(list(b))
然后,基于this post
,您将有三种方法。让我们使用第二种方法来提高效率 -
dims = np.maximum(a.max(0),b_arr.max(0)) + 1
a1D = np.ravel_multi_index(a.T,dims)
b1D = np.ravel_multi_index(b_arr.T,dims)
out = np.flatnonzero(np.in1d(a1D,b1D))
示例运行 -
In [89]: a
Out[89]:
array([[1, 2],
[3, 4],
[6, 4],
[5, 3],
[3, 5]])
In [90]: b
Out[90]: {(1, 2), (6, 4), (9, 9)}
In [91]: b_arr = np.array(list(b))
In [92]: dims = np.maximum(a.max(0),b_arr.max(0)) + 1
...: a1D = np.ravel_multi_index(a.T,dims)
...: b1D = np.ravel_multi_index(b_arr.T,dims)
...: out = np.flatnonzero(np.in1d(a1D,b1D))
...:
In [93]: out
Out[93]: array([0, 2])
答案 2 :(得分:0)
供参考,直接列表理解(循环)答案:
In [108]: [i for i,v in enumerate(a) if tuple(v) in b]
Out[108]: [0, 2]
与filter
方法的速度基本相同:
In [111]: timeit [i for i,v in enumerate(a) if tuple(v) in b]
10000 loops, best of 3: 24.5 µs per loop
In [114]: timeit list(filter(lambda x: tuple(a[x]) in b, range(len(a))))
10000 loops, best of 3: 29.7 µs per loop
但这是一个玩具的例子,所以时间安排没有意义。
如果a
已经不是数组,由于创建数组的开销,这些列表方法会比数组更快。
有一些numpy set操作,但它们适用于1d数组。我们可以通过将2d数组转换为1d结构来解决这个问题。
In [117]: a.view('i,i')
Out[117]:
array([[(1, 2)],
[(3, 4)],
[(6, 4)],
[(5, 3)],
[(3, 5)]],
dtype=[('f0', '<i4'), ('f1', '<i4')])
In [119]: np.array(list(b),'i,i')
Out[119]:
array([(1, 2), (6, 4), (9, 9)],
dtype=[('f0', '<i4'), ('f1', '<i4')])
有一个使用np.void
的版本,但它更容易记住和玩这个&#39;我,我&#39; D型。
这样可行:
In [123]: np.nonzero(np.in1d(a.view('i,i'),np.array(list(b),'i,i')))[0]
Out[123]: array([0, 2], dtype=int32)
但它比迭代慢得多:
In [124]: timeit np.nonzero(np.in1d(a.view('i,i'),np.array(list(b),'i,i')))[0]
10000 loops, best of 3: 153 µs per loop
正如其他近期union
个问题所述,np.in1d
使用了多种策略。一个是基于广播和where
。另一个使用unique
,concatenation
,sorting
和差异。
广播解决方案(是的,它很混乱) - 但速度超过in1d
。
In [150]: timeit np.nonzero((a[:,:,None,None]==np.array(list(b))[:,:]).any(axis=-1).any(axis=-1).all(axis=-1))[0]
10000 loops, best of 3: 52.2 µs per loop
答案 3 :(得分:0)
使用列表理解的单行解决方案:
In [62]: a = np.array([[1,2],
...: [3,4],
...: [6,4],
...: [5,3],
...: [3,5]])
In [63]: b = set(((1,2),(6,4),(9,9)))
In [64]: where([tuple(e) in b for e in a])[0]
Out[64]: array([0, 2])