说我有一个排序的numpy数组:
arr = np.array([0.0, 0.0],
[0.5, 0.0],
[1.0, 0.0],
[0.0, 0.5],
[0.5, 0.5],
[1.0, 0.5],
[0.0, 1.0],
[0.5, 1.0],
[1.0, 1.0])
并且假设我对它进行了一个非常简单的操作,这样我就有了一个新的数组,它与旧数组相同,但顺序是另一个:
arr2 = np.array([0.5, 0.0],
[0.0, 0.0],
[0.0, 0.5],
[1.0, 0.0],
[0.5, 0.5],
[1.0, 0.5],
[0.0, 1.0],
[1.0, 1.0],
[0.5, 1.0])
问题是:如何获得arr2
中arr
的每个元素放置位置的索引。换句话说,我想要一个方法,它接受两个数组并返回一个与arr2
长度相同的数组,但是使用arr
元素的索引。例如,返回数组的第一个元素将是arr2
中arr
的第一个元素的索引。
where_things_are(arr2, arr)
return : array([1, 0, 3, 2, 4, 5, 6, 8, 7])
numpy中是否存在这样的函数?
修改
我试过了:
np.array([np.where((arr == x).all(axis=1)) for x in arr2])
返回我想要的内容,但我的问题仍然存在:使用numpy方法有更有效的方法吗?
EDIT2:
如果arr2
的长度与原始数组的长度不同(如果我从中移除了一些元素),它也应该有用。因此,它没有找到并反转排列,而是找到元素所在的位置。
答案 0 :(得分:2)
关键是颠倒排列。即使原始数组未排序,下面的代码仍然有效。如果它已排序,则可以使用find_map_sorted
,这显然更快。
更新:根据OP不断变化的要求,我添加了一个处理丢失元素的分支。
import numpy as np
def invperm(p):
q = np.empty_like(p)
q[p] = np.arange(len(p))
return q
def find_map(arr1, arr2):
o1 = np.argsort(arr1)
o2 = np.argsort(arr2)
return o2[invperm(o1)]
def find_map_2d(arr1, arr2):
o1 = np.lexsort(arr1.T)
o2 = np.lexsort(arr2.T)
return o2[invperm(o1)]
def find_map_sorted(arr1, arrs=None):
if arrs is None:
o1 = np.lexsort(arr1.T)
return invperm(o1)
# make unique-able
rdtype = np.rec.fromrecords(arrs[:1, ::-1]).dtype
recstack = np.r_[arrs[:,::-1], arr1[:,::-1]].view(rdtype).view(np.recarray)
uniq, inverse = np.unique(recstack, return_inverse=True)
return inverse[len(arrs):]
x1 = np.random.permutation(100000)
x2 = np.random.permutation(100000)
print(np.all(x2[find_map(x1, x2)] == x1))
rows = np.random.random((100000, 8))
r1 = rows[x1, :]
r2 = rows[x2, :]
print(np.all(r2[find_map_2d(r1, r2)] == r1))
rs = r1[np.lexsort(r1.T), :]
print(np.all(rs[find_map_sorted(r2), :] == r2))
# lose ten elements
print(np.all(rs[find_map_sorted(r2[:-10], rs), :] == r2[:-10]))
答案 1 :(得分:1)
这是一种使用numpy Broadcasting的方式:
In [10]: ind = np.where(arr[:, None] == arr2[None, :])[1]
In [11]: ind[np.where(np.diff(ind)==0)]
Out[11]: array([1, 0, 3, 2, 4, 5, 6, 8, 7])
这背后的想法是,增加数组的维度,使它们的比较产生一个3d数组,因为如果我们在比较结果的第二轴上有两个连续的相等项,那么原始子数组的长度为2这两个项目都是平等的。为了更好地演示,这里是比较的结果而不选择第二轴:
In [96]: np.where(arr[:, None] == arr2[None, :])
Out[96]:
(array([0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7,
7, 7, 8, 8, 8, 8, 8, 8]),
array([0, 1, 1, 2, 3, 6, 0, 0, 1, 3, 4, 8, 0, 1, 3, 3, 5, 7, 1, 2, 2, 4, 5,
6, 0, 2, 4, 4, 5, 8, 2, 3, 4, 5, 5, 7, 1, 2, 6, 6, 7, 8, 0, 4, 6, 7,
8, 8, 3, 5, 6, 7, 7, 8]),
array([1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1,
0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1,
0, 1, 0, 0, 1, 0, 1, 1]))
然后,为了找到那些项目,我们只需找到他们的差异为0的地方。
答案 2 :(得分:0)
如果您保证唯一性:
[ np.where(np.logical_and((arr2==x)[:,1], (arr2==x)[:,0])==True)[0][0] for x in arr]
请注意,我将您的数组转换为2D: e.g。
arr2 = np.array([[0.5, 0.0],
[0.0, 0.0],
[0.0, 0.5],
[1.0, 0.0],
[0.5, 0.5],
[1.0, 0.5],
[0.0, 1.0],
[1.0, 1.0],
[0.5, 1.0]])
答案 3 :(得分:0)
numpy_indexed包(免责声明:我是它的作者)包含完全解决此类问题的高效功能; npi.indices是list.index的ndarray等价物。
import numpy_indexed as npi
idx = npi.indices(arr, arr2)
这将返回一个索引列表,例如arr [idx] == arr2。如果arr2包含arr中不存在的元素,则会引发ValueError;但是你可以通过“缺失”来控制它。 kwarg。
如果numpy中包含此功能,请回答您的问题;是的,从某种意义上说,numpy是一个图灵完备的生态系统。但不是真的,如果你以有效,正确和一般的方式计算实现它所需的代码行数。