pandas 2.2.3 — versi yang kami pakai untuk menguji bab ini — dibangun di atas NumPy: di balik setiap kolom DataFrame terdapat array NumPy yang diberi label. Karena keduanya serumpun, pertukaran data antara DataFrame/Series dan ndarray hampir tanpa gesekan. Persoalan menarik justru ada pada detailnya: dtype apa yang muncul setelah konversi, dan konversi mana yang menyalin data.
Kita mulai dari arah NumPy ke pandas, lalu kembali ke NumPy dengan to_numpy(), dan ditutup dengan aturan salin-tempel memori (copy=True) yang sering menyelamatkan dari bug halus.
Membangun DataFrame dari Array NumPy #
Konstruktor pd.DataFrame menempatkan kolom array berdasarkan posisi, lalu melabelinya dengan columns dan index:
import numpy as np
import pandas as pd
data = np.array([
[3500, 120],
[5000, 80],
[12000, 25],
])
df = pd.DataFrame(data, columns=["harga", "stok"],
index=["Indomie", "Teh Kotak", "Kopi Sachet"])
print(df)
df["nilai"] = data[:, 0] * data[:, 1]
print(df)Output yang Dihasilkan:
harga stok
Indomie 3500 120
Teh Kotak 5000 80
Kopi Sachet 12000 25
harga stok nilai
Indomie 3500 120 420000
Teh Kotak 5000 80 400000
Kopi Sachet 12000 25 300000Bedah baris demi baris:
- Baris 4-8: array
databerbentuk(3, 2)bertipeint64— stok gudang tiga produk fiktif. - Baris 9-10 (
pd.DataFrame(data, ...)): kolom ke-0 menjadihargadan kolom ke-1 menjadistoksemata karena urutannya; label index tidak menyaring atau menata ulang baris, array mentah tidak mengenal label. - Baris 11-12: kolom baru
nilaidihitung dengan vectorization di array (data[:, 0] * data[:, 1]) sebelum diserahkan ke pandas; panjang hasilnya harus cocok dengan jumlah baris.
Dua istilah yang perlu dibedakan: index adalah label baris milik pandas, sedangkan ndarray hanya bekerja secara posisional. Bila data kita berpindah dari array ke DataFrame, penugasan label terjadi setelah data tersalin, bukan saat penghitungan.
Mengubah DataFrame Menjadi Array #
df.to_numpy() adalah cara yang disarankan untuk keluar dari DataFrame ke ndarray. Bentuk dan nilainya mengikuti semua kolom, sedangkan dtype menyesuaikan isi kolom terburuk:
import numpy as np
import pandas as pd
df = pd.DataFrame({
"produk": ["Indomie", "Teh Kotak"],
"harga": [3500, 5000],
"stok": [120, 80],
})
arr = df.to_numpy()
print(arr)
print(arr.dtype)Output yang Dihasilkan:
[['Indomie' 3500 120]
['Teh Kotak' 5000 80]]
objectPenjelasannya:
- Baris 3-8: DataFrame berisi satu kolom teks dan dua kolom numerik.
- Baris 9-11 (
df.to_numpy()): hasilnya array 2-D berisi semua kolom; karena satu DataFrame harus satu dtype, kehadiran kolom teks memaksa seluruh array menjadiobject. - Baris 12 (
print(arr.dtype)): dtypeobjectberarti setiap sel adalah objek Python terpisah — semua keunggulan kecepatan NumPy hilang pada array ini.
Series dan Array Dua Arah #
Untuk satu kolom, Series bertukar data dengan array 1-D tanpa banyak drama. Yang perlu diingat: label index tidak ikut pindah ke array, sehingga kita harus menyerahkannya kembali secara eksplisit:
import numpy as np
import pandas as pd
s = pd.Series([27.5, 28.1, 26.9], index=["Senin", "Selasa", "Rabu"])
a = s.to_numpy()
print(a, a.dtype)
print("rata-rata:", np.mean(a))
kembali = pd.Series(a, index=s.index)
print(kembali)Output yang Dihasilkan:
[27.5 28.1 26.9] float64
rata-rata: 27.5
Senin 27.5
Selasa 28.1
Rabu 26.9
dtype: float64Bedah singkat:
- Baris 3-5:
s.to_numpy()menghasilkan ndarrayfloat64; labelSenin/Selasa/Rabutinggal di pandas, array hanya membawa nilai. - Baris 6: fungsi NumPy seperti
np.meanlangsung menerima hasilnya — di sinilah NumPy menjadi bahasa bersama antar pustaka. - Baris 7-8: konstruktor
pd.Series(a, index=s.index)menyusun kembali Series; nilai ditempatkan berdasarkan posisi, lalu label index lama ditempelkan pada posisi tersebut.
Aturan Salin Memori: to_numpy(copy=True) #
Bagian ini adalah gotcha terpenting bab. Secara bawaan, to_numpy() boleh mengembalikan array yang berbagi memori dengan kolom DataFrame; mutasi array akan merembes ke DataFrame:
import numpy as np
import pandas as pd
df = pd.DataFrame({"suhu": [27.5, 28.1, 26.9]})
arr = df.to_numpy()
print("default berbagi ->", np.shares_memory(arr, df["suhu"].to_numpy()))
arr[0, 0] = 99.0
print("df ikut berubah ->", df["suhu"].iloc[0])
arr2 = df.to_numpy(copy=True)
arr2[0, 0] = 5.0
print("df dgn copy=True ->", df["suhu"].iloc[0])Output yang Dihasilkan:
default berbagi -> True
df ikut berubah -> 99.0
df dgn copy=True -> 99.0Mari kita baca hasilnya:
- Baris 5-6: pada DataFrame satu-dtype seperti ini,
to_numpy()mengembalikan array yang berbagi buffer dengan kolomsuhu—np.shares_memorymembuktikanTrue. - Baris 7-8: menulisi
arr[0, 0]langsung mengubah nilai di dalam DataFrame; dua objek berbeda, satu memori. - Baris 9-11:
copy=Truememaksa salinan baru; perubahanarr2tidak memengaruhidfsama sekali (nilainya tetap99.0dari mutasi sebelumnya).
Ringkasan Arah Konversi #
| Kebutuhan | API | Catatan |
|---|---|---|
| Array ke DataFrame | pd.DataFrame(arr, columns=..., index=...) | kolom ditempatkan berdasarkan posisi |
| DataFrame ke array | df.to_numpy() | dtype mengikuti gabungan kolom; bisa object |
| Series ke array | s.to_numpy() | index tidak ikut; nilai saja |
| Array ke Series | pd.Series(a, index=...) | nilai posisional, label ditempel |
| Salin terjamin | df.to_numpy(copy=True) | wajib bila array akan dimutasi |
Dengan lima pola di atas, hampir semua kebutuhan harian NumPy–pandas terselesaikan. Untuk data yang mengandung nilai kosong, ingat bahwa pandas menandainya sebagai NaN — perlakuannya dibahas pada bab NaN dan Infinity, sementara persamaan dan perbedaan kedua pustaka ini terasa paling jelas ketika kita membaca kembali Pengenalan Vectorization.