熊猫数据框/ numpy数组“轴”定义中的歧义


91

对于如何定义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应该是指各列而不是各行的均值...


有关别名,“列”“索引” /“行” 的详细说明,请参见下面的答案
泰德·彼得鲁

这太奇怪了。轴在mean和之间应保持一致drop。需要非线性思考才能得出实际行为。
javadba

Answers:


167

将其记住为0 = down1 = across可能是最简单的。

这意味着:

  • 使用axis=0的方法应用于沿着每列,或行标签(索引)。
  • 用于axis=1在每一行或列标签上应用方法。

这是一张图片,显示每个轴都引用的DataFrame部分:

记住熊猫遵循NumPy对这个词的使用也很有用axis。在NumPy的术语表中解释了用法:

为一维以上的数组定义了轴。二维数组具有两个相应的轴:第一个垂直跨行垂直向下(轴0),第二个水平跨列垂直(轴1)。[我的重点]

因此,关于问题中的方法df.mean(axis=1),似乎已正确定义。它以水平方式跨列(即沿每一行)获取条目的平均值。另一方面,df.mean(axis=0)这是跨行垂直向下作用的操作。

同样,df.drop(name, axis=1)指的是对列标签的操作,因为它们直观地越过了水平轴。指定axis=0将使该方法作用于行。


3
使我感到挣扎的是,df.apply(...,axis = 0)并未“超出”轴0(索引),而是在列上运行,重现了包含所有索引的Series。提示是df.apply(...,axis = 0)返回Series,因此您可以对整个索引应用操作。
moritzschaefer

2
我认为如果您将其df.apply视为类似于的方法,也会有所帮助df.sum。例如,df.sum(axis=0)对DataFrame的每一列求和。同样,您可以编写df.apply(sum, axis=0)以执行完全相同的操作。当操作确实施加到数据帧的每一列,实际功能流下轴线0
亚历莱利

不幸的是命名和顺序约定R的apply函数相反-在R中,较低的MARGIN(类似于axispandas)值“ 1”对应于“ rows”,这意味着该函数适用于每一行,而较大的值“ 2”是指“列”,这意味着该功能适用于每一列
基思·休吉特

它是大熊猫的破坏性虫子
微积分

10

另一种解释方式:

// 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上是相同的吗?
Nuance

9

已经有正确的答案,但我举另一个例子,说明> 2维。

该参数axis表示要更改的轴
例如,考虑存在一个尺寸为axbxc的数据

  • df.mean(axis=1)返回尺寸为ax 1 xc的数据帧。
  • df.drop("col4", axis=1)返回尺寸为ax(b-1)xc的数据

在此,axis=1第二根轴是b,因此b在这些示例中值将更改。


1
对我来说,这个答案比我在该主题上看到的任何可视化图都更直观。但是,对于多维数组,xarray比pandas更好。
艾丽斯(Alys)

2

应该更广为人知的是,可以使用字符串别名'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

添加轴= 1 /列的新列

类似地,当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'}

1

当axis ='rows'或axis = 0时,表示沿行方向(上下)访问元素。如果沿轴= 0应用总和,它将为我们提供每一列的总计。

当axis ='columns'或axis = 1时,表示在列方向上从左到右访问元素。如果沿轴= 1应用总和,我们将获得每一行的总数。

仍然令人困惑!但是以上对我来说比较容易。


0

我发现所有其他答案令人困惑。我是这样想的:

axis=0:结果的形状为水平(一行)
axis=1:结果的形状为垂直(一行)

所以

  • df.drop(name, axis=1):删除列
  • df.mean(axis=1):计算一列(结果可以添加为新列)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.