axis
本文最后更新于4 天前,其中的信息可能已经过时,如有错误请发送邮件到184874483@qq.com
import numpy as np

N, M, P = map(int, input().split())

arr1 = [list(map(int, input().split())) for _ in range(N)]
arr2 = [list(map(int, input().split())) for _ in range(M)]

arr1 = np.array(arr1)
arr2 = np.array(arr2)

print(np.concatenate((arr1, arr2), axis=0))

axis 这个参数到底是什么意思

你现在可以先把 axis 暂时理解成一句最实用的话:

axis 决定你“沿着哪一个方向去操作数组”。

numpy.concatenate() 里面,axis 的意思就是:

你要沿着哪一个轴,把多个数组接起来。


先看你给的这两个数组

array_1 = numpy.array([[1,2,3],[0,0,0]])
array_2 = numpy.array([[0,0,0],[7,8,9]])

把它们写整齐一点,就是:

array_1 =
[[1 2 3]
 [0 0 0]]

array_2 =
[[0 0 0]
 [7 8 9]]

这两个数组的形状都是:

(2, 3)

表示:

  • 2 行
  • 3 列

二维数组里,axis=0axis=1 怎么理解

对于二维数组,你可以先这样记:

  • axis=0:按上下方向处理,也就是“行的方向”
  • axis=1:按左右方向处理,也就是“列的方向”

你也可以把它记成:

  • axis=0:往下堆
  • axis=1:往右拼

这是最适合初学者的记法。


为什么你这里 axis=1 可以成功

你的代码是:

print(numpy.concatenate((array_1, array_2), axis=1))

这里的 axis=1 表示:

把两个数组按列方向拼接,也就是左右拼接。

所以效果相当于:

[[1 2 3]    +    [0 0 0]
 [0 0 0]]        [7 8 9]]

左右拼起来以后,就是:

[[1 2 3 0 0 0]
 [0 0 0 7 8 9]]

所以输出结果是:

[[1 2 3 0 0 0]
 [0 0 0 7 8 9]]

它为什么能成功,核心原因是什么

因为:

你使用的是 axis=1

也就是左右拼接。

那么左右拼接时,要求是什么?

要求是:

行数必须一样。

因为你是一行对一行地往右接。

而你的两个数组:

  • array_1.shape = (2, 3)
  • array_2.shape = (2, 3)

它们的行数都是 2,完全一致。

所以可以成功拼接。


这里最容易混淆的一点

很多人会以为:

axis=1 是不是要求第 1 维必须相同?”

这个想法不够直观,初学时很容易绕晕。

你现在先用更直白的方式理解:

如果是 axis=1,说明你要左右拼接

那么左右拼接时:

  • 行数必须相同
  • 列数可以增加

你这里刚好满足这一点,所以成功。

拼接后:

  • 原来每个数组 2 行 3 列
  • 左右拼接后变成 2 行 6 列

所以结果形状是:

(2, 6)

如果改成 axis=0 会发生什么

如果你写:

print(numpy.concatenate((array_1, array_2), axis=0))

那就变成上下拼接。

相当于:

[[1 2 3]
 [0 0 0]]

[[0 0 0]
 [7 8 9]]

上下接起来后就是:

[[1 2 3]
 [0 0 0]
 [0 0 0]
 [7 8 9]]

这时结果形状变成:

(4, 3)

因为:

  • 行数变多了:2 + 2 = 4
  • 列数不变:还是 3

所以 axis 到底该怎么判断

你以后看到 concatenate,直接先问自己:

我要的是“上下接”,还是“左右接”?

如果是:

上下接

就写:

axis=0

要求:

列数相同

左右接

就写:

axis=1

要求:

行数相同


用你这道题和你上一道题对比一下,就会特别清楚

你上一道题

前一个数组形状是:

(4, 2)

后一个数组形状是:

(3, 2)

你当时写了:

axis=1

也就是左右拼接。

但左右拼接要求行数相同。

可是:

  • 一个 4 行
  • 一个 3 行

行数不同,所以报错。


这一次这道题

两个数组都是:

(2, 3)

你写的是:

axis=1

左右拼接要求行数相同。

这里两个数组都是 2 行,所以成功。


再进一步:axis 本质上是“维度编号”

如果你想稍微更正式一点理解:

一个二维数组的形状写成:

(行数, 列数)

比如 (2, 3)

  • 第 0 维大小是 2,也就是 2 行
  • 第 1 维大小是 3,也就是 3 列

所以:

  • axis=0:沿着第 0 维方向操作
  • axis=1:沿着第 1 维方向操作

但是对于初学者来说,这个说法不如“上下接 / 左右接”好记。

所以你现阶段优先记住这个就够了:

  • axis=0:上下拼
  • axis=1:左右拼

一张非常实用的小表

写法直观理解结果变化需要满足的条件
axis=0上下拼接行数增加列数相同
axis=1左右拼接列数增加行数相同

这个表你后面做题时会非常有用。


本题小结

你这段代码之所以能成功:

print(numpy.concatenate((array_1, array_2), axis=1))

原因就是:

  1. axis=1 表示左右拼接
  2. 左右拼接要求两个数组的行数相同
  3. array_1array_2 都是 2 行
  4. 所以可以成功拼接
  5. 拼接后结果从 (2, 3) 变成 (2, 6)

最终结果是:

[[1 2 3 0 0 0]
 [0 0 0 7 8 9]]

给你一个非常小的练习

你自己判断一下下面这两个能不能拼:

a.shape = (3, 2)
b.shape = (3, 4)

请你试着回答:

1. 用 axis=0 能不能拼?

2. 用 axis=1 能不能拼?

3. 如果能拼,结果形状是什么?

提示:

  • axis=0 看列数
  • axis=1 看行数

为什么叫 axis=0axis=1,而不是直接写成 rowcol

这是一个非常好的问题。很多初学者第一次接触 NumPy 的时候,都会觉得这里有点别扭:

“明明二维数组就是行和列,为什么不直接写 rowcol,非要写成 axis=0axis=1 呢?”

这其实不是 NumPy 故意绕,而是因为它面对的对象不只是二维表格,而是更一般的 多维数组。一旦你把这个背景想清楚,axis 这个名字就会变得很自然。


先说结论:rowcol 只适合二维,axis 适合任意维度

如果一个数组永远只有二维,那么用 rowcol 确实很直观:

  • row 表示行
  • col 表示列

但是 NumPy 里的数组,不一定只有二维。

它可能是:

  • 一维数组
  • 二维数组
  • 三维数组
  • 四维数组
  • 更多维数组

这时候,如果还用 rowcol,就会立刻出问题。

因为:

  • 一维数组没有“行列”这种说法
  • 三维数组不止“行列”两个方向
  • 更高维数组更不可能只靠 rowcol 表达清楚

所以 NumPy 需要一个更通用的概念,这个概念就是:

第 0 轴、第 1 轴、第 2 轴……

也就是 axis=0axis=1axis=2


axis 本质上是什么意思

你可以把 axis 理解成:

数组的某一个方向,或者某一个维度编号。

比如一个数组的形状是:

(2, 3)

这表示它有两个维度:

  • 第 0 维大小是 2
  • 第 1 维大小是 3

NumPy 就把这两个维度分别编号为:

  • axis=0
  • axis=1

所以,axis 其实不是“行”或者“列”本身,它更像是在说:

“我要针对第几个维度来做操作。”


为什么不用 rowcol

原因一:一维数组根本没有 row 和 col

比如:

a = numpy.array([10, 20, 30])

它的形状是:

(3,)

这是一个一维数组。

这时候你说它有“行”吗?不太准确。
你说它有“列”吗?也不准确。

但你可以说:

  • 它只有一个轴
  • 这个轴就是 axis=0

所以在一维数组里,axis=0 仍然是一个统一、自然的说法。


原因二:三维数组已经不止行和列了

比如一个三维数组:

a.shape = (2, 3, 4)

这表示它有 3 个维度。

这时候你再说:

  • row
  • col

就不够用了。

因为第三个方向叫什么?

你总不能继续发明:

  • row
  • col
  • depth

那四维呢?五维呢?

名字会越来越乱。

而 NumPy 的做法很统一:

  • 第一个方向:axis=0
  • 第二个方向:axis=1
  • 第三个方向:axis=2
  • 第四个方向:axis=3

这样不管几维,都能描述。

这就是为什么数学和编程里更喜欢用“维度编号”而不是“行列”这种只适合二维的名字。


原因三:很多函数本来就不是“按行/按列”那么简单

比如 sum()max()mean()argmax() 这些函数,都有 axis 参数。

如果 NumPy 写成:

sum(row=?)
sum(col=?)

那一维怎么办?三维怎么办?四维怎么办?

它根本不统一。

而用 axis 就很统一:

numpy.sum(a, axis=0)
numpy.sum(a, axis=1)
numpy.sum(a, axis=2)

无论数组几维,这套写法都成立。

所以你可以把 axis 看成 NumPy 的“统一语言”。


在二维数组里,为什么 axis=0 看起来像“行方向”?

这也是一个特别容易让人绕进去的地方。

先看一个二维数组:

a = numpy.array([
    [1, 2, 3],
    [4, 5, 6]
])

它的形状是:

(2, 3)

这表示:

  • 第 0 维大小是 2,也就是有 2 行
  • 第 1 维大小是 3,也就是有 3 列

所以这里:

  • axis=0 对应的是“行这一维”
  • axis=1 对应的是“列这一维”

但是要注意:

“axis=0 是行这一维”
不等于
“axis=0 就是横着的一行”

它说的是“第 0 个维度”,不是说“第 0 行”。

这个区别很重要。


为什么有时候会觉得 axis=0 是“上下”,有时候又像是“按列”?

这是初学者最常见的困惑之一。

原因是:

axis 在不同函数里,表示的不是完全同一层直觉。

例如:

concatenate()

axis=0 表示沿着第 0 轴拼接。

对于二维数组来说,你会直观地感觉成:

上下拼接

因为行数增加了。


sum()

如果你写:

numpy.sum(a, axis=0)

你会发现结果像是在“按列求和”。

比如:

a = numpy.array([
    [1, 2, 3],
    [4, 5, 6]
])

print(numpy.sum(a, axis=0))

结果是:

[5 7 9]

这是把每一列加起来了。

于是很多人就懵了:

“不是说 axis=0 是行吗?为什么这里变成按列了?”

其实并不矛盾。

因为在 sum(axis=0) 里,意思是:

沿着第 0 轴去压缩、去合并。

第 0 轴是“行这一维”,你把“行这一维”压掉之后,剩下的自然就是每一列的结果。

所以:

  • concatenate(axis=0) 中,表示沿第 0 维去扩展
  • sum(axis=0) 中,表示沿第 0 维去汇总

函数动作不同,你看到的直观效果也不同。

但底层逻辑其实是一致的:

都是针对第 0 轴进行操作。


所以 axis 最准确的理解方式是什么

如果你想建立更稳的理解,不要死记:

  • axis=0 = 行
  • axis=1 = 列

因为这个记法只在二维里部分好用,而且一到别的函数就容易混乱。

更稳的理解应该是:

axis 表示“第几个维度”

然后再结合函数去看:

  • 是沿这个维度拼接
  • 还是沿这个维度求和
  • 还是沿这个维度找最大值
  • 还是沿这个维度重排

这样理解会更通用。


一个类比:把数组想成一个盒子

你可以把数组想成一个有多个方向的盒子。

二维数组像一张表,有两个方向:

  • 上下方向
  • 左右方向

三维数组像很多张表叠起来,就有三个方向:

  • 第一个方向
  • 第二个方向
  • 第三个方向

NumPy 不关心你把它叫“行”“列”“深度”还是别的名字。

它只关心:

  • 第 0 个方向
  • 第 1 个方向
  • 第 2 个方向

这就像坐标轴一样:

  • x 轴
  • y 轴
  • z 轴

你不会问“为什么不用左和右来命名 x 轴”,因为坐标轴本来就是统一抽象。

NumPy 的 axis 也是类似的思路。


你现阶段最该怎么记

对于初学阶段,我建议你分两层记忆。

第一层:做题时的直观记法

在二维数组里先记:

  • axis=0:和“上下”有关
  • axis=1:和“左右”有关

这个记法最适合你现在做 concatenate()sum()reshape() 相关的基础题。


第二层:更本质的理解

同时再补上一个更底层的认识:

  • axis=0 是第 0 个维度
  • axis=1 是第 1 个维度
  • axis=2 是第 2 个维度

这样以后你学到三维数组、图像数组、深度学习张量时,就不会卡住。


一张对比表:为什么不用 row/col

写法适用范围优点缺点
row / col主要适合二维直观不能推广到一维、三维、更多维
axis=0 / axis=1 / axis=2适合任意维数组统一、通用、可扩展初学时不如行列直观

所以不是 row/col 不好,而是它的适用范围太窄。
NumPy 作为一个处理通用多维数组的库,必须采用更通用的表达方式。


回到你最关心的一点:为什么 NumPy 要这样设计

因为 NumPy 不是“专门处理表格”的库,而是“处理多维数组”的库。

只要它要处理的是多维数组,就不能把接口设计死在“行和列”上。

所以它选择了更抽象、但也更强大的方式:

axis 表示维度编号。

这就是为什么你会看到:

axis=0
axis=1
axis=2

而不是:

row
col

本节小结

“为什么叫 axis=0axis=1,而不是 rowcol?”
最核心的答案就是一句话:

因为 rowcol 只适合二维数组,而 NumPy 处理的是任意维度的数组,所以必须用更通用的 axis

你现在可以这样记:

  1. axis 本质上是“第几个维度”
  2. 二维里它可以暂时对应成“行方向 / 列方向”
  3. 但 NumPy 之所以不用 row/col,是为了适配一维、三维、更多维数组
  4. 所以 axis 是一个更抽象,但更统一的设计

小练习

先不写代码,只思考下面这个问题:

a.shape = (2, 3, 4)

请你试着回答:

1. 这个数组一共有几个轴?

2. 分别是哪几个 axis

3. 为什么这时候再用 rowcol 就不够了?

提示:

  • shape 里有几个数字,就有几个轴
  • 轴从 0 开始编号,不是从 1 开始

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇