Неоднозначність у визначенні "осі" масиву даних Pandas / масиву Numpy


93

Я був дуже заплутаний щодо того, як визначаються осі 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. Потрібне нелінійне мислення, щоб дійти до фактичної поведінки.
StephenBoesch

Відповіді:


169

Мабуть, найпростіше запам'ятати це як 0 = вниз і 1 = поперек .

Це означає:

  • Використовуйте axis=0для застосування методу в кожному стовпці або до міток рядків (індекс).
  • Використовуйте, axis=1щоб застосувати метод до кожного рядка або до міток стовпців.

Ось малюнок, щоб показати частини DataFrame, на які посилається кожна вісь:

Також корисно пам’ятати, що Pandas слідкує за використанням слова NumPy axis. Використання пояснюється в глосарії термінів NumPy :

Осі визначаються для масивів, що мають більше одного виміру. Двовимірний масив має дві відповідні осі: перша проходить вертикально вниз поперек рядків (вісь 0) , а друга - горизонтально через стовпці (вісь 1) . [ мій акцент ]

Отже, щодо методу, про який йдеться df.mean(axis=1),, здається, правильно визначений. Він приймає середнє значення записів горизонтально через стовпці , тобто вздовж кожного окремого рядка. З іншого боку, df.mean(axis=0)це буде операція, що діє вертикально вниз поперек рядів .

Подібним чином, df.drop(name, axis=1)відноситься до дії на мітки стовпців, оскільки вони інтуїтивно переходять горизонтальну вісь. Вказівка axis=0змушує метод діяти замість рядків.


3
Мене змусило боротися те, що df.apply (..., ось = 0) не «перебіг» вісь 0 (індекс), а перебіг стовпці, повернувши ряди, що містять усі індекси. Підказка полягає в тому, що df.apply (..., ось = 0) повертає серію, щоб ВИ могли застосувати операцію, що працює над повним індексом.
Moritzschaefer

2
Я думаю, це також допомагає, якщо ви вважаєте df.applyподібним до такого методу, як df.sum. Наприклад, df.sum(axis=0)підсумовує кожен стовпець DataFrame. Подібним чином ви можете писати, df.apply(sum, axis=0)щоб виконати точно ту саму операцію. Хоча операція дійсно застосовується до кожного стовпця в DataFrame, фактична функція працює вниз по осі 0.
Alex Riley

Шкода, що правила іменування та порядку є протилежними функції застосування R - у R нижнє MARGIN(подібно до axisпанд) значення "1" відповідає "рядкам", що означає, що функція застосовується до кожного рядка , тоді як більше значення "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 означає те саме?
Нюанс

9

Вже є правильні відповіді, але я наводжу інший приклад із> 2 вимірами.

Параметр axisозначає вісь, яку потрібно змінити .
Наприклад, розглянемо, що існує фрейм даних із розмірністю axbxc .

  • df.mean(axis=1)повертає фрейм даних із розміром осі 1 xc .
  • df.drop("col4", axis=1)повертає фрейм даних із розмірністю ax (b-1) xc .

Тут axis=1означає другу вісь, яка є b, тому bзначення буде змінено в цих прикладах.


1
Ця відповідь для мене більш інтуїтивна, ніж будь-яка візуалізація, яку я бачив на цю тему. Однак xarray кращий для багатовимірних масивів, ніж панди.
alys

2

Має бути більш широко відомим, що псевдоніми рядків "індекс" і "стовпці" можна використовувати замість цілих чисел 0/1. Псевдоніми набагато чіткіші і допомагають мені згадати, як відбуваються розрахунки. Іншим псевдонімом для "index" є "рядки" .

Коли 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')

Щоб отримати операцію зліва направо на рядках, використовуйте ось = 'стовпці'. Я пам’ятаю це, думаючи, що до мого 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)

Додайте новий рядок з віссю = 0 / індекс / рядки

Давайте використаємо ці результати, щоб додати додаткові рядки або стовпці для завершення пояснення. Отже, щоразу, коли використовується вісь = 0 / індекс / рядки, це все одно, що отримати новий рядок 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 / стовпці

Подібним чином, коли вісь = 1 / стовпці, вона створюватиме дані, які можна легко перетворити у власний стовпець:

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

Коли вісь = 'рядки' або вісь = 0, це означає елементи доступу у напрямку рядків, вгору вниз. Якщо застосовувати суму вздовж осі = 0, це дасть нам підсумки кожного стовпця.

Коли вісь = 'стовпці' або вісь = 1, це означає елементи доступу у напрямку стовпців, зліва направо. Якщо застосувати суму по осі = 1, ми отримаємо підсумки кожного рядка.

Все ще бентежить! Але вищесказане трохи полегшує мене.


0

Усі інші відповіді мене бентежать. Ось як я про це думаю:

axis=0: форма результату горизонтальна (рядок)
axis=1: форма результату вертикальна (стовпець)

Тому

  • df.drop(name, axis=1): опускає стовпець
  • df.mean(axis=1): обчислює стовпець (результат можна додати як новий стовпець)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.