Ambiguïté dans la définition de "l'axe" de la trame de données Pandas / tableau Numpy

91

J'ai été très confus sur la façon dont les axes python sont définis et s'ils font référence aux lignes ou aux colonnes d'un DataFrame. Considérez le code ci-dessous:

>>> 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

Donc, si nous appelons df.mean(axis=1), nous obtiendrons une moyenne sur les lignes:

>>> df.mean(axis=1)
0    1
1    2
2    3

Cependant, si nous appelons df.drop(name, axis=1), nous supprimons en fait une colonne , pas une ligne:

>>> df.drop("col4", axis=1)
   col1  col2  col3
0     1     1     1
1     2     2     2
2     3     3     3

Quelqu'un peut-il m'aider à comprendre ce que signifie un "axe" dans pandas / numpy / scipy?

Une note latérale, DataFrame.meanpourrait être mal définie. Cela dit dans la documentation que DataFrame.meancela axis=1est censé signifier une moyenne sur les colonnes, pas sur les lignes ...

hlin117
la source
Pour une explication détaillée des alias, «colonnes» et «index» / «lignes», voir cette réponse ci-dessous .
Ted Petrou
C'est juste bizarre. L'axe doit être cohérent entre le meanet le drop. Il faut une réflexion non linéaire pour arriver au comportement réel.
StephenBoesch

Réponses:

167

Il est peut-être plus simple de s'en souvenir comme étant 0 = bas et 1 = transversal .

Ça signifie:

  • À utiliser axis=0pour appliquer une méthode en bas de chaque colonne ou aux étiquettes de ligne (l'index).
  • Utilisez axis=1pour appliquer une méthode à chaque ligne ou aux étiquettes de colonne.

Voici une image pour montrer les parties d'un DataFrame auxquelles chaque axe fait référence:

Il est également utile de se rappeler que Pandas suit l'utilisation du mot par NumPy axis. L'utilisation est expliquée dans le glossaire de NumPy :

Les axes sont définis pour les tableaux avec plusieurs dimensions. Un tableau à deux dimensions a deux axes correspondants: le premier s'étendant verticalement vers le bas sur les lignes (axe 0) et le second horizontalement sur les colonnes (axe 1) . [ mon emphase ]

Donc, concernant la méthode dans la question df.mean(axis=1),, semble être correctement définie. Il prend la moyenne des entrées horizontalement sur les colonnes , c'est-à-dire le long de chaque ligne individuelle. D'autre part, df.mean(axis=0)serait une opération agissant verticalement vers le bas à travers les rangées .

De même, df.drop(name, axis=1)fait référence à une action sur les étiquettes de colonne, car elles traversent intuitivement l'axe horizontal. La spécification axis=0ferait plutôt agir la méthode sur les lignes.

Alex Riley
la source
3
Ce qui m'a fait mal, c'est que df.apply (..., axis = 0), n'a pas "dépassé" l'axe 0 (l'index), mais a parcouru les colonnes, returing Series contenant tous les index. L'indice est que df.apply (..., axis = 0) renvoie Series afin que VOUS puissiez appliquer un fonctionnement en cours d'exécution sur l'index complet.
moritzschaefer
2
Je pense que cela aide également si vous considérez df.applycomme similaire à une méthode telle que df.sum. Par exemple, df.sum(axis=0)additionne chaque colonne du DataFrame. De même, vous pouvez écrire df.apply(sum, axis=0)pour faire exactement la même opération. Alors que l'opération est effectivement appliquée à chaque colonne dans le DataFrame, la fonction réelle descend l'axe 0.
Alex Riley
Il est malheureux que les conventions de dénomination et d'ordre soient à l' opposé de la fonction apply de R - dans R, la valeur inférieure MARGIN(similaire à celle des axispandas) de "1" correspond à "lignes", ce qui signifie que la fonction est appliquée à chaque ligne , tandis que le une valeur plus élevée de «2» fait référence aux «colonnes», ce qui signifie que la fonction est appliquée à chaque colonne .
Keith Hughitt
c'est un bug destructeur chez les pandas
Calcul
10

Une autre façon d'expliquer:

// 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

À propos df.drop(l'axe signifie la position)

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

À propos df.apply(axe signifie direction)

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
o0omycomputero0o
la source
Ne pensez-vous pas, sur l'axe 1 et parallèle à l'axe 0, la même signification?
Nuance
9

Il y a déjà des réponses correctes, mais je vous donne un autre exemple avec> 2 dimensions.

Le paramètre axissignifie l' axe à modifier .
Par exemple, considérez qu'il existe un dataframe avec la dimension axbxc .

  • df.mean(axis=1)renvoie une trame de données avec dimenstion ax 1 xc .
  • df.drop("col4", axis=1)renvoie une trame de données avec la dimension ax (b-1) xc .

Ici, axis=1signifie le deuxième axe qui est b, donc la bvaleur sera modifiée dans ces exemples.

jeongmin.cha
la source
1
Cette réponse m'est plus intuitive que n'importe quelle visualisation que j'ai vue sur ce sujet. Cependant, xarray est meilleur pour les tableaux multidimensionnels que pour les pandas.
alys
2

Il devrait être plus largement connu que les alias de chaîne «index» et «colonnes» peuvent être utilisés à la place des entiers 0/1. Les alias sont beaucoup plus explicites et m'aident à me rappeler comment les calculs se déroulent. Un autre alias pour «index» est «lignes» .

Quand axis='index'est utilisé, les calculs se déroulent dans les colonnes, ce qui est déroutant. Mais je m'en souviens comme obtenant un résultat de la même taille qu'une autre ligne.

Faisons apparaître quelques données à l'écran pour voir de quoi je parle:

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

Lorsque nous voulons prendre la moyenne de toutes les colonnes, nous utilisons axis='index'pour obtenir ce qui suit:

df.mean(axis='index')
a    0.562664
b    0.478956
c    0.410046
d    0.546366
dtype: float64

Le même résultat serait obtenu par:

df.mean() # default is axis=0
df.mean(axis=0)
df.mean(axis='rows')

Pour obtenir une opération de gauche à droite sur les lignes, utilisez axis = 'columns'. Je m'en souviens en pensant qu'une colonne supplémentaire peut être ajoutée à mon 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

Le même résultat serait obtenu par:

df.mean(axis=1)

Ajouter une nouvelle ligne avec axis = 0 / index / rows

Utilisons ces résultats pour ajouter des lignes ou des colonnes supplémentaires pour compléter l'explication. Ainsi, chaque fois que vous utilisez axis = 0 / index / rows, c'est comme obtenir une nouvelle ligne du DataFrame. Ajoutons une ligne:

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

Ajouter une nouvelle colonne avec axe = 1 / colonnes

De même, lorsque axis = 1 / columns, il créera des données qui peuvent être facilement converties dans sa propre colonne:

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

Il semble que vous puissiez voir tous les alias avec les variables privées suivantes:

df._AXIS_ALIASES
{'rows': 0}

df._AXIS_NUMBERS
{'columns': 1, 'index': 0}

df._AXIS_NAMES
{0: 'index', 1: 'columns'}
Ted Petrou
la source
1

Lorsque axis = 'rows' ou axis = 0, cela signifie accéder aux éléments dans le sens des lignes, de haut en bas. Si vous appliquez la somme le long de l'axe = 0, cela nous donnera les totaux de chaque colonne.

Lorsque axis = 'colonnes' ou axis = 1, cela signifie accéder aux éléments dans le sens des colonnes, de gauche à droite. Si vous appliquez la somme le long de l'axe = 1, nous obtiendrons les totaux de chaque ligne.

Toujours déroutant! Mais ce qui précède me facilite un peu la tâche.

débutant
la source
0

Je trouve toutes les autres réponses déroutantes. Voici comment j'y pense:

axis=0: la forme du résultat est horizontale (une ligne)
axis=1: la forme du résultat est verticale (une colonne)

Donc

  • df.drop(name, axis=1): supprime une colonne
  • df.mean(axis=1): calcule une colonne (le résultat peut être ajouté en tant que nouvelle colonne)
AXO
la source