【问题标题】:Make every n-th slice of a 3-d numpy array consecutive使 3-d numpy 数组的每个第 n 个切片连续
【发布时间】:2019-02-15 17:53:20
【问题描述】:

声明

假设我们有一些 3 维 numpy 数组 A,其形状为 (X, Y, Z)。我想创建一个新数组B,它的形状也将是(X, Y, Z)

我们希望B 沿第零轴的前 n 个切片 (:n) 对应于 A 沿第零轴的每个第 m 切片 (::m)。

我们还希望B 的切片n:2*n 对应于A 的每个m+1 切片(1::m)。数组的其余部分依此类推。

使用矢量化 numpy 计算实现此目的的最佳方法是什么?

示例

上面的陈述最好通过一个例子来理解。所以让我们开始设置一些示例数组A

import numpy as np

# Create array A with shape (15, 3, 3)
n = 3; m = 5
a = np.array([i * np.eye(3) for i in range(1, 1+m)])
A = np.tile(a, (n, 1, 1))

如果我们看一下A 的一些零切片,我们会发现:

print(A[0])
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
print(A[1])
[[2. 0. 0.]
 [0. 2. 0.]
 [0. 0. 2.]]

...

print(A[4])
[[5. 0. 0.]
 [0. 5. 0.]
 [0. 0. 5.]]
print(A[5])
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]

等等。

A 中的值并不重要,但应该有助于说明原始语句。

我想知道我们是否可以仅使用 numpy 函数创建矩阵 B。数组B 应该有切片:

print(B[0])
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
print(B[1])
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
print(B[2])
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
print(B[3])
[[2. 0. 0.]
 [0. 2. 0.]
 [0. 0. 2.]]

等等。

有没有办法用纯 numpy 解决方案从 A 生成 B

我尝试过的

以下内容根据需要提供B,但随着m 变大,它变得乏味:

# vstack solution
B = np.vstack((A[::m], A[1::m], A[2::m], A[3::m], A[4::m]))

使用列表推导也可以,但我想避免使用循环:

# List comprehension solution
B = np.vstack([A[i::m] for i in range(m)])

【问题讨论】:

  • 所以在你的例子中n 是3?但是上面写着print(B[4])print(B[5]),不应该是print(B[2])print(B[3])吗?
  • 对不起,笨拙的编辑。你是对的。我会修改帖子

标签: python arrays python-3.x numpy


【解决方案1】:

我认为这是你想要的:

import numpy as np

# Create array A with shape (15, 3, 3)
a = np.array([i * np.eye(3) for i in range(1, 6)])
A = np.tile(a, (3, 1, 1))

B = np.swapaxes(A.reshape(3, 5, 3, 3), 0, 1)
B = B.reshape(-1, 3, 3)
print(B)
# [[[1. 0. 0.]
#   [0. 1. 0.]
#   [0. 0. 1.]]
#
#  [[1. 0. 0.]
#   [0. 1. 0.]
#   [0. 0. 1.]]
#
#  [[1. 0. 0.]
#   [0. 1. 0.]
#   [0. 0. 1.]]
#
#  [[2. 0. 0.]
#   [0. 2. 0.]
#   [0. 0. 2.]]
# ...

【讨论】:

  • 优秀。谢谢,这是一个很好的解决方案。重塑为 4d 并交换轴非常聪明!
【解决方案2】:

如果我明白,也许你可以使用numpy.sort

B = np.sort(A, axis = 0)

【讨论】:

  • 您好,感谢您的解决方案。你是对的,例如它会将A 操作为B。但是,数组中的数字并不重要,这并不能解决我的问题顶部给出的更一般的陈述。我认为这是我的错,因为这个例子可能会产生误导。 @jdehesa 下面有一个很好的解决方案。
【解决方案3】:

设置

n = 3; m = 5
a = np.array([i * np.eye(n) for i in range(1, 1+m)])

沿轴 0 使用 np.repeat 代替 tile,并使用 Fortran 样式排序进行整形。

np.repeat(a, n, 0).reshape(m*n, n, n, order='F')

array([[[1., 0., 0.],
        [0., 1., 0.],
        [0., 0., 1.]],

       [[1., 0., 0.],
        [0., 1., 0.],
        [0., 0., 1.]],

       [[1., 0., 0.],
        [0., 1., 0.],
        [0., 0., 1.]],

       [[2., 0., 0.],
        [0., 2., 0.],
        [0., 0., 2.]],    
       ...    
       [[5., 0., 0.],
        [0., 5., 0.],
        [0., 0., 5.]]])

验证

# your approach
A = np.tile(a, (n, 1, 1))
B = np.vstack((A[::m], A[1::m], A[2::m], A[3::m], A[4::m]))

# my approach
usr_B = np.repeat(a, n, 0).reshape(m*n, n, n, order='F')

>>> np.array_equal(B, usr_B)
True

时间

%%timeit
A = np.tile(a, (n, 1, 1))
B = np.vstack((A[::m], A[1::m], A[2::m], A[3::m], A[4::m]))
19 µs ± 57.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%%timeit
A = np.tile(a, (3, 1, 1))
B = np.swapaxes(A.reshape(3, 5, 3, 3), 0, 1)
B = B.reshape(-1, 3, 3)
11 µs ± 74.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit np.repeat(a, n, 0).reshape(m*n, n, n, order='F')
2.68 µs ± 21.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

【讨论】:

  • 感谢您的回答。也许你可以为我澄清一些我认为我不明白的观点。在您的解决方案中,我看不到在任何时候创建的数组 A --- 这是这个问题的起点。我也不清楚.reshape(m*n, n, n, order='F') 命令的目的:它似乎并没有改变np.repeat(a, n, 0)
  • @jwalton3141 你不需要创建A,使用这个解决方案,我只使用原始数组a 来获得你想要的输出。重塑效果很好,您只需将结果重新分配给另一个变量即可查看输出,它不会就地修改数组。
  • 我明白了。我认为我的问题可能误导了您,因为A 这个问题的起点。我想知道如何从AB,而不是从aB。不过,我确实试图在我的问题中说明这一点
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-03
  • 2012-10-26
  • 1970-01-01
  • 2017-04-17
  • 2020-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多