问题描述
我在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。