我有一个大小为X
的二维数组(500,10)
和一个大小为Y
的单维索引数组500
,其每个条目都是正确值列的索引对应的X行,例如y(0)
为2,则表示X的第一行的第2列是正确的,类似地,y(3) = 4
表示X
的第3行和第4列具有正确的值。
我希望使用索引数组Y从X获取所有正确的值,而不使用任何循环,即使用向量化,在这种情况下,输出应为(500,1)
。但是当我X[:,y]
时,它会给出输出(500,500)
。有人可以帮助我如何使用Y,PLZ。
谢谢大家的帮助。
答案 0 :(得分:5)
另一个选项是多维列表位置索引:
import numpy as np
ncol = 10 # 10 in your case
nrow = 500 # 500 in your case
# just creating some test data:
x = np.arange(ncol*nrow).reshape(nrow,ncol)
y = (ncol * np.random.random_sample((nrow, 1))).astype(int)
print(x)
print(y)
print(x[np.arange(nrow),y.T].T)
语法解释为here。您基本上需要每个维度的索引数组。在第一个维度中,在您的情况下,这只是[0,...,500],第二个维度是您的y数组。我们需要转置它(.T),因为它必须具有与第一个和输出数组相同的形状。第二次换位并不是真的需要,但会给你你想要的形状。
修改强>
性能问题出现了,我尝试了迄今为止提到的三种方法。您需要line_profiler以
运行以下内容kernprof -l -v tmp.py
其中tmp.py是:
import numpy as np
@profile
def calc(x,y):
z = np.arange(nrow)
a = x[z,y.T].T # mine, with the suggested speed up
b = x[:,y].diagonal().T # Christoph Terasa
c = np.array([i[j] for i, j in zip(x, y)]) # tobias_k
return (a,b,c)
ncol = 5 # 10 in your case
nrow = 10 # 500 in your case
x = np.arange(ncol*nrow).reshape(nrow,ncol)
y = (ncol * np.random.random_sample((nrow, 1))).astype(int)
a, b, c = calc(x,y)
print(a==b)
print(b==c)
我的python 2.7.6的输出:
Line # Hits Time Per Hit % Time Line Contents
==============================================================
3 @profile
4 def calc(x,y):
5 1 4 4.0 0.1 z = np.arange(nrow)
6 1 35 35.0 0.8 a = x[z,y.T].T
7 1 3409 3409.0 76.7 b = x[:,y].diagonal().T
8 501 995 2.0 22.4 c = np.array([i[j] for i, j in zip(x, y)])
9
10 1 1 1.0 0.0 return (a,b,c)
其中%Time或Time是相关列。我不知道如何描述内存消耗,其他人则必须这样做。 现在看起来我的解决方案对于所请求的尺寸来说速度最快。
答案 1 :(得分:4)
虽然从句法角度来看并不是很直观
X[:,Y].diagonal()[0]
会为您提供您正在寻找的价值。花哨的索引从X
的每一行中选择Y
中的所有值,而diagonal
仅选择i == j的索引处的那些。最后使用[0]
建立索引只会使2d数组变平。
答案 2 :(得分:4)
您需要辅助向量R
来索引行
In [50]: X = np.arange(24).reshape((6,4))
In [51]: Y = np.random.randint(0,4,6)
In [52]: R = np.arange(6)
In [53]: Y
Out[53]: array([0, 2, 2, 0, 1, 0])
In [54]: X[R,Y]
Out[54]: array([ 0, 6, 10, 12, 17, 20])
用于您的用例
X_y = X[np.arange(500), Y]
修改的
我忘了提及,如果你想要2D结果,你可以使用虚拟索引获得这样的结果
X_y_2D = X[np.arange(500), Y, None]