将numpy数组重塑为小子切片

问题描述

我在numpy中有一个数组,如下所示:

[1,2,3,4,5,6,7,8,9,10]

我想像这样重塑它:

[[1,3],[2,4],[3,5],[4,6],[6,8],[7,9],[8,10]]

最有效的方法是什么?

我当前正在做的是使用np.append进行循环,但这会花费很长时间。

谢谢

解决方法

您可以使用numpy的跨步技巧(numpy.lib.stride_tricks.as_strided)来创建数组的新视图。这将比任何列表理解都快,因为没有数据被复制。 IPython Cookbook has more examples使用跨步技巧。

import numpy as np

a = np.array([1,2,3,4,5,6,7,8,9,10])
bytes_per_item = a.dtype.itemsize
b = np.lib.stride_tricks.as_strided(
    a,shape=(8,3),strides=(bytes_per_item,bytes_per_item))
array([[ 1,3],[ 2,4],[ 3,5],[ 4,6],[ 5,7],[ 6,8],[ 7,9],[ 8,10]])

定时测试

此答案比此处使用循环的答案要快几个数量级。查找以下测试(使用%timeit魔术在Jupyter Notebook中完成)。请注意,其中一个功能不适用于numpy数组,并且需要Python列表。

设置

import numpy as np

a = np.arange(1,100001,dtype=np.int64)
a_list = a.tolist()

def jakub(a,shape):
    a = np.asarray(a)
    bytes_per_item = a.dtype.itemsize
    # The docs for this function recommend setting `writeable=False` to
    # prevent modifying the underlying array.
    return np.lib.stride_tricks.as_strided(
        a,shape=shape,bytes_per_item),writeable=False)

# https://stackoverflow.com/a/63426256/5666087
def daveldito(arr):
    return np.array([arr[each:each+2]+[arr[each+2]] for each in range(len(arr)-2)])

# https://stackoverflow.com/a/63426205/5666087
def akshay_sehgal(a):
    return np.array([i for i in zip(a,a[1:],a[2:])])

结果

%timeit jakub(a,shape=(a.shape[0]-2,3))
8.85 µs ± 425 ns per loop (mean ± std. dev. of 7 runs,100000 loops each)

%timeit daveldito(a_list)
141 ms ± 8.94 ms per loop (mean ± std. dev. of 7 runs,10 loops each)

%timeit akshay_sehgal(a)
168 ms ± 9.43 ms per loop (mean ± std. dev. of 7 runs,1 loop each)
,

您可以在列表上进行3克迭代的一种方法是使用zip

a = [1,10]
np.array([i for i in zip(a,a[2:])])
array([[ 1,10]])

可以使用以下命令来创建解决n-gram迭代的通用函数-

def find_ngrams(input_list,n):
    return np.array(list(zip(*[input_list[i:] for i in range(n)])))

find_ngrams(a,3) #try setting n to other values like 2 or 4 or 5
array([[ 1,10]])
find_ngrams(a,5)
array([[ 1,10]])
,

我将按照以下步骤进行操作(请注意,我仅依赖于基本的列表理解):

arr = [1,10]
np.array([arr[each:each+2]+[arr[each+2]] for each in range(len(arr)-2)])

输出:

array([[ 1,10]])

关于性能,对于100_000中的arr个元素,我2016年末的MacBook Pro提供以下时间统计信息:

CPU时间:用户148毫秒,sys:26.1毫秒,总计:174毫秒 挂墙时间:186毫秒

,

使用np.lib.stride_tricks.as_strided的另一种解决方案:

import numpy as np
x = np.array([1,10])

newshape = x.shape[:-1] + (x.shape[-1] - 3 + 1,3)
a = np.lib.stride_tricks.as_strided(x,shape=newshape,strides=x.strides + (x.strides[-1],))

返回

array([[ 1,10]])

您可以阅读有关该主题的更多信息,例如here

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...