高效的numpy索引:获取M行的每个块的前N行

时间:2016-09-25 23:24:22

标签: python numpy vectorization

x = np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15])

我想从5的每个块中获取前2行数组x,结果应为:

x[fancy_indexing] = [1,2, 6,7, 11,12]

使用for循环构建索引很容易。

是否有单线切片技巧可以将其拉下来?这里简单点。

4 个答案:

答案 0 :(得分:3)

方法#1 这是使用boolean-indexing的矢量化单行 -

x[np.mod(np.arange(x.size),M)<N]

方法#2 如果你想要表现,这是使用NumPy strides的另一种矢量化方法 -

n = x.strides[0]
shp = (x.size//M,N)
out = np.lib.stride_tricks.as_strided(x, shape=shp, strides=(M*n,n)).ravel()

示例运行 -

In [61]: # Inputs
    ...: x = np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15])
    ...: N = 2
    ...: M = 5
    ...: 

In [62]: # Approach 1
    ...: x[np.mod(np.arange(x.size),M)<N]
Out[62]: array([ 1,  2,  6,  7, 11, 12])

In [63]: # Approach 2
    ...: n = x.strides[0]
    ...: shp = (x.size//M,N)
    ...: out=np.lib.stride_tricks.as_strided(x,shape=shp,strides=(M*n,n)).ravel()
    ...: 

In [64]: out
Out[64]: array([ 1,  2,  6,  7, 11, 12])

答案 1 :(得分:1)

将数组重塑为多行五列,然后取(切片)每行的前两列。

>>> x
array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15])
>>> x.reshape(x.shape[0] / 5, 5)[:,:2]
array([[ 1,  2],
       [ 6,  7],
       [11, 12]])

或者

>>> x.reshape(x.shape[0] / 5, 5)[:,:2].flatten()
array([ 1,  2,  6,  7, 11, 12])
>>> 

它仅适用于长度为5的倍数的1-d数组。

答案 2 :(得分:0)

import numpy as np

x = np.array(range(1, 16))
y = np.vstack([x[0::5], x[1::5]]).T.ravel()
y
// => array([ 1,  2,  6,  7, 11, 12])

获取数组N中每个M行的第[1, 2, ..., K行:

import numpy as np

K = 30
M = 5
N = 2

x = np.array(range(1, K+1))
y = np.vstack([x[i::M] for i in range(N)]).T.ravel()
y
// => array([ 1,  2,  6,  7, 11, 12, 16, 17, 21, 22, 26, 27])

请注意.T.ravel()是快速操作:它们不会复制任何数据,只是操纵数组的尺寸和步幅。

如果您坚持使用花式索引获取切片:

import numpy as np

K = 30
M = 5
N = 2

x = np.array(range(1, K+1))
fancy_indexing = [i*M+n for i in range(len(x)//M) for n in range(N)]
x[fancy_indexing]
// => array([ 1,  2,  6,  7, 11, 12, 16, 17, 21, 22, 26, 27])

答案 3 :(得分:0)

我首先想到你需要这个才能用于2d阵列,因为你的“M行的每个块的前N行”都是这样的,所以我会把这个解决方案保留下去。

你可以通过将数组重塑为3d来实现一些魔力:

// ===== Code from file PersonInfo.java =====
public class PersonInfo {
   private int numKids;

   public void setNumKids(int personsKids) {
      numKids = personsKids;
      return;
   }

   public void incNumKids() {
      numKids = numKids + 1;
      return;
   }

   public int getNumKids() {
      return numKids;
   }
}
// ===== end =====

// ===== Code from file CallPersonInfo.java =====
public class CallPersonInfo {
   public static void main (String [] args) {
      PersonInfo person1 = new PersonInfo();

      person1.setNumKids(3);


//changes must be made after this line. So NO changes above this line.

      System.out.println("Kids: " + person1.getNumKids());

      person1.setNumKids(4);
      System.out.println("New baby, kids now: " + person1.getNumKids());

//changes must be made above this line. So NO changes below this line.     

      return;
   }
}
// ===== end =====  

这将根据您的偏好提取每列。为了将它用于你的1d案例,你需要使用M = 5 # size of blocks N = 2 # number of columns to cut x = np.arange(3*4*M).reshape(4,-1) # (4,3*N)-shaped dummy input x = x.reshape(x.shape[0],-1,M)[:,:,:N+1].reshape(x.shape[0],-1) # (4,3*N)-shaped output 将你的1d阵列变成2d阵列​​。

相关问题