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. 这很奇怪。轴在meandrop 之间应该是一致的。需要非线性思维才能得出实际行为。 【参考方案1】:

可能最简单的方法是将其记住为 0=down1=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

Pandas 多索引 DataFrame 到 Numpy Ndarray

将 Pandas Dataframe 转换为 numpy 数组