在大型1维NumPy数组中切片模式

时间:2018-12-20 16:28:28

标签: python numpy indexing slice

我有一个1维数组,其中的肠腔中有一个模式。我举一个例子。在数组ALTER FOREIGN FUNCTION app.fn_getphone ( iduser INT ) SERVER mssql_svr_cm OPTIONS (TABLE 'dbo.fn_getphone', row_estimate_method 'showplan_all'); 中,我有 前4个具有一位数字的小肠,其次4个具有两位数字的小肠,然后下6个具有3位数字的小肠。 (这个单,双,三位数只是为了突出显示模式。实际的数组具有相似值的浮点数。)示例的一维数组看起来像:

arr

现在,一个完整的模式共有4 + 4 + 6 = 14个肠。此模式(或重复单元)重复了数十万次,因此我数组的长度是14的倍数(在上面的示例import numpy as np arr = np.array([1, 2, 3, 4, 11, 12, 13, 14, 111, 123, 132, 145, 176, 129, 6, 5, 3, 2, 21, 82, 53, 34, 121, 133, 139, 165, 186, 119]) 中为14 * 2 = 28)。

问题:

我要提取所有一位数字的小肠(一个重复单元的前4个数字),所有两位数字的小肠 (一个重复单元的后4个数字)和所有三位数的小肠(一个重复单元的后6个数字)。

这样,我想将我的大arr分成三个一维数组。因此,所需的输出

arr

我的想法

一种方法可能是将arr1 = array([1, 2, 3, 4, 6, 5, 3, 2]) arr2 = array([11, 12, 13, 14, 21, 82, 53, 34]) arr3 = array([111, 123, 132, 145, 176, 129, 121, 133, 139, 165, 186, 119]) 简单地放入2d数组,因为我知道重复的次数(在示例reshape中== 28/14 = 2),然后使用索引来获取所有第一个4、4和6的块 然后arr

concatenate

,然后使用切片将块作为

arr = arr.reshape(2, 14)

但是我有兴趣了解使用某种 masking slicing 而无需先转换为2d的替代高效解决方案数组。

4 个答案:

答案 0 :(得分:1)

根据要求使用图案的遮罩(并假设arr长度是遮罩长度的精确倍数):

mask1 = [True]*4 + [False]*10
mask2 = [False]*4 + [True]*4 + [False]*6
mask3 = [False]*8 + [True]*6

然后您可以通过执行以下操作直接获得所需的数组:

n_masks = (len(arr) // len(mask1))
arr1 = arr[mask1 * n_masks]
arr2 = arr[mask2 * n_masks]
arr3 = arr[mask3 * n_masks]

答案 1 :(得分:1)

您可以直接访问索引

import numpy as np
arr = np.array([1, 2, 3, 4, 11, 12, 13, 14, 111, 123, 132, 145, 176, 129,
                6, 5, 3, 2, 21, 82, 53, 34, 121, 133, 139, 165, 186, 119])

run_length = 14
repetitions = 2

indices1 = [run_length * i + j for i in range(repetitions) for j in range(4)]
arr1 = arr[indices1]

indices2 = [run_length * i + j for i in range(repetitions) for j in range(4, 8)]
arr2 = arr[indices2]

indices3 = [run_length * i + j for i in range(repetitions) for j in range(8, 14)]
arr3 = arr[indices3]

print(arr1)
print(arr2)
print(arr3)

输出

[1 2 3 4 6 5 3 2]
[11 12 13 14 21 82 53 34]
[111 123 132 145 176 129 121 133 139 165 186 119]

您可以将所有内容放入这样的函数中:

import numpy as np
arr = np.array([1, 2, 3, 4, 11, 12, 13, 14, 111, 123, 132, 145, 176, 129,
                6, 5, 3, 2, 21, 82, 53, 34, 121, 133, 139, 165, 186, 119])


def extract(arr, run_length, repetitions, pattern_lengths):
    chunks = [0] + np.cumsum(pattern_lengths).tolist()

    for start, end in zip(chunks, chunks[1:]):
        indices = [run_length * i + j for i in range(repetitions) for j in range(start, end)]
        yield arr[indices]


arr1, arr2, arr3 = list(extract(arr, 14, 2, [4, 4, 6]))

print(arr1)
print(arr2)
print(arr3)

答案 2 :(得分:1)

您还可以构建遮罩:

# if you know where your indices are, otherwise use a formula
mask = np.zeros((3, 2, 14), dtype=bool)
mask[0,:, 0:4] = True
mask[1,:, 4:8] = True
mask[2,:, 8:] = True

arr1, arr2, arr3 = (arr[m.flatten()] for m in mask)
print (arr1, arr2, arr3)

答案 3 :(得分:1)

我们可以简单地重塑为2D(记住重塑会创建一个视图,并且内存开销为零,因此在运行时实际上是空闲的),而col的数量与模式lenth相同(示例中为14)。然后,slice列出第一个数组输出的前4个条目,接下来的4个用于第二个数组,最后的第8个col用于最后一个数组。

因为我们需要扁平化的输出,所以可以使用.ravel()来实现。

因此-

In [44]: a2d = arr.reshape(-1,14) # 2d view into arr
    ...: arr1,arr2,arr3 = a2d[:,:4].ravel(),a2d[:,4:8].ravel(),a2d[:,8:].ravel()

In [45]: arr1
Out[45]: array([1, 2, 3, 4, 6, 5, 3, 2])

In [46]: arr2
Out[46]: array([11, 12, 13, 14, 21, 82, 53, 34])

In [47]: arr3
Out[47]: array([111, 123, 132, 145, 176, 129, 121, 133, 139, 165, 186, 119])

现在,说我们对2D数组输出没问题,然后-

In [48]: arr1,arr2,arr3 = a2d[:,:4],a2d[:,4:8],a2d[:,8:]

In [49]: arr1
Out[49]: 
array([[1, 2, 3, 4],
       [6, 5, 3, 2]])

In [50]: arr2
Out[50]: 
array([[11, 12, 13, 14],
       [21, 82, 53, 34]])

In [51]: arr3
Out[51]: 
array([[111, 123, 132, 145, 176, 129],
       [121, 133, 139, 165, 186, 119]])

那么,为什么要接受这个?因为它是原始输入arr的视图,因此如前所述,它的内存开销为零,实际上是空闲的-

In [52]: np.shares_memory(arr,arr1)
Out[52]: True

依次类推,其他两个数组。