DataLens

loc vs iloc

Pilih baris dan kolom secara presisi berdasarkan label dengan .loc atau berdasarkan posisi dengan .iloc, dan ubah nilai dengan aman tanpa SettingWithCopyWarning.

Level: Dasar · 9 menit baca

Latihan modul ini

Soal-soal untuk pelajaran ini berjalan di browser-mu dan langsung mengecek jawabanmu.

Idenya

Kurung siku biasa di pandas melakukan hal berbeda tergantung apa yang kamu berikan: nama memilih kolom, list memilih beberapa kolom, slice memilih baris, mask memfilter baris. Praktis, tapi ambigu. pandas punya dua selector eksplisit yang artinya selalu sama:

Keduanya menerima dua bagian yang dipisah koma: baris yang mana, lalu kolom yang mana. Kode pandas profesional memakainya untuk apa pun selain mencari satu kolom dengan cepat.

Supaya perbedaannya jelas, pakai nama produk sebagai index:

import pandas as pd

products = pd.DataFrame({
    "name": ["French Press 600ml", "Arabica Gayo 250g", "Ceramic Mug", "Gel Pen Set", "USB-C Hub"],
    "category": ["Kitchen", "Coffee", "Kitchen", "Stationery", "Electronics"],
    "price": [185000, 95000, 55000, 38000, 289000],
    "stock": [24, 80, 150, 0, 15],
}).set_index("name")
print(products)
                       category   price  stock
name
French Press 600ml      Kitchen  185000     24
Arabica Gayo 250g        Coffee   95000     80
Ceramic Mug             Kitchen   55000    150
Gel Pen Set          Stationery   38000      0
USB-C Hub           Electronics  289000     15

.set_index("name") memindahkan kolom name ke index, sehingga setiap baris diberi label sesuai produknya.

.loc: berdasarkan label

Modul ini memakai tabel produk kecil di mana setiap baris diberi label nama produknya. .loc mencari berdasarkan label-label itu: kamu menyebutkan baris mana (atau baris-baris mana) dan kolom mana (atau kolom-kolom mana) yang kamu mau, dipisahkan koma. Ini yang kamu dapatkan tergantung seberapa banyak yang kamu minta:

print(products.loc["Ceramic Mug", "price"])
print(products.loc["Ceramic Mug"])
print(products.loc[["Gel Pen Set", "USB-C Hub"], ["price", "stock"]])
55000
category    Kitchen
price         55000
stock           150
Name: Ceramic Mug, dtype: object
              price  stock
name
Gel Pen Set   38000      0
USB-C Hub    289000     15

Pakai : untuk berarti "semua":

print(products.loc[:, "category"].tolist())
print(products.loc["Arabica Gayo 250g":"Gel Pen Set", "price"])
['Kitchen', 'Coffee', 'Kitchen', 'Stationery', 'Electronics']
name
Arabica Gayo 250g    95000
Ceramic Mug          55000
Gel Pen Set          38000
Name: price, dtype: int64
Awas

Slice label dengan .loc mengikutsertakan ujung akhirnya. "Arabica Gayo 250g":"Gel Pen Set" mengembalikan tiga produk, termasuk Gel Pen Set. Slice posisi (dengan .iloc atau list) tidak mengikutsertakan ujung akhirnya. Ini adalah salah kaprah loc/iloc yang paling umum.

.loc dengan boolean mask

.loc menerima mask untuk baris, sehingga kamu bisa memfilter sekaligus memilih kolom dalam satu langkah:

low = products.loc[products["stock"] < 20, ["category", "stock"]]
print(low)
                category  stock
name
Gel Pen Set   Stationery      0
USB-C Hub    Electronics     15

Inilah cara idiomatis untuk menulis "kolom-kolom ini, untuk baris di mana…".

.iloc: berdasarkan posisi

Kadang kamu tidak peduli apa nama sebuah baris, hanya di mana letaknya: baris pertama, baris terakhir, sepuluh teratas. Untuk itulah .iloc. Selector ini mengabaikan label sepenuhnya dan menghitung posisi mulai dari 0, persis seperti list Python:

print(products.iloc[0])
print(products.iloc[-1, 1])
print(products.iloc[1:3, [0, 2]])
category    Kitchen
price        185000
stock            24
Name: French Press 600ml, dtype: object
289000
                  category  stock
name
Arabica Gayo 250g   Coffee     80
Ceramic Mug        Kitchen    150

Pakai .iloc kalau posisi memang yang kamu maksud: "10 baris pertama", "baris terakhir", "setiap baris berselang". Pakai .loc kalau yang kamu maksud adalah sesuatu yang spesifik berdasarkan nama. Kode yang menulis iloc[3] padahal maksudnya "Gel Pen Set" akan rusak begitu datanya diurutkan dengan cara lain.

Saat index-nya 0, 1, 2…

Dengan index bernomor bawaan, .loc dan .iloc terlihat sama, dan itu jebakan:

sales = pd.read_csv("sales.csv")
completed = sales[sales["status"] == "completed"]
print(completed.index[:5].tolist())
print(completed.loc[22, "product"])
print(completed.iloc[0]["product"])
[0, 1, 2, 3, 4]
Pour-over Kettle
Desk Organizer

Setelah difilter, label index tetap menyimpan nilai aslinya (mereka label, bukan posisi). completed.loc[22] berarti "baris yang berlabel 22", sedangkan completed.iloc[0] berarti "baris pertama yang tersisa". Kalau kamu ingin label 0, 1, 2… yang baru setelah memfilter, panggil .reset_index(drop=True).

Mengubah nilai dengan aman

.loc juga cara untuk mengisi nilai, termasuk untuk baris yang memenuhi kondisi:

products.loc["Gel Pen Set", "stock"] = 40
products.loc[products["category"] == "Kitchen", "price"] = (
    products.loc[products["category"] == "Kitchen", "price"] * 0.9
).round().astype(int)
print(products[["category", "price", "stock"]])
                       category   price  stock
name
French Press 600ml      Kitchen  166500     24
Arabica Gayo 250g        Coffee   95000     80
Ceramic Mug             Kitchen   49500    150
Gel Pen Set          Stationery   38000     40
USB-C Hub           Electronics  289000     15

Setiap harga Kitchen sekarang 10% lebih rendah, dan stok pen set sudah diisi ulang, langsung di tempat.

SettingWithCopyWarning

Suatu saat kamu akan melihat warning ini. Penyebabnya adalah pemilihan berantai (chained) yang diikuti assignment:

products[products["stock"] == 0]["stock"] = 50     # SettingWithCopyWarning, mungkin tidak melakukan apa-apa
products.loc[products["stock"] == 0, "stock"] = 50  # benar: satu .loc, baris dan kolom sekaligus

Baris pertama memilih sebagian baris (membuat DataFrame baru yang sementara) lalu mengisi nilai di salinan sementara itu, sehingga data aslimu mungkin sama sekali tidak berubah. pandas memperingatkanmu karena ia tidak tahu apakah kamu bermaksud mengubah data aslinya. Perbaikannya selalu sama: lakukan pemilihan dan assignment dalam satu pemanggilan .loc. Kalau kamu memang ingin DataFrame terpisah untuk diubah, buat secara eksplisit dengan .copy(): low_stock = products[products["stock"] < 20].copy().

Mengapa ini penting untuk kode yang bersih

.loc dan .iloc membuat maksudmu tidak ambigu: "harga produk ini" versus "baris ketiga". Pakai .loc untuk makna dan filter, .iloc untuk posisi, satu .loc[mask, column] = value untuk update, dan .copy() saat kamu ingin subset yang independen. Kode yang ditulis seperti ini tidak diam-diam berhenti bekerja saat datanya diurutkan, difilter atau diberi index ulang.

Rangkuman

Latihan modul ini

Soal-soal untuk pelajaran ini berjalan di browser-mu dan langsung mengecek jawabanmu.

Berikutnya: Menambah, mengganti nama, dan membuang kolom →