Pandas Dataframe / Numpy Array“轴”定义中的歧义
Posted
技术标签:
【中文标题】Pandas Dataframe / Numpy Array“轴”定义中的歧义【英文标题】:Ambiguity in Pandas Dataframe / Numpy Array "axis" definition 【发布时间】:2014-11-04 13:32:37 【问题描述】:我一直很困惑 python 轴是如何定义的,以及它们是指 DataFrame 的行还是列。考虑下面的代码:
>>> df = pd.DataFrame([[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]], columns=["col1", "col2", "col3", "col4"])
>>> df
col1 col2 col3 col4
0 1 1 1 1
1 2 2 2 2
2 3 3 3 3
因此,如果我们调用 df.mean(axis=1)
,我们将得到各行的平均值:
>>> df.mean(axis=1)
0 1
1 2
2 3
但是,如果我们调用df.drop(name, axis=1)
,我们实际上删除一列,而不是一行:
>>> df.drop("col4", axis=1)
col1 col2 col3
0 1 1 1
1 2 2 2
2 3 3 3
谁能帮我理解 pandas/numpy/scipy 中的“轴”是什么意思?
附注,DataFrame.mean
可能定义错误。它在DataFrame.mean
的文档中说,axis=1
应该表示列的平均值,而不是行的平均值......
【问题讨论】:
有关别名的详细说明,'columns' 和 'index'/'rows' see this answer below. 这很奇怪。轴在mean
和drop
之间应该是一致的。需要非线性思维才能得出实际行为。
【参考方案1】:
可能最简单的方法是将其记住为 0=down 和 1=across。
这意味着:
使用axis=0
将方法应用于每一列或行标签(索引)。
使用axis=1
将方法应用于每一行或列标签。
这是一张显示每个轴所指的 DataFrame 部分的图片:
记住 Pandas 遵循 NumPy 使用 axis
这个词也很有用。用法在 NumPy 的glossary of terms 中有说明:
轴是为一维以上的数组定义的。二维数组有两个对应的轴:第一个轴垂直向下跨行(轴 0),第二个轴水平跨列(轴 1)。 [我的重点]
因此,关于问题中的方法df.mean(axis=1)
,似乎定义正确。它采用横向跨列条目的平均值,即沿每个单独的行。另一方面,df.mean(axis=0)
将是一个垂直向下跨行的操作。
同样,df.drop(name, axis=1)
指的是对列标签的操作,因为它们直观地穿过水平轴。指定 axis=0
将使该方法改为作用于行。
【讨论】:
让我苦苦挣扎的是,df.apply(..., axis=0) 没有“越过”轴 0(索引),而是越过列,返回 Series包含所有索引。线索是, df.apply(..., axis=0) 返回系列,因此您可以在整个索引上应用操作。 我认为如果您将df.apply
视为类似于df.sum
等方法,这也会有所帮助。例如,df.sum(axis=0)
对 DataFrame 的每一列求和。同样,您可以编写df.apply(sum, axis=0)
来执行完全相同的操作。虽然该操作确实应用于 DataFrame 中的每一列,但实际函数沿轴 0 运行。
不幸的是,命名和顺序约定与R的apply function的相反——在R中,较低的MARGIN
(类似于pandas中的axis
) “1”的值对应于“行”,这意味着该函数应用于每一行,而“2”的较大值对应于“列”,这意味着该函数应用于每列.
它是 pandas 中的破坏性错误【参考方案2】:
已经有正确的答案,但我给你另一个> 2维的例子。
参数axis
表示要改变的轴。
例如,假设有一个维度为 a x b x c 的数据框。
df.mean(axis=1)
返回一个尺寸为 a x 1 x c 的数据框。
df.drop("col4", axis=1)
返回一个维度为 a x (b-1) x c 的数据框。
这里,axis=1
表示第二个轴,即b
,因此在这些示例中b
的值将被更改。
【讨论】:
这个答案对我来说比我在这个主题上看到的任何可视化都更直观。但是,对于多维数组,xarray 比 pandas 更好。 最佳答案。另外,3d不需要带,2d数据框也可以这样解释。【参考方案3】:另一种解释方式:
// Not realistic but ideal for understanding the axis parameter
df = pd.DataFrame([[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]],
columns=["idx1", "idx2", "idx3", "idx4"],
index=["idx1", "idx2", "idx3"]
)
---------------------------------------1
| idx1 idx2 idx3 idx4
| idx1 1 1 1 1
| idx2 2 2 2 2
| idx3 3 3 3 3
0
关于df.drop
(轴表示位置)
A: I wanna remove idx3.
B: **Which one**? // typing while waiting response: df.drop("idx3",
A: The one which is on axis 1
B: OK then it is >> df.drop("idx3", axis=1)
// Result
---------------------------------------1
| idx1 idx2 idx4
| idx1 1 1 1
| idx2 2 2 2
| idx3 3 3 3
0
关于df.apply
(轴表示方向)
A: I wanna apply sum.
B: Which direction? // typing while waiting response: df.apply(lambda x: x.sum(),
A: The one which is on *parallel to axis 0*
B: OK then it is >> df.apply(lambda x: x.sum(), axis=0)
// Result
idx1 6
idx2 6
idx3 6
idx4 6
【讨论】:
你不觉得,在轴 1 上和平行于轴 0 的意思是一样的吗?【参考方案4】:应该更广为人知的是,字符串别名 'index' 和 'columns' 可以用来代替整数 0/1。别名更加明确,帮助我记住计算是如何发生的。 'index' 的另一个别名是 'rows'。
当使用axis='index'
时,计算会沿列向下进行,这会造成混淆。但是,我记得它得到的结果与另一行的大小相同。
让我们在屏幕上获取一些数据,看看我在说什么:
df = pd.DataFrame(np.random.rand(10, 4), columns=list('abcd'))
a b c d
0 0.990730 0.567822 0.318174 0.122410
1 0.144962 0.718574 0.580569 0.582278
2 0.477151 0.907692 0.186276 0.342724
3 0.561043 0.122771 0.206819 0.904330
4 0.427413 0.186807 0.870504 0.878632
5 0.795392 0.658958 0.666026 0.262191
6 0.831404 0.011082 0.299811 0.906880
7 0.749729 0.564900 0.181627 0.211961
8 0.528308 0.394107 0.734904 0.961356
9 0.120508 0.656848 0.055749 0.290897
当我们想取所有列的平均值时,我们使用axis='index'
得到以下结果:
df.mean(axis='index')
a 0.562664
b 0.478956
c 0.410046
d 0.546366
dtype: float64
同样的结果会得到:
df.mean() # default is axis=0
df.mean(axis=0)
df.mean(axis='rows')
要在行上使用从左到右的操作,请使用axis='columns'。我记得可能会在我的 DataFrame 中添加一个额外的列:
df.mean(axis='columns')
0 0.499784
1 0.506596
2 0.478461
3 0.448741
4 0.590839
5 0.595642
6 0.512294
7 0.427054
8 0.654669
9 0.281000
dtype: float64
同样的结果会得到:
df.mean(axis=1)
添加一个axis=0/index/rows的新行
让我们使用这些结果添加额外的行或列来完成解释。因此,每当使用axis = 0/index/rows 时,就像获取DataFrame 的新行一样。让我们添加一行:
df.append(df.mean(axis='rows'), ignore_index=True)
a b c d
0 0.990730 0.567822 0.318174 0.122410
1 0.144962 0.718574 0.580569 0.582278
2 0.477151 0.907692 0.186276 0.342724
3 0.561043 0.122771 0.206819 0.904330
4 0.427413 0.186807 0.870504 0.878632
5 0.795392 0.658958 0.666026 0.262191
6 0.831404 0.011082 0.299811 0.906880
7 0.749729 0.564900 0.181627 0.211961
8 0.528308 0.394107 0.734904 0.961356
9 0.120508 0.656848 0.055749 0.290897
10 0.562664 0.478956 0.410046 0.546366
添加一个axis=1/columns的新列
同样,当axis=1/columns 时,它会创建可以轻松制作成自己的列的数据:
df.assign(e=df.mean(axis='columns'))
a b c d e
0 0.990730 0.567822 0.318174 0.122410 0.499784
1 0.144962 0.718574 0.580569 0.582278 0.506596
2 0.477151 0.907692 0.186276 0.342724 0.478461
3 0.561043 0.122771 0.206819 0.904330 0.448741
4 0.427413 0.186807 0.870504 0.878632 0.590839
5 0.795392 0.658958 0.666026 0.262191 0.595642
6 0.831404 0.011082 0.299811 0.906880 0.512294
7 0.749729 0.564900 0.181627 0.211961 0.427054
8 0.528308 0.394107 0.734904 0.961356 0.654669
9 0.120508 0.656848 0.055749 0.290897 0.281000
您似乎可以看到所有具有以下私有变量的别名:
df._AXIS_ALIASES
'rows': 0
df._AXIS_NUMBERS
'columns': 1, 'index': 0
df._AXIS_NAMES
0: 'index', 1: 'columns'
【讨论】:
很高兴知道第一个轴编号有别名,尽管它们更明确,但它们并不经常使用。谁能想象在学校被告知“这是一张表,尝试沿轴 0 计算总和”而不是“尝试按列求总和”(不幸的是,在 pandas 的情况下,沿“索引”)。【参考方案5】:当axis='rows'或axis=0时,表示按行的方向访问元素,从上到下。如果沿轴 = 0 应用总和,它将为我们提供每列的总数。
当axis='columns'或axis=1时,表示按列的方向访问元素,从左到右。如果沿axis = 1应用sum,我们将得到每一行的总数。
仍然令人困惑!但是上面的内容对我来说更容易一些。
【讨论】:
【参考方案6】:我记住了维度的变化,如果axis=0,行变化,列不变,如果axis=1,列变化,行不变。
【讨论】:
以上是关于Pandas Dataframe / Numpy Array“轴”定义中的歧义的主要内容,如果未能解决你的问题,请参考以下文章
pandas将dataframe数据转化为numpy数据(extracting values of a dataframe as a numpy array data)
将 Pandas 系列的二维 numpy 数组转换为一维 numpy 数组列的 Pandas DataFrame
将 numpy.array 存储在 Pandas.DataFrame 的单元格中
numpy.ndarray 与 pandas.DataFrame