【问题标题】:3-dimensional array in numpynumpy中的3维数组
【发布时间】:2014-05-23 19:03:37
【问题描述】:

Python 和 Numpy 的新手,尝试创建 3 维数组。我的问题是尺寸的顺序与 Matlab 相比是关闭的。事实上,这个顺序根本没有意义。

创建矩阵:

x = np.zeros((2,3,4))

在我的世界中,这应该导致 2 行、3 列和 4 个深度维度,并且应该显示为:

[0 0 0      [0 0 0      [0 0 0      [0 0 0
 0 0 0]      0 0 0]      0 0 0]      0 0 0] 

在每个深度维度上分开。 相反,它显示为

[0 0 0 0      [0 0 0 0
 0 0 0 0       0 0 0 0
 0 0 0 0]      0 0 0 0]

即 3 行 4 列 2 个深度维度。也就是说,第一个维度是“深度”。为了进一步增加这个问题,使用 OpenCV 导入图像,颜色维度是最后一个维度,也就是说,我将颜色信息视为深度维度。如果我只想在已知较小的 3 维数组上尝试一些东西,这会使事情变得非常复杂。

我是不是误会了什么?如果不是,为什么使用这种不直观的方式处理 3D 维数组是 numpy 的?

【问题讨论】:

标签: python numpy


【解决方案1】:

您是对的,您正在创建一个具有 2 行、3 列和 4 深度的矩阵。 Numpy 打印与 Matlab 不同的矩阵:

麻木:

>>> import numpy as np
>>> np.zeros((2,3,2))
 array([[[ 0.,  0.],
    [ 0.,  0.],
    [ 0.,  0.]],

   [[ 0.,  0.],
    [ 0.,  0.],
    [ 0.,  0.]]])

Matlab

>> zeros(2, 3, 2)
 ans(:,:,1) =
     0     0     0
     0     0     0
 ans(:,:,2) =
     0     0     0
     0     0     0

但是,您正在计算相同的矩阵。看看Numpy for Matlab users,它将指导您将Matlab代码转换为Numpy。


例如,如果您使用的是 OpenCV,则可以使用 numpy 构建图像,同时考虑到 OpenCV 使用 BGR 表示:

import cv2
import numpy as np

a = np.zeros((100, 100,3))
a[:,:,0] = 255

b = np.zeros((100, 100,3))
b[:,:,1] = 255

c = np.zeros((100, 200,3)) 
c[:,:,2] = 255

img = np.vstack((c, np.hstack((a, b))))

cv2.imshow('image', img)
cv2.waitKey(0)

如果你看一下矩阵c,你会看到它是一个 100x200x3 的矩阵,这正是它在图像中显示的内容(红色,因为我们将 R 坐标设置为 255,其他两个保持为 0 )。

【讨论】:

  • 好的,所以如果一切计算正确,我可以期望算法对于较小的矩阵和大图像也是相同的?将第三维视为“深度”。这是有道理的,因为数学将所有维度都视为相同。但是有什么方法可以让 Numpy 正确存在吗?恐怕链接在这方面没有多大帮助:(
  • Matlab 和 Numpy 处理图像的方式不同,如果您使用 OpenCV,则它将图像表示为 BGR 而不是 RGB,然后 Matlab 使用 fortran 读取矩阵。所以在将代码从 matlab 移植到 numpy 时,你必须考虑所有这些因素
  • 太好了,我尝试了一些东西,当然,正如你所说。我知道 BGR 演示文稿(它让我很烦恼,但没有这么多)。我只是希望有一种方法可以“正确”地呈现它。现在,我将分别查看每个暗淡,因为(对于 3D 矩阵 e)e[:,:,1] 显示正确,而 e[:,:,:-1] 显示不合逻辑。谢谢!
  • 这是不正确的,“深度”是显示的第一个维度。在 C 排序中,显示的第一个维度是具有“最大步幅”的维度。实际顺序是深度、行、列。在 fortran 排序中它是相反的,所以它是列、行和深度。
【解决方案2】:

你有一个截断的数组表示。我们来看一个完整的例子:

>>> a = np.zeros((2, 3, 4))
>>> a
array([[[ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.]],

       [[ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.],
        [ 0.,  0.,  0.,  0.]]])

NumPy 中的数组打印为单词array 后跟结构,类似于嵌入式 Python 列表。让我们创建一个类似的列表:

>>> l = [[[ 0.,  0.,  0.,  0.],
          [ 0.,  0.,  0.,  0.],
          [ 0.,  0.,  0.,  0.]],

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

>>> l
[[[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]], 
 [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]]]

这个复合列表l 的第一级正好有2 个元素,就像数组a 的第一个维度(行数)一样。这些元素中的每一个本身都是一个包含 3 个元素的列表,等于 a 的第二维(列数)。最后,最嵌套的列表每个都有 4 个元素,与a 的第三维相同(深度/颜色数)。

所以你得到了与 Matlab 中完全相同的结构(在尺寸方面),只是以另一种方式打印。

一些注意事项:

  1. Matlab 逐列存储数据(“Fortran 顺序”),而 NumPy 默认逐行存储它们(“C 顺序”)。这不会影响索引,但可能会影响性能。例如,在 Matlab 中,高效循环将在列上进行(例如 for n = 1:10 a(:, n) end),而在 NumPy 中,最好对行进行迭代(例如 for n in range(10): a[n, :] -- 注意 n 在第一个位置,而不是最后一个位置)。

  2. 如果您在 OpenCV 中使用彩色图像,请记住:

    2.1。它以 BGR 格式存储图像,而不是像大多数 Python 库那样以 RGB 格式存储图像。

    2.2。大多数函数适用于图像坐标 (x, y),这与矩阵坐标 (i, j) 是相反的。

【讨论】:

  • 是的,我从 jabaldonedo 和一些测试中了解了很多。即使后端逻辑使其更易于理解,它的显示方式也不合逻辑。我一定会考虑订单存储,很棒的提示!
  • 这实际上并非不合逻辑,只是不同而已。没有真正的方法可以在 2D 屏幕上表示 3D 阵列,因此不同的环境使用不同的方法。 Matlab 和 NumPy 两者都有其打印数组的基本原理。
  • 在阅读了这个答案并摸索之后,我觉得在“行、列、堆栈”序列中考虑 numpy 数组是不合适的。最好这样想,“第一个容器容纳第二个容器,容纳第三个容器”。
  • 显示不合逻辑,它似乎是 2 个数组,每个数组有 3 行 4 列,但这里的答案实际上是 4 个 2 行和列的堆叠数组
  • @seanysull 如果您将数据结构视为尺寸为 2、3 和 4 的框,则 2 之间的唯一区别是将参考系旋转 90 度。这并非不合逻辑,只是观点不同。
【解决方案3】:

尽管人们喜欢说“顺序与约定无关”,但当进入跨域接口、IE 从 C 排序转换为 Fortran 排序或其他一些排序方案时,这会发生故障。在那里,您的数据的精确布局以及在 numpy 中如何表示形状非常重要。

默认情况下,numpy 使用 C 排序,这意味着内存中的连续元素是存储在 rows 中的元素。您还可以执行 FORTRAN 排序(“F”),而是根据列对元素进行排序,索引连续元素。

Numpy 的形状还有它自己的显示形状的顺序。在 numpy 中,形状首先是最大步幅,即,在 3d 向量中,它将是 最小连续维度、Z 或页面、第 3 暗等...所以在执行时:

np.zeros((2,3,4)).shape

你会得到

(2,3,4)

实际上是(frames, rows, columns)。做np.zeros((2,2,3,4)).shape 将意味着(metaframs, frames, rows, columns)。当您考虑在 C 语言中创建多维数组时,这更有意义。对于 C++,创建非连续定义的 4D 数组会产生 array [ of arrays [ of arrays [ of elements ]]]。这会强制您取消引用包含所有其他数组(第 4 维)的第一个数组,然后一直保持相同(第 3、第 2、第 1 维)导致语法如下:

double element = array4d[w][z][y][x];

在 fortran 中,这个索引顺序是相反的(x 是第一个 array4d[x][y][z][w]),最连续到最不连续,在 matlab 中,它变得很奇怪。

Matlab 尝试保留数学默认排序(行、列),但也在库内部使用列专业,并且不遵循 C 中的维度排序约定。在 matlab 中,您可以这样排序:

double element = array4d[y][x][z][w];

它颠覆了所有约定并创建了奇怪的情况,您有时索引好像行排序,有时列排序(例如创建矩阵)。

实际上,Matlab 是不直观的,而不是 Numpy。

【讨论】:

    【解决方案4】:

    阅读这篇文章以获得更好的洞察力:numpy: Array shapes and reshaping arrays

    注意:NumPylayers, rows, columns 的顺序报告 3D 数组的形状。

    【讨论】:

      【解决方案5】:

      没有必要深入研究如此深入的技术,让自己被炸死。让我以最简单的方式解释它。在我们的数学学龄期,我们都学过“Sets”。只需将 3D numpy 数组视为“集合”的形成。

      x = np.zeros((2,3,4)) 
      

      简单的意思:

      2 Sets, 3 Rows per Set, 4 Columns
      

      示例:

      输入

      x = np.zeros((2,3,4))
      

      输出

      Set # 1 ---- [[[ 0.,  0.,  0.,  0.],  ---- Row 1
                     [ 0.,  0.,  0.,  0.],  ---- Row 2
                     [ 0.,  0.,  0.,  0.]], ---- Row 3 
          
      Set # 2 ----  [[ 0.,  0.,  0.,  0.],  ---- Row 1
                     [ 0.,  0.,  0.,  0.],  ---- Row 2
                     [ 0.,  0.,  0.,  0.]]] ---- Row 3
      

      解释: 看?我们有 2 组,每组 3 行和 4 列。

      注意:每当您看到两端用双括号括起来的“一组数字”时。将其视为“set”。而 3D 和 3D+ 数组总是建立在这些“集合”之上。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-12-30
        • 1970-01-01
        • 1970-01-01
        • 2021-07-17
        • 1970-01-01
        • 1970-01-01
        • 2020-11-25
        • 2021-09-18
        相关资源
        最近更新 更多