numpy.roll实现二维ndarray按行不同偏移水平滚动的问题
对
np.roll参数规则的正确理解 np.roll是作用于全数组的全局数组操作,官方文档中「偏移元组与axis元组长度必须一致」的规则,核心是给不同的坐标轴分别设置独立的全局偏移,不是给同一个坐标轴上的不同子元素(比如二维数组的不同行)设置差异化偏移。
举个简单例子:传入shift=(1,2), axis=(0,1)时,执行逻辑是先把整个数组沿0轴(行方向)全局滚1位,再沿1轴(列方向)全局滚2位,两次操作都是覆盖全数组的。
你之前写的np.roll(a, [1,2,1,3], axis=(1,1,1,1)),相当于重复4次指定1轴,numpy会按顺序对全数组执行4次列方向全局滚动,最终等价于沿1轴全局滚动(1+2+1+3) % 数组列数位,当然出不了逐行不同偏移的效果。
逐行设置不同水平偏移的实现方案
np.roll原生不支持单轴下不同位置设置不同偏移,这类需求可以用numpy高级索引构造移位索引实现:水平循环滚动的本质就是把每一行的列索引按指定偏移循环移位,再按新索引取数就行。
以你给出的测试数组、偏移量[1,2,1,3]为例,代码如下:
import numpy as np a = np.array([ [6, 3, 9, 2, 3], [1, 7, 8, 1, 2], [5, 4, 2, 2, 4], [3, 9, 7, 6, 5], ]) shifts = [1, 2, 1, 3] n_rows, n_cols = a.shape # 生成每行的基础列索引矩阵 col_idx = np.tile(np.arange(n_cols), (n_rows, 1)) # 按每行偏移调整列索引,取模实现循环移位,避免负数索引 shifted_col_idx = (col_idx - np.array(shifts).reshape(-1, 1)) % n_cols # 配合行索引用高级索引取数 row_idx = np.arange(n_rows).reshape(-1, 1) result = a[row_idx, shifted_col_idx]
运行得到的结果完全符合预期:
array([[3, 6, 3, 9, 2], [1, 2, 1, 7, 8], [4, 5, 4, 2, 2], [7, 6, 5, 3, 9]])
如果要实现按列设置不同垂直偏移,逻辑完全一致,只需要把索引构造逻辑对应到行维度即可。
内容的提问来源于stack exchange,提问作者xaratustra
相关产品推荐
相关产品推荐

