Bagaimana iloc, ix, dan loc berbeda?

636

Adakah yang bisa menjelaskan bagaimana ketiga metode mengiris ini berbeda?
Saya telah melihat dokumen , dan saya telah melihat jawaban ini , tetapi saya masih tidak dapat menjelaskan bagaimana ketiganya berbeda. Bagi saya, mereka tampaknya dapat dipertukarkan sebagian besar, karena mereka berada di tingkat yang lebih rendah.

Misalnya, kita ingin mendapatkan lima baris pertama a DataFrame. Bagaimana bisa ketiganya bekerja?

df.loc[:5]
df.ix[:5]
df.iloc[:5]

Bisakah seseorang menyajikan tiga kasus di mana perbedaan dalam penggunaannya lebih jelas?

AZhao
sumber
7
sangat penting untuk menyebutkan skenario SettingWithCopyWarning: stackoverflow.com/questions/20625582/… dan stackoverflow.com/questions/23688307/…
Paul
9
Perhatikan bahwa ix sekarang direncanakan untuk tidak digunakan lagi: github.com/pandas-dev/pandas/issues/14218
JohnE

Jawaban:

970

Catatan: dalam versi panda 0.20.0 dan di atasnya, ixsudah usang dan penggunaan locdan ilocdianjurkan sebagai gantinya. Saya telah meninggalkan bagian dari jawaban ini yang menggambarkan ixutuh sebagai referensi untuk pengguna versi panda sebelumnya. Contoh telah ditambahkan di bawah ini yang menunjukkan alternatif untuk ix .


Pertama, inilah rekap dari tiga metode:

  • locmendapat baris (atau kolom) dengan label tertentu dari indeks.
  • ilocmendapat baris (atau kolom) pada posisi tertentu dalam indeks (sehingga hanya membutuhkan bilangan bulat).
  • ixbiasanya mencoba berperilaku seperti loctetapi kembali berperilaku seperti ilocjika label tidak ada dalam indeks.

Penting untuk mencatat beberapa seluk-beluk yang dapat membuat ixsedikit sulit untuk digunakan:

  • jika indeks adalah tipe integer, ixhanya akan menggunakan pengindeksan berbasis label dan tidak jatuh kembali ke pengindeksan berbasis posisi. Jika label tidak ada dalam indeks, kesalahan akan muncul.

  • jika indeks tidak hanya berisi bilangan bulat, maka diberikan bilangan bulat, ixakan segera menggunakan pengindeksan berbasis posisi daripada pengindeksan berbasis label. Namun jika ixdiberikan jenis lain (misalnya string), itu dapat menggunakan pengindeksan berbasis label.


Untuk mengilustrasikan perbedaan antara ketiga metode, pertimbangkan Seri berikut:

>>> s = pd.Series(np.nan, index=[49,48,47,46,45, 1, 2, 3, 4, 5])
>>> s
49   NaN
48   NaN
47   NaN
46   NaN
45   NaN
1    NaN
2    NaN
3    NaN
4    NaN
5    NaN

Kita akan melihat slicing dengan nilai integer 3.

Dalam hal ini, s.iloc[:3]kembalikan 3 baris pertama (karena memperlakukan 3 sebagai posisi) dan s.loc[:3]mengembalikan 8 baris pertama (karena memperlakukan 3 sebagai label):

>>> s.iloc[:3] # slice the first three rows
49   NaN
48   NaN
47   NaN

>>> s.loc[:3] # slice up to and including label 3
49   NaN
48   NaN
47   NaN
46   NaN
45   NaN
1    NaN
2    NaN
3    NaN

>>> s.ix[:3] # the integer is in the index so s.ix[:3] works like loc
49   NaN
48   NaN
47   NaN
46   NaN
45   NaN
1    NaN
2    NaN
3    NaN

Pemberitahuan s.ix[:3]mengembalikan Seri yang sama seperti s.loc[:3]karena mencari label terlebih dahulu daripada bekerja pada posisi (dan indeks untuk stipe integer).

Bagaimana jika kita mencoba dengan label integer yang tidak ada dalam indeks (katakanlah 6)?

Di sini s.iloc[:6]mengembalikan 6 baris pertama Seri seperti yang diharapkan. Namun, s.loc[:6]memunculkan KeyError karena 6tidak ada dalam indeks.

>>> s.iloc[:6]
49   NaN
48   NaN
47   NaN
46   NaN
45   NaN
1    NaN

>>> s.loc[:6]
KeyError: 6

>>> s.ix[:6]
KeyError: 6

Sesuai dengan seluk-beluk yang disebutkan di atas, s.ix[:6]sekarang memunculkan KeyError karena mencoba bekerja seperti loctetapi tidak dapat menemukan 6dalam indeks. Karena indeks kami bertipe integer ix, jangan kembali seperti apa iloc.

Namun, jika indeks kami adalah tipe campuran, diberi bilangan bulat ixakan berperilaku seperti ilocsegera daripada menaikkan KeyError:

>>> s2 = pd.Series(np.nan, index=['a','b','c','d','e', 1, 2, 3, 4, 5])
>>> s2.index.is_mixed() # index is mix of different types
True
>>> s2.ix[:6] # now behaves like iloc given integer
a   NaN
b   NaN
c   NaN
d   NaN
e   NaN
1   NaN

Ingatlah bahwa ixmasih dapat menerima yang bukan bilangan bulat dan berperilaku seperti loc:

>>> s2.ix[:'c'] # behaves like loc given non-integer
a   NaN
b   NaN
c   NaN

Sebagai saran umum, jika Anda hanya mengindeks menggunakan label, atau hanya mengindeks menggunakan posisi integer, tetap dengan locatau ilocuntuk menghindari hasil yang tidak terduga - cobalah untuk tidak menggunakannya ix.


Menggabungkan pengindeksan berbasis posisi dan berbasis label

Terkadang diberi DataFrame, Anda akan ingin mencampur metode pengindeksan label dan posisi untuk baris dan kolom.

Misalnya, pertimbangkan DataFrame berikut. Cara terbaik untuk mengiris baris hingga dan termasuk 'c' dan mengambil empat kolom pertama?

>>> df = pd.DataFrame(np.nan, 
                      index=list('abcde'),
                      columns=['x','y','z', 8, 9])
>>> df
    x   y   z   8   9
a NaN NaN NaN NaN NaN
b NaN NaN NaN NaN NaN
c NaN NaN NaN NaN NaN
d NaN NaN NaN NaN NaN
e NaN NaN NaN NaN NaN

Dalam versi panda sebelumnya (sebelum 0.20.0) ixmemungkinkan Anda melakukan ini dengan cukup rapi - kita dapat mengiris baris dengan label dan kolom dengan posisi (perhatikan bahwa untuk kolom, ixakan secara default untuk pengirisan berbasis posisi karena 4bukan nama kolom ):

>>> df.ix[:'c', :4]
    x   y   z   8
a NaN NaN NaN NaN
b NaN NaN NaN NaN
c NaN NaN NaN NaN

Di versi panda nanti, kita dapat mencapai hasil ini menggunakan ilocdan bantuan metode lain:

>>> df.iloc[:df.index.get_loc('c') + 1, :4]
    x   y   z   8
a NaN NaN NaN NaN
b NaN NaN NaN NaN
c NaN NaN NaN NaN

get_loc()adalah metode indeks yang berarti "dapatkan posisi label dalam indeks ini". Perhatikan bahwa karena mengiris dengan iloceksklusif dari titik akhir, kita harus menambahkan 1 ke nilai ini jika kita ingin baris 'c' juga.

Ada contoh lebih lanjut dalam dokumentasi panda di sini .

Alex Riley
sumber
12
Penjelasan hebat! Satu pertanyaan terkait yang selalu saya miliki adalah hubungan apa, jika ada, loc, iloc dan ix miliki dengan pengaturan SettingWithCopy peringatan? Ada beberapa dokumentasi tapi sejujurnya aku masih kecil bingung pandas.pydata.org/pandas-docs/stable/...
measureallthethings
3
@ mengukur semua hal:: loc, ilocdan ixmungkin masih memicu peringatan jika dirantai bersama. Menggunakan contoh DataFrame di dokumen yang ditautkan dfmi.loc[:, 'one'].loc[:, 'second']memicu peringatan seperti dfmi['one']['second']karena salinan data (bukan tampilan) mungkin dikembalikan oleh operasi pengindeksan pertama.
Alex Riley
Apa yang Anda gunakan jika Anda ingin mencari DateIndex dengan Date, atau semacamnya df.ix[date, 'Cash']?
cjm2671
@ cjm2671: keduanya locatau ixharus berfungsi dalam kasus itu. Misalnya, df.loc['2016-04-29', 'Cash']akan mengembalikan semua indeks baris dengan tanggal tertentu dari kolom 'Uang'. (Anda dapat sespesifik mungkin ketika mengambil indeks dengan string, mis. '2016-01'Akan memilih semua datetimes yang jatuh pada Januari 2016, `'2016-01-02 11' akan memilih datetimes pada 2 Januari 2016 dengan waktu 11: ??: ?? .)
Alex Riley
Jika Anda ingin memperbarui jawaban ini di beberapa titik, ada saran di sini untuk cara menggunakan loc / iloc bukan ix github.com/pandas-dev/pandas/issues/14218
JohnE
142

ilocbekerja berdasarkan positioning integer. Jadi, apa pun label baris Anda, Anda selalu dapat, mis. Mendapatkan baris pertama dengan melakukan

df.iloc[0]

atau lima baris terakhir dengan melakukan

df.iloc[-5:]

Anda juga dapat menggunakannya di kolom. Ini mengambil kolom ke-3:

df.iloc[:, 2]    # the : in the first position indicates all rows

Anda bisa menggabungkannya untuk mendapatkan persimpangan baris dan kolom:

df.iloc[:3, :3] # The upper-left 3 X 3 entries (assuming df has 3+ rows and columns)

Di sisi lain, .locgunakan indeks bernama. Mari kita menyiapkan bingkai data dengan string sebagai label baris dan kolom:

df = pd.DataFrame(index=['a', 'b', 'c'], columns=['time', 'date', 'name'])

Lalu kita bisa mendapatkan baris pertama

df.loc['a']     # equivalent to df.iloc[0]

dan dua baris 'date'kolom kedua oleh

df.loc['b':, 'date']   # equivalent to df.iloc[1:, 1]

dan seterusnya. Sekarang, mungkin perlu menunjukkan bahwa indeks baris dan kolom default untuk DataFrameadalah bilangan bulat dari 0 dan dalam kasus ini ilocdan locakan bekerja dengan cara yang sama. Inilah sebabnya tiga contoh Anda setara. Jika Anda memiliki indeks non-numerik seperti string atau datetimes, df.loc[:5] akan memunculkan kesalahan.

Anda juga dapat melakukan pengambilan kolom hanya dengan menggunakan kerangka data __getitem__:

df['time']    # equivalent to df.loc[:, 'time']

Sekarang anggaplah Anda ingin mencampur posisi dan bernama pengindeksan, yaitu pengindeksan menggunakan nama pada baris dan posisi pada kolom (untuk memperjelas, maksud saya pilih dari bingkai data kami, daripada membuat bingkai data dengan string dalam indeks baris dan bilangan bulat di indeks kolom). Di sinilah .ixmasuk:

df.ix[:2, 'time']    # the first two rows of the 'time' column

Saya pikir itu juga layak disebutkan bahwa Anda dapat melewati vektor boolean ke locmetode juga. Sebagai contoh:

 b = [True, False, True]
 df.loc[b] 

Akan mengembalikan baris 1 dan 3 df. Ini sama dengan df[b]untuk seleksi, tetapi juga dapat digunakan untuk menetapkan melalui vektor boolean:

df.loc[b, 'name'] = 'Mary', 'John'
JoeCondron
sumber
Apakah df.iloc [:,:] setara dengan semua baris dan kolom?
Alvis
Ya, seperti yang akan terjadi df.loc[:, :]. Ini dapat digunakan untuk menetapkan kembali nilai-nilai keseluruhan DataFrameatau membuat tampilan itu.
JoeCondron
hai, apakah Anda tahu mengapa loc dan iloc mengambil parameter di antara tanda kurung persegi [] dan bukan sebagai metode normal di antara tanda kurung klasik ()?
Marinir Galantin
119

Menurut pendapat saya, jawaban yang diterima membingungkan, karena menggunakan DataFrame dengan hanya nilai yang hilang. Saya juga tidak suka istilah berbasis posisi untuk .ilocdan sebagai gantinya, lebih suka lokasi integer karena jauh lebih deskriptif dan apa .ilockepanjangannya. Kata kuncinya adalah INTEGER - .ilocmembutuhkan INTEGER.

Lihat seri blog saya yang sangat terperinci tentang pemilihan subset untuk informasi lebih lanjut


.ix sudah usang dan ambigu dan tidak boleh digunakan

Karena .ixsudah usang kami hanya akan fokus pada perbedaan antara .locdan .iloc.

Sebelum kita berbicara tentang perbedaan, penting untuk memahami bahwa DataFrames memiliki label yang membantu mengidentifikasi setiap kolom dan setiap indeks. Mari kita lihat contoh DataFrame:

df = pd.DataFrame({'age':[30, 2, 12, 4, 32, 33, 69],
                   'color':['blue', 'green', 'red', 'white', 'gray', 'black', 'red'],
                   'food':['Steak', 'Lamb', 'Mango', 'Apple', 'Cheese', 'Melon', 'Beans'],
                   'height':[165, 70, 120, 80, 180, 172, 150],
                   'score':[4.6, 8.3, 9.0, 3.3, 1.8, 9.5, 2.2],
                   'state':['NY', 'TX', 'FL', 'AL', 'AK', 'TX', 'TX']
                   },
                  index=['Jane', 'Nick', 'Aaron', 'Penelope', 'Dean', 'Christina', 'Cornelia'])

masukkan deskripsi gambar di sini

Semua kata dalam huruf tebal adalah label. Label, age, color, food, height, scoredan statedigunakan untuk kolom . Label lain, Jane, Nick, Aaron, Penelope, Dean, Christina, Corneliadigunakan untuk indeks .


Cara utama untuk memilih baris tertentu dalam DataFrame adalah dengan .locdan .ilocpengindeks. Masing-masing pengindeks ini juga dapat digunakan untuk secara bersamaan memilih kolom tetapi lebih mudah untuk hanya fokus pada baris untuk saat ini. Juga, masing-masing pengindeks menggunakan seperangkat tanda kurung yang segera mengikuti nama mereka untuk membuat pilihan mereka.

.loc memilih data hanya dengan label

Pertama-tama kita akan berbicara tentang .locpengindeks yang hanya memilih data dengan indeks atau label kolom. Dalam DataFrame sampel kami, kami telah memberikan nama yang berarti sebagai nilai untuk indeks. Banyak DataFrames tidak akan memiliki nama yang berarti dan sebaliknya, default ke hanya bilangan bulat dari 0 ke n-1, di mana n adalah panjang dari DataFrame.

Ada tiga input berbeda yang dapat Anda gunakan .loc

  • Sebuah benang
  • Daftar string
  • Notasi irisan menggunakan string sebagai nilai awal dan berhenti

Memilih satu baris dengan .loc dengan sebuah string

Untuk memilih satu baris data, letakkan label indeks di dalam tanda kurung berikut .loc.

df.loc['Penelope']

Ini mengembalikan baris data sebagai Seri

age           4
color     white
food      Apple
height       80
score       3.3
state        AL
Name: Penelope, dtype: object

Memilih beberapa baris dengan .loc dengan daftar string

df.loc[['Cornelia', 'Jane', 'Dean']]

Ini mengembalikan DataFrame dengan baris dalam urutan yang ditentukan dalam daftar:

masukkan deskripsi gambar di sini

Memilih beberapa baris dengan .loc dengan notasi slice

Notasi irisan didefinisikan oleh nilai awal, berhenti dan langkah. Saat mengiris dengan label, panda menyertakan nilai stop dalam pengembalian. Berikut irisan dari Harun ke Dean, inklusif. Ukuran langkahnya tidak ditentukan secara eksplisit tetapi default ke 1.

df.loc['Aaron':'Dean']

masukkan deskripsi gambar di sini

Irisan kompleks dapat diambil dengan cara yang sama seperti daftar Python.

.iloc memilih data hanya dengan lokasi integer

Sekarang mari kita beralih ke .iloc. Setiap baris dan kolom data dalam DataFrame memiliki lokasi integer yang mendefinisikannya. Ini merupakan tambahan untuk label yang ditampilkan secara visual dalam output . Lokasi integer hanyalah jumlah baris / kolom dari atas / kiri mulai dari 0.

Ada tiga input berbeda yang dapat Anda gunakan .iloc

  • Bilangan bulat
  • Daftar bilangan bulat
  • Notasi irisan menggunakan bilangan bulat sebagai nilai awal dan berhenti

Memilih satu baris dengan .iloc dengan integer

df.iloc[4]

Ini mengembalikan baris ke-5 (lokasi integer 4) sebagai Seri

age           32
color       gray
food      Cheese
height       180
score        1.8
state         AK
Name: Dean, dtype: object

Memilih beberapa baris dengan .iloc dengan daftar bilangan bulat

df.iloc[[2, -2]]

Ini mengembalikan DataFrame dari baris ketiga dan kedua ke terakhir:

masukkan deskripsi gambar di sini

Memilih beberapa baris dengan .iloc dengan notasi slice

df.iloc[:5:3]

masukkan deskripsi gambar di sini


Pemilihan baris dan kolom secara simultan dengan .loc dan .iloc

Satu kemampuan luar biasa dari keduanya .loc/.ilocadalah kemampuan mereka untuk memilih baris dan kolom secara bersamaan. Dalam contoh di atas, semua kolom dikembalikan dari setiap pilihan. Kita dapat memilih kolom dengan tipe input yang sama seperti yang kita lakukan untuk baris. Kita hanya perlu memisahkan pemilihan baris dan kolom dengan koma .

Sebagai contoh, kita dapat memilih baris Jane, dan Dean hanya dengan tinggi kolom, skor dan status seperti ini:

df.loc[['Jane', 'Dean'], 'height':]

masukkan deskripsi gambar di sini

Ini menggunakan daftar label untuk baris dan notasi irisan untuk kolom

Kami secara alami dapat melakukan operasi serupa dengan .ilochanya menggunakan bilangan bulat.

df.iloc[[1,4], 2]
Nick      Lamb
Dean    Cheese
Name: food, dtype: object

Pilihan serentak dengan label dan lokasi integer

.ixdigunakan untuk membuat pilihan secara bersamaan dengan label dan lokasi integer yang berguna tetapi membingungkan dan ambigu pada waktu dan untungnya itu sudah usang. Jika Anda perlu membuat pilihan dengan campuran label dan lokasi integer, Anda harus membuat label pilihan atau lokasi integer Anda.

Misalnya, jika kita ingin memilih baris Nickdan Corneliabersama dengan kolom 2 dan 4, kita bisa menggunakan .locdengan mengubah bilangan bulat menjadi label dengan yang berikut:

col_names = df.columns[[2, 4]]
df.loc[['Nick', 'Cornelia'], col_names] 

Atau sebagai alternatif, ubah label indeks menjadi bilangan bulat dengan get_locmetode indeks.

labels = ['Nick', 'Cornelia']
index_ints = [df.index.get_loc(label) for label in labels]
df.iloc[index_ints, [2, 4]]

Seleksi Boolean

Pengindeks .loc juga dapat melakukan seleksi boolean. Sebagai contoh, jika kita tertarik untuk menemukan semua baris di mana usia di atas 30 dan mengembalikan hanya kolom fooddan scorekita dapat melakukan hal berikut:

df.loc[df['age'] > 30, ['food', 'score']] 

Anda dapat meniru ini dengan .iloctetapi Anda tidak bisa mengirimkannya seri boolean. Anda harus mengubah Seri boolean menjadi array numpy seperti ini:

df.iloc[(df['age'] > 30).values, [2, 4]] 

Memilih semua baris

Dimungkinkan untuk digunakan .loc/.ilochanya untuk pemilihan kolom. Anda dapat memilih semua baris dengan menggunakan titik dua seperti ini:

df.loc[:, 'color':'score':2]

masukkan deskripsi gambar di sini


Operator pengindeksan [],, dapat memilih baris dan kolom juga tetapi tidak secara bersamaan.

Kebanyakan orang akrab dengan tujuan utama operator pengindeksan DataFrame, yaitu untuk memilih kolom. Sebuah string memilih kolom tunggal sebagai Seri dan daftar string memilih beberapa kolom sebagai DataFrame.

df['food']

Jane          Steak
Nick           Lamb
Aaron         Mango
Penelope      Apple
Dean         Cheese
Christina     Melon
Cornelia      Beans
Name: food, dtype: object

Menggunakan daftar memilih banyak kolom

df[['food', 'score']]

masukkan deskripsi gambar di sini

Apa yang kurang dikenal orang adalah, ketika notasi slice digunakan, maka seleksi terjadi oleh label baris atau dengan lokasi integer. Ini sangat membingungkan dan sesuatu yang hampir tidak pernah saya gunakan tetapi berhasil.

df['Penelope':'Christina'] # slice rows by label

masukkan deskripsi gambar di sini

df[2:6:2] # slice rows by integer location

masukkan deskripsi gambar di sini

Ketertarikan .loc/.ilocuntuk memilih baris sangat disukai. Operator pengindeksan saja tidak dapat memilih baris dan kolom secara bersamaan.

df[3:5, 'color']
TypeError: unhashable type: 'slice'
Ted Petrou
sumber
6
Wow, ini adalah salah satu penjelasan yang diartikulasikan dengan sangat baik dan jernih yang pernah saya temui tentang topik pemrograman, Apa yang Anda jelaskan di bagian terakhir tentang pengindeksan normal yang berfungsi baik pada baris atau kolom adalah salah satu alasan kami memiliki loc dan iloc metode. Saya menemukan peringatan itu dalam kursus datacamp. a.) Apa yang dikembalikan df.columns dan df.index? Apakah ini daftar string? Jika itu daftar, apakah bisa mengakses dua elemen seperti ini df.columns [[2,4]] dalam daftar? b.) Dapatkah saya memanggil get_loc () di df.columns? c.) Mengapa kita perlu memanggil df ['age']> 30.nilai jika iloc.
pragun
Jawaban terbaik yang pernah saya lihat.
Maks.
Ini adalah jawaban yang sangat bagus, saya suka itu tidak mendapatkan banyak ke ix, yang sudah usang dan tidak ada gunanya untuk menyelam jauh. Terima kasih.
omabena