2014-10-07 66 views
3

我正在使用numpy 1.9来处理一组数组。假设我有类似的东西我有两个二维数组AB和一个1-d阵列C,这看起来像:非对齐元素在numpy数组中的插入

>>> A 
array([[ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.]]) 
>>> B 
array([[-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.]]) 
>>> C 
array([1, 3, 2, 4, 0]) 

我的目标是在从B A的所有元素插入,根据C.更具体地说,如果位置0处的C具有1,则应当在A [0,1]之后插入B [0,1]。

这里的预期结果:

array([[ 1, 1, -1, 1, 1, 1], 
     [ 1, 1, 1, 1, -1, 1], 
     [ 1, 1, 1, -1, 1, 1], 
     [ 1, 1, 1, 1, 1, -1], 
     [ 1, -1, 1, 1, 1, 1]]) 

我试图实现它这样的,但它不是非常快:

for i in xrange(size(C, 0)): 
    j = C[i] 
    A[i, :] = numpy.insert(A[i], j, B[i, j]) 

有一种方法,使其更快? (做一个单一的numpy操作,如口罩或类似的东西)

+2

你是一个错误的例子结果(你不能将一个6元素数组赋给'A [i,:]',它只有5个元素的空间)。 – 2014-10-07 03:57:43

+0

@WarrenWeckesser对不起,你是对的,我写下了示例矩阵,并没有多想太多。我正在修复:) – ProGM 2014-10-07 04:49:36

+1

我调整了你的迭代工作。 – hpaulj 2014-10-07 06:56:27

回答

5

如何一个讨厌的单线?

一,数据;数组的形状与您的形状相同,但我使用整数使示例更易于阅读。

In [81]: A 
Out[81]: 
array([[ 0, 1, 2, 3, 4], 
     [ 5, 6, 7, 8, 9], 
     [10, 11, 12, 13, 14], 
     [15, 16, 17, 18, 19], 
     [20, 21, 22, 23, 24]]) 

In [82]: B 
Out[82]: 
array([[ 0, 100, 200, 300, 400], 
     [ 500, 600, 700, 800, 900], 
     [1000, 1100, 1200, 1300, 1400], 
     [1500, 1600, 1700, 1800, 1900], 
     [2000, 2100, 2200, 2300, 2400]]) 

In [83]: C 
Out[83]: array([1, 3, 2, 4, 0]) 

而这里的肮脏的一行:

In [84]: np.insert(A.ravel(), np.ravel_multi_index((range(A.shape[0]), C), A.shape) + 1, B[range(B.shape[0]), C]).reshape(A.shape[0], A.shape[1]+1) 
Out[84]: 
array([[ 0, 1, 100, 2, 3, 4], 
     [ 5, 6, 7, 8, 800, 9], 
     [ 10, 11, 12, 1200, 13, 14], 
     [ 15, 16, 17, 18, 19, 1900], 
     [ 20, 2000, 21, 22, 23, 24]]) 

这里是破旧的版本:

A.ravel()变平A成1-d阵列,我会打电话给F

In [87]: F = A.ravel() 

In [88]: F 
Out[88]: 
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 
     17, 18, 19, 20, 21, 22, 23, 24]) 

(编辑:原来这第一步 - 展平A - 没有必要。正如@hpaulj在他的回答中指出的那样,np.insert会默认将该阵列展平。)

np.ravel_multi_index用于将所需的二维位置转换为折叠数组中的索引。

In [89]: insert_indices = np.ravel_multi_index((range(A.shape[0]), C), A.shape) + 1 

In [90]: insert_indices 
Out[90]: array([ 2, 9, 13, 20, 21]) 

B[range(B.shape[0]), C]拉期望值出B

In [91]: values = B[range(B.shape[0]), C] 

In [92]: values 
Out[92]: array([ 100, 800, 1200, 1900, 2000]) 

np.insert进行实际的+ 1末,因为你想后插入的元素C给出的指标是必要的插入并创建一个新阵列:

In [93]: np.insert(F, insert_indices, values) 
Out[93]: 
array([ 0, 1, 100, 2, 3, 4, 5, 6, 7, 8, 800, 
      9, 10, 11, 12, 1200, 13, 14, 15, 16, 17, 18, 
     19, 1900, 20, 2000, 21, 22, 23, 24]) 

现在只是重塑,要得到最终的结果是:

In [94]: np.insert(F, insert_indices, values).reshape(A.shape[0], A.shape[1]+1) 
Out[94]: 
array([[ 0, 1, 100, 2, 3, 4], 
     [ 5, 6, 7, 8, 800, 9], 
     [ 10, 11, 12, 1200, 13, 14], 
     [ 15, 16, 17, 18, 19, 1900], 
     [ 20, 2000, 21, 22, 23, 24]]) 
+1

有用的解决方案!它也可以用于三维矩阵吗?我尝试了一个小时,但我找不到正确的方式来实现您的解决方案,而不使用800 * 600 * 6矩阵的任何循环。根据这个例子,我想从B完全插入第三维元素。你可以写一个3维版本吗?谢谢! – Rowandish 2014-10-07 08:35:55

3

首先,一些稍微清晰阵列:

>>> A 
array([[ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.]]) 
>>> B 
array([[-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.]]) 
>>> C 
array([1, 3, 2, 4, 0]) 

下,一些面膜诡计:

>>> ge_mask = C.reshape(-1, 1) >= numpy.arange(5) 
>>> eq_mask = C.reshape(-1, 1) == numpy.arange(5) 
>>> lt_mask = C.reshape(-1, 1) < numpy.arange(5) 

而且政变degrâce:

>>> result = numpy.zeros((A.shape[0], A.shape[1] + 1)) 
>>> result[:,0:5][ge_mask] = A[ge_mask] 
>>> result[:,1:6][eq_mask] = B[eq_mask] 
>>> result[:,1:6][lt_mask] = A[lt_mask] 
>>> result 
array([[ 1., 1., -1., 1., 1., 1.], 
     [ 1., 1., 1., 1., -1., 1.], 
     [ 1., 1., 1., -1., 1., 1.], 
     [ 1., 1., 1., 1., 1., -1.], 
     [ 1., -1., 1., 1., 1., 1.]]) 

Warren's刚刚发布的答案好像从记忆的角度来看可能会更好。不知道速度。 (我认为上面是有点更清晰!)

+0

肯定更清晰。 :) – 2014-10-07 04:22:19

+0

谢谢!我会尝试两种方法。也许我必须编辑我的文章,以添加一个更可读的示例矩阵,就像你的;) – ProGM 2014-10-07 04:48:06

3

我相信这是修正迭代:

A=np.arange(25).reshape(5,5) 
B=np.arange(25).reshape(5,5)*-1 
C=np.array([1,3,2,4,0]) 

A2=np.zeros((5,6),dtype=int) 
for i,c in enumerate(C): 
    A2[i,:]=np.insert(A[i],c+1,B[i,c]) 

生产:

array([[ 0, 1, -1, 2, 3, 4], 
     [ 5, 6, 7, 8, -8, 9], 
     [ 10, 11, 12, -12, 13, 14], 
     [ 15, 16, 17, 18, 19, -19], 
     [ 20, -20, 21, 22, 23, 24]]) 

这可以变成一个班轮为:

np.array([np.insert(a, c+1, b[c]) for a,b,c in zip(A,B,C)]) 

在沃伦的回答等效范围是:

c <=> c = np.ravel_multi_index((range(5), C), (5,5)) 
b <=> B.ravel()[c] 
np.insert(A, c+1, B.ravel()[c]).reshape(5,6) 

np.insert ravels A作为默认值。对于这个小例子,这个ravel_multi_index比行迭代快两倍。