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:
.loc[rows, columns]memilih berdasarkan label: label index dan nama kolom..iloc[rows, columns]memilih berdasarkan posisi integer: 0, 1, 2… seperti list.
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
- Satu label baris dan satu nama kolom → satu nilai.
- Hanya label baris → baris itu, sebagai Series.
- List label → sebuah DataFrame.
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
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
iloc[0]adalah baris pertama, apa pun labelnya.iloc[-1, 1]adalah baris terakhir, kolom kedua (price).iloc[1:3, [0, 2]]adalah baris di posisi 1 dan 2 (ujung akhir tidak ikut), kolom di posisi 0 dan 2.
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
.loc[rows, cols]memilih berdasarkan label;.iloc[rows, cols]berdasarkan posisi.:berarti semua. Slice label.locmengikutsertakan ujung akhir; slice.iloctidak..loc[mask, ["a", "b"]]memfilter baris dan memilih kolom dalam satu langkah.- Setelah difilter, label index tetap memakai nilai lamanya;
.reset_index(drop=True)menomori ulang. - Isi nilai dengan
df.loc[row_selector, "col"] = valuedalam satu langkah untuk menghindari SettingWithCopyWarning. - Pakai
.copy()saat kamu ingin subset independen untuk diubah.