[英]Repeat 1D array to 2D array with shifted rows
我想使用一个数组a = [1, 2, 3, 4, 5]
并将它变成一个 5x5 数组,如下所示:
[[1, 2, 3, 4, 5],
[2, 3, 4, 5, 0],
[3, 4, 5, 0, 0],
[4, 5, 0, 0 ,0],
[5, 0, 0, 0, 0]]
我怎样才能用numpy
做到这一点?
我还希望能够使用像a = [1, 6, 2, 3, 8]
这样的任意数组并得到:
[[1, 6, 2, 3, 8],
[6, 2, 3, 8, 0],
[2, 3, 8, 0, 0],
[3, 8, 0, 0, 0],
[8, 0, 0, 0, 0]]
以下解决方案仅在您只需要一个视图时才有效。 此解决方案不返回可写数组。 如果你需要一个可写数组,你可以简单地将视图传递给数组构造函数: np.array(array_view)
,但在这一点上,@ linalg.hankel
解决方案中的 linalg.hankel 是一个更好的方法,除非你想使用任何我添加的有趣功能。
这是一个适用于任意一维 arrays 并且速度极快的解决方案:
def fast_hankel_view(a: np.ndarray) -> np.ndarray:
arr = np.append(a, np.zeros(a.size - 1, a.dtype))
return np.lib.stride_tricks.sliding_window_view(arr, a.size)
Output:
>>> a = np.array([1, 2, 3, 4, 5])
>>> fast_hankel_view(a)
array([[1, 2, 3, 4, 5],
[2, 3, 4, 5, 0],
[3, 4, 5, 0, 0],
[4, 5, 0, 0, 0],
[5, 0, 0, 0, 0]])
>>> a = np.array([1, 4, 3, 5, 8, 3, 8, 3, 2, 1, 8])
>>> fast_hankel_view(a)
array([[1, 4, 3, 5, 8, 3, 8, 3, 2, 1, 8],
[4, 3, 5, 8, 3, 8, 3, 2, 1, 8, 0],
[3, 5, 8, 3, 8, 3, 2, 1, 8, 0, 0],
[5, 8, 3, 8, 3, 2, 1, 8, 0, 0, 0],
[8, 3, 8, 3, 2, 1, 8, 0, 0, 0, 0],
[3, 8, 3, 2, 1, 8, 0, 0, 0, 0, 0],
[8, 3, 2, 1, 8, 0, 0, 0, 0, 0, 0],
[3, 2, 1, 8, 0, 0, 0, 0, 0, 0, 0],
[2, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
100,000 个随机整数数组的小型基准测试:
In [3]: x = np.random.randint(0, 255, (1, 100000), dtype="uint8")
In [4]: %timeit fast_hankel_view(x)
25.8 µs ± 165 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
同样,这非常快,因为它只是构建输入数组x
的视图:
In [5]: h = fast_hankel_view(x)
In [6]: h += 1
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-14-ce0b251d63e1> in <module>
----> 1 h += 1
ValueError: output array is read-only
然而,重申一下,您可以通过将视图传递给np.array()
构造函数来从 output 获取可写数组:
In [7]: x = np.array([1, 3, 5, 7])
In [8]: h = np.array(fast_hankel_view(x))
In [9]: h
Out[9]:
array([[1, 3, 5, 7],
[3, 5, 7, 0],
[5, 7, 0, 0],
[7, 0, 0, 0]])
In [10]: h += 1
In [11]: h
Out[11]:
array([[2, 4, 6, 8],
[4, 6, 8, 1],
[6, 8, 1, 1],
[8, 1, 1, 1]])
通过一个小的修改,你也可以在对角线上反射,如果你愿意,或者用另一个数组填充(注意,两个 arrays 的元素总数必须是奇数才能使结果为正方形):
import numpy as np
def fast_hankel_view(x: np.ndarray) -> np.ndarray:
return np.lib.stride_tricks.sliding_window_view(x, (x.size + 1) // 2)
def hankel_view_builder(a: np.ndarray, pad="zeros") -> np.ndarray:
if type(pad) == np.ndarray:
arr = np.append(a, pad)
elif pad == "zeros":
arr = np.append(a, np.zeros(a.size - 1, a.dtype))
elif pad == "reflect":
arr = np.append(a, np.flip(a)[1:])
else:
raise ValueError("invalid pad type!")
return fast_hankel_view(arr)
附加到两个 arrays 并使用sliding_window_view
的一个很好的好处是您可以提供不同长度的 arrays(在我看来,使用 scipy 的linalg.hankel
返回不直观的结果):
In [11]: x
Out[11]: array([1, 2, 3])
In [12]: y
Out[12]: array([4, 5, 6, 7, 8, 9])
In [13]: hankel_view_builder(x, y) # note the parity of |x| + |y|
Out[13]:
array([[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[3, 4, 5, 6, 7],
[4, 5, 6, 7, 8],
[5, 6, 7, 8, 9]])
In [14]: hankel_view_builder(y, "reflect")
Out[14]:
array([[4, 5, 6, 7, 8, 9],
[5, 6, 7, 8, 9, 8],
[6, 7, 8, 9, 8, 7],
[7, 8, 9, 8, 7, 6],
[8, 9, 8, 7, 6, 5],
[9, 8, 7, 6, 5, 4]])
In [15]: hankel_view_builder(y)
Out[15]:
array([[4, 5, 6, 7, 8, 9],
[5, 6, 7, 8, 9, 0],
[6, 7, 8, 9, 0, 0],
[7, 8, 9, 0, 0, 0],
[8, 9, 0, 0, 0, 0],
[9, 0, 0, 0, 0, 0]])
如果可以使用 scipy:
from scipy import linalg
linalg.hankel([1,2,3,4,5])
# array([[1, 2, 3, 4, 5],
# [2, 3, 4, 5, 0],
# [3, 4, 5, 0, 0],
# [4, 5, 0, 0, 0],
# [5, 0, 0, 0, 0]])
如果不:
def hankel(a):
n = len(a)
out = np.zeros((n,n),int)
out.ravel()[:-1].reshape(n+1,n-1)[1:,0] = a[-1]
np.copyto(out.ravel()[:1-2*n].reshape(n-1,n-1),a[:-1],where=np.tri(n-1,dtype=bool).T)
return out
hankel([1,2,3,4,5])
# array([[1, 2, 3, 4, 5],
# [2, 3, 4, 5, 0],
# [3, 4, 5, 0, 0],
# [4, 5, 0, 0, 0],
# [5, 0, 0, 0, 0]])
import numpy as np
a = [1, 2, 3, 4, 5]
r = np.add.outer(a,a) - 1
np.where(r <= len(a), r, 0)
Output
array([[1, 2, 3, 4, 5],
[2, 3, 4, 5, 0],
[3, 4, 5, 0, 0],
[4, 5, 0, 0, 0],
[5, 0, 0, 0, 0]])
更一般的不断增加 integer 范围
a = [-2, -1, 0 , 1, 2, 3]
r = np.add.outer(a,a) - np.min(a)
np.where(r <= np.max(a), r, 0)
Output
array([[-2, -1, 0, 1, 2, 3],
[-1, 0, 1, 2, 3, 0],
[ 0, 1, 2, 3, 0, 0],
[ 1, 2, 3, 0, 0, 0],
[ 2, 3, 0, 0, 0, 0],
[ 3, 0, 0, 0, 0, 0]])
对于任意 arrays
import numpy as np
a = np.array([1, 4, 3, 5, 8, 3, 8, 3, 2, 1, 8])
x = np.arange(len(a))
r = np.add.outer(x,x)
idx = np.where(r <= len(x)-1, r, 0)
np.where(r <= len(x)-1, np.full(r.shape, a)[np.arange(len(a)),idx], 0)
Output
array([[1, 4, 3, 5, 8, 3, 8, 3, 2, 1, 8],
[4, 3, 5, 8, 3, 8, 3, 2, 1, 8, 0],
[3, 5, 8, 3, 8, 3, 2, 1, 8, 0, 0],
[5, 8, 3, 8, 3, 2, 1, 8, 0, 0, 0],
[8, 3, 8, 3, 2, 1, 8, 0, 0, 0, 0],
[3, 8, 3, 2, 1, 8, 0, 0, 0, 0, 0],
[8, 3, 2, 1, 8, 0, 0, 0, 0, 0, 0],
[3, 2, 1, 8, 0, 0, 0, 0, 0, 0, 0],
[2, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
对于想要沿轴 0 移动的任意 arrays:
import numpy as np
a = np.array([1,2,3,4,5])
padded = np.append(np.zeros((1, a.size)), a)
print("padded:")
print(padded)
duplicated = np.tile(padded, a.size)
print("duplicated:")
print(duplicated)
resized = np.resize(duplicated, (a.size+1, padded.size - 1))
print("resized:")
print(resized)
flipped = resized[::-1]
print("flipped:")
print(flipped)
result = flipped[:a.size,:a.size]
print("result:")
print(result)
Output
padded:
[0. 0. 0. 0. 0. 1. 2. 3. 4. 5.]
duplicated:
[0. 0. 0. 0. 0. 1. 2. 3. 4. 5. 0. 0. 0. 0. 0. 1. 2. 3. 4. 5. 0. 0. 0. 0.
0. 1. 2. 3. 4. 5. 0. 0. 0. 0. 0. 1. 2. 3. 4. 5. 0. 0. 0. 0. 0. 1. 2. 3.
4. 5.]
resized:
[[0. 0. 0. 0. 0. 1. 2. 3. 4.]
[5. 0. 0. 0. 0. 0. 1. 2. 3.]
[4. 5. 0. 0. 0. 0. 0. 1. 2.]
[3. 4. 5. 0. 0. 0. 0. 0. 1.]
[2. 3. 4. 5. 0. 0. 0. 0. 0.]
[1. 2. 3. 4. 5. 0. 0. 0. 0.]]
flipped:
[[1. 2. 3. 4. 5. 0. 0. 0. 0.]
[2. 3. 4. 5. 0. 0. 0. 0. 0.]
[3. 4. 5. 0. 0. 0. 0. 0. 1.]
[4. 5. 0. 0. 0. 0. 0. 1. 2.]
[5. 0. 0. 0. 0. 0. 1. 2. 3.]
[0. 0. 0. 0. 0. 1. 2. 3. 4.]]
result:
[[1. 2. 3. 4. 5.]
[2. 3. 4. 5. 0.]
[3. 4. 5. 0. 0.]
[4. 5. 0. 0. 0.]
[5. 0. 0. 0. 0.]]
arr = np. array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# Convert 1D array to a 2D numpy array of 2 rows and 3 columns.
arr_2d = np. reshape(arr, (2, 5))
print(arr_2d)
您可以使用 reshape function。根据您的要求填充数组,然后使用 reshape。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.