Ambiguitas dalam definisi "axis" Pandas Dataframe / Numpy Array

93

Saya sangat bingung tentang bagaimana sumbu python didefinisikan, dan apakah mereka merujuk ke baris atau kolom DataFrame. Perhatikan kode di bawah ini:

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

Jadi jika kita menelepon df.mean(axis=1), kita akan mendapatkan mean di seluruh baris:

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

Namun, jika kita memanggil df.drop(name, axis=1), kita sebenarnya menjatuhkan kolom , bukan baris:

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

Adakah yang bisa membantu saya memahami apa yang dimaksud dengan "sumbu" di pandas / numpy / scipy?

Catatan tambahan, DataFrame.meanmungkin saja salah didefinisikan. Dikatakan dalam dokumentasi untuk DataFrame.meanitu axis=1seharusnya berarti mean di atas kolom, bukan baris ...

hlin117
sumber
Untuk penjelasan rinci tentang alias, 'kolom' dan 'baris' / 'indeks' lihat jawaban ini di bawah .
Ted Petrou
Ini aneh. Sumbu harus konsisten melintasi meandan drop. Dibutuhkan pemikiran nonlinier untuk sampai pada perilaku yang sebenarnya.
StephenBoesch

Jawaban:

169

Mungkin yang paling sederhana adalah mengingatnya sebagai 0 = turun dan 1 = menyilang .

Ini berarti:

  • Gunakan axis=0untuk menerapkan metode di setiap kolom, atau ke label baris (indeks).
  • Gunakan axis=1untuk menerapkan metode di setiap baris, atau ke label kolom.

Berikut adalah gambar untuk memperlihatkan bagian-bagian dari DataFrame yang dirujuk setiap sumbu:

Penting juga untuk diingat bahwa Panda mengikuti penggunaan kata NumPy axis. Penggunaannya dijelaskan dalam glosarium istilah NumPy :

Sumbu ditentukan untuk larik dengan lebih dari satu dimensi. Larik 2 dimensi memiliki dua sumbu yang sesuai: yang pertama berjalan secara vertikal ke bawah melintasi baris (sumbu 0) , dan yang kedua berjalan secara horizontal melintasi kolom (sumbu 1) . [ penekanan saya ]

Jadi, tentang metode dalam pertanyaan df.mean(axis=1), tampaknya didefinisikan dengan benar. Ini mengambil mean dari entri secara horizontal di seluruh kolom , yaitu di sepanjang setiap baris individu. Di sisi lain, df.mean(axis=0)akan menjadi operasi yang bertindak secara vertikal ke bawah melintasi baris .

Demikian pula, df.drop(name, axis=1)mengacu pada tindakan pada label kolom, karena label tersebut secara intuitif melintasi sumbu horizontal. Menentukan axis=0akan membuat metode bekerja pada baris sebagai gantinya.

Alex Riley
sumber
3
Apa yang membuat saya kesulitan adalah, df.apply (..., axis = 0), tidak "menabrak" sumbu 0 (indeks), tetapi berlari di atas kolom, mengembalikan Seri yang berisi semua indeks. Petunjuknya adalah, df.apply (..., axis = 0) mengembalikan Seri sehingga ANDA dapat menerapkan operasi yang berjalan di seluruh indeks.
moritzschaefer
2
Saya pikir itu juga membantu jika Anda melihatnya df.applymirip dengan metode seperti df.sum. Misalnya, df.sum(axis=0)menjumlahkan setiap kolom DataFrame. Demikian pula, Anda dapat menulis df.apply(sum, axis=0)untuk melakukan operasi yang persis sama. Sementara operasi memang diterapkan ke setiap kolom di DataFrame, fungsi sebenarnya berjalan di sumbu 0.
Alex Riley
Ini disayangkan bahwa konvensi penamaan dan ketertiban adalah kebalikan dari R menerapkan fungsi - di R, semakin rendah MARGIN(mirip dengan axisdi panda) nilai "1" dapat disamakan dengan "baris" yang berarti fungsi diterapkan untuk setiap baris , sedangkan nilai yang lebih besar dari "2" mengacu pada "kolom" yang berarti fungsi tersebut diterapkan ke setiap kolom .
Keith Hughitt
Ini adalah bug yang merusak di panda
Kalkulus
10

Cara lain untuk menjelaskan:

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

Tentang df.drop(sumbu berarti posisi)

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

Tentang df.apply(sumbu berarti arah)

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
sumber
Tidakkah menurut kalian, pada sumbu 1 dan sejajar dengan sumbu 0 berarti sama?
Nuansa
9

Sudah ada jawaban yang benar, tapi saya beri contoh lain dengan> 2 dimensi.

Parameter axisberarti sumbu yang akan diubah .
Misalnya, ada dataframe dengan dimensi axbxc .

  • df.mean(axis=1)mengembalikan kerangka data dengan sumbu dimensi 1 xc .
  • df.drop("col4", axis=1)mengembalikan kerangka data dengan sumbu dimensi (b-1) xc .

Di sini, axis=1berarti sumbu kedua b, jadi bnilai akan berubah dalam contoh ini.

jeongmin.cha
sumber
1
Bagi saya jawaban ini lebih intuitif daripada visualisasi apa pun yang pernah saya lihat tentang topik ini. Namun, xarray lebih baik untuk array multi-dimensi daripada panda.
alys
2

Perlu diketahui secara lebih luas bahwa string alias 'index' dan 'kolom' dapat digunakan sebagai pengganti bilangan bulat 0/1. Aliasnya jauh lebih eksplisit dan membantu saya mengingat bagaimana penghitungan dilakukan. Alias ​​lain untuk 'indeks' adalah 'baris' .

Ketika axis='index'digunakan, maka perhitungan terjadi di kolom, yang membingungkan. Tapi, saya ingat mendapatkan hasil yang ukurannya sama dengan baris lainnya.

Mari kita dapatkan beberapa data di layar untuk melihat apa yang saya bicarakan:

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

Saat kita ingin mengambil mean dari semua kolom, kita gunakan axis='index'untuk mendapatkan yang berikut:

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

Hasil yang sama didapat oleh:

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

Untuk menggunakan operasi dari kiri ke kanan pada baris, gunakan axis = 'kolom'. Saya mengingatnya dengan berpikir bahwa kolom tambahan dapat ditambahkan ke DataFrame saya:

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

Hasil yang sama didapat oleh:

df.mean(axis=1)

Tambahkan baris baru dengan sumbu = 0 / indeks / baris

Mari gunakan hasil ini untuk menambahkan baris atau kolom tambahan untuk melengkapi penjelasannya. Jadi, setiap kali menggunakan sumbu = 0 / indeks / baris, ini seperti mendapatkan baris baru dari DataFrame. Mari tambahkan baris:

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

Tambahkan kolom baru dengan sumbu = 1 / kolom

Demikian pula, jika sumbu = 1 / kolom akan membuat data yang dapat dengan mudah dibuat menjadi kolomnya sendiri:

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

Tampaknya Anda dapat melihat semua alias dengan variabel privat berikut:

df._AXIS_ALIASES
{'rows': 0}

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

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

Ketika sumbu = 'baris' atau sumbu = 0, itu berarti elemen akses ke arah baris, dari atas ke bawah. Jika menerapkan jumlah di sepanjang sumbu = 0, itu akan memberi kita total dari setiap kolom.

Ketika sumbu = 'kolom' atau sumbu = 1, itu berarti elemen akses ke arah kolom, dari kiri ke kanan. Jika menerapkan penjumlahan di sepanjang sumbu = 1, kita akan mendapatkan total dari setiap baris.

Masih membingungkan! Tetapi hal di atas membuatnya sedikit lebih mudah bagi saya.

pemula
sumber
0

Saya menemukan semua jawaban lain membingungkan. Begini cara saya memikirkannya:

axis=0: bentuk hasil horizontal (baris)
axis=1: bentuk hasil vertikal (kolom)

Begitu

  • df.drop(name, axis=1): menjatuhkan kolom
  • df.mean(axis=1): menghitung kolom (hasilnya bisa ditambahkan sebagai kolom baru)
AXO
sumber