Data tabular nyata hampir selalu memuat kekosongan, misalnya sensor gagal merekam, responden melewatkan pertanyaan, atau berkas gabungan tidak lengkap. scikit-learn menampung kekosongan itu sebagai NaN (not a number) dan menolak memprosesnya secara bawaan. Topik ini membahas imputasi (imputation), yaitu pengisian nilai yang hilang dengan nilai pengganti, melalui SimpleImputer beserta empat strateginya dan akibat masing-masing pada data yang miring.
NaN dan penolakan model bawaan#
NaN adalah nilai khusus pada aritmetika titik apung yang menandai hasil yang tidak terdefinisi atau data yang tidak terekam. Nilai ini berbeda dari nol dan tidak bisa dibandingkan dengan bilangan apa pun, termasuk dengan NaN itu sendiri. Pada pandas, kekosongan string juga tampil sebagai NaN, sehingga istilah ini menjadi penanda kekosongan yang umum pada data tabular.
Kebanyakan estimator scikit-learn memeriksa keberadaan NaN saat fit dan menolak data yang memuatnya. Penolakan ini disengaja, karena cara mengisi kekosongan yang tepat bergantung pada data dan keputusan analisis, sehingga keputusan itu diserahkan kepada pemanggil melalui transformer imputasi.
Perbaikan didahului pengukuran, yaitu menghitung kekosongan pada setiap kolom lebih dahulu. Pada array NumPy, np.isnan(X).sum() menghitung banyaknya NaN, sedangkan df.isna().sum() pada pandas memberikan jumlah per kolom dalam bentuk tabel yang mudah dibaca. Angka tersebut menentukan langkah berikutnya, karena kolom dengan sedikit kekosongan layak diimputasi, sedangkan kolom yang sebagian besar kosong lebih baik dibuang. Perilaku penolakan pada model dapat dibuktikan dengan menangkap pengecualian yang muncul.
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
X = np.array([[1.0, 2.0], [3.0, np.nan], [5.0, 6.0]])
y = np.array([0, 1, 0])
try:
KNeighborsClassifier().fit(X, y)
except ValueError as e:
print("ValueError:", e)ValueError: Input X contains NaN.
KNeighborsClassifier does not accept missing values encoded as NaN natively. For supervised learning, you might want to consider sklearn.ensemble.HistGradientBoostingClassifier and Regressor which accept missing values encoded as NaNs natively. Alternatively, it is possible to preprocess the data, for instance by using an imputer transformer in a pipeline or drop samples with missing values. See https://scikit-learn.org/stable/modules/impute.html You can find a list of all estimators that handle NaN values at the following page: https://scikit-learn.org/stable/modules/impute.html#estimators-that-handle-nan-valuesPesan error tersebut menunjukkan dua jalan keluar yang sah, yaitu menggunakan estimator yang menerima NaN secara bawaan seperti HistGradientBoostingClassifier atau mengimputasi data terlebih dahulu. Menghapus baris yang memuat NaN juga mungkin, tetapi langkah itu berarti kehilangan baris data. Imputasi dengan SimpleImputer adalah pilihan yang paling sering digunakan pada data tabular.
Empat strategi SimpleImputer#
SimpleImputer mengisi kekosongan setiap kolom dengan statistik yang dipelajari dari nilai kolom itu yang tidak hilang. Empat strateginya adalah mean yang mengisi dengan rata-rata kolom, median yang mengisi dengan median kolom, most_frequent yang mengisi dengan nilai yang paling sering muncul, dan constant yang mengisi dengan nilai tetap yang diberikan melalui fill_value. Parameter missing_values menetapkan penanda kekosongan yang dicari, secara bawaan np.nan, sehingga penanda lain seperti 0 juga dapat diperlakukan sebagai kekosongan. Berkas berikut menjalankan keempatnya pada matriks yang memuat satu NaN serta satu nilai ekstrem.
import numpy as np
from sklearn.impute import SimpleImputer
np.set_printoptions(suppress=True)
X = np.array([
[22.0, 30.0, 1200.0],
[24.0, 31.0, np.nan],
[26.0, 30.0, 1350.0],
[28.0, 33.0, 1350.0],
[23.0, 30.0, 98000.0],
])
print("Data asli (np.nan menandai nilai yang hilang):")
print(X)
for strategi in ["mean", "median", "most_frequent"]:
hasil = SimpleImputer(strategy=strategi).fit_transform(X)
print(f"Hasil strategi {strategi}:")
print(hasil)
hasil = SimpleImputer(strategy="constant", fill_value=0).fit_transform(X)
print("Hasil strategi constant dengan fill_value 0:")
print(hasil)Data asli (np.nan menandai nilai yang hilang):
[[ 22. 30. 1200.]
[ 24. 31. nan]
[ 26. 30. 1350.]
[ 28. 33. 1350.]
[ 23. 30. 98000.]]
Hasil strategi mean:
[[ 22. 30. 1200.]
[ 24. 31. 25475.]
[ 26. 30. 1350.]
[ 28. 33. 1350.]
[ 23. 30. 98000.]]
Hasil strategi median:
[[ 22. 30. 1200.]
[ 24. 31. 1350.]
[ 26. 30. 1350.]
[ 28. 33. 1350.]
[ 23. 30. 98000.]]
Hasil strategi most_frequent:
[[ 22. 30. 1200.]
[ 24. 31. 1350.]
[ 26. 30. 1350.]
[ 28. 33. 1350.]
[ 23. 30. 98000.]]
Hasil strategi constant dengan fill_value 0:
[[ 22. 30. 1200.]
[ 24. 31. 0.]
[ 26. 30. 1350.]
[ 28. 33. 1350.]
[ 23. 30. 98000.]]Kolom ketiga memuat nilai normal 1200 sampai 1350 dan satu nilai ekstrem 98000, sehingga statistik yang dipelajari untuk mengisi NaN-nya berbeda-beda pada setiap strategi. Strategi mean menghasilkan 25475 yang jauh dari seluruh nilai normal kolom itu, sementara median dan most_frequent menghasilkan 1350 yang terletak di tengah nilai normal. Strategi constant mengisi dengan 0 sesuai nilai yang diberikan tanpa memandang isi kolom. Statistik pada setiap kolom dihitung dari nilai yang tidak hilang saja, sehingga NaN tidak ikut menarik hasil perhitungannya.
Memilih strategi pada data yang miring#
Selisih antara 25475 dan 1350 memperlihatkan mengapa pilihan strategi bukan perkara selera. Rata-rata mudah digeser oleh satu nilai ekstrem karena perhitungannya menjumlah seluruh nilai, sehingga satu 98000 sudah cukup mengangkat rata-rata kolom itu hingga belasan ribu. Median justru memilih nilai tengah setelah data diurutkan, sehingga nilai ekstrem hanya berperan sebagai satu baris data dan tidak menggeser hasilnya.
Aturan praktisnya dapat dirumuskan singkat. Strategi mean aman pada data numerik yang sebarannya simetris dan bebas pencilan. Strategi median lebih tahan pada data numerik yang miring atau yang pencilannya belum dibersihkan. Strategi most_frequent menjadi pilihan untuk kolom kategorikal maupun string karena rata-rata dan median tidak terdefinisi pada nilai teks. Strategi constant berguna apabila kekosongan itu sendiri membawa makna, misalnya 0 pada jumlah pesanan yang tidak pernah dibuat, karena nilai penggantinya dinyatakan secara sadar.
Statistik tersimpan dan digunakan ulang#
Imputasi pada SimpleImputer mengikuti kontrak transformer yang sama dengan scaler dan encoder. Statistik pengisian dipelajari dari data latih, kemudian digunakan ulang untuk data apa pun yang ditransformasikan selanjutnya, sehingga data latih dan data uji diisi dengan nilai yang konsisten. Bukti berikut menampilkan statistik yang tersimpan beserta pemakaiannya pada satu baris data baru.
import numpy as np
from sklearn.impute import SimpleImputer
np.set_printoptions(suppress=True)
X = np.array([
[22.0, 30.0, 1200.0],
[24.0, 31.0, np.nan],
[26.0, 30.0, 1350.0],
[28.0, 33.0, 1350.0],
[23.0, 30.0, 98000.0],
])
imputer = SimpleImputer(strategy="median").fit(X)
print("Statistik tersimpan di imputer:", imputer.statistics_)
X_baru = np.array([[21.0, np.nan, 1400.0]])
print("Data baru setelah transform:")
print(imputer.transform(X_baru))Statistik tersimpan di imputer: [ 24. 30. 1350.]
Data baru setelah transform:
[[ 21. 30. 1400.]]Konsistensi ini penting ketika data uji memuat kekosongan pada posisi yang berbeda dari data latih. Statistik tetap diambil dari data latih, bukan dihitung ulang dari data uji, karena statistik data uji tidak tersedia saat prediksi nanti. Aturan lengkapnya diulas pada topik Fitting Hanya pada Train.
Ringkasan#
- Kebanyakan estimator scikit-learn menolak data yang memuat NaN, sehingga pengisian nilai yang hilang perlu dilakukan sebelum
fit. - SimpleImputer menyediakan strategi
mean,median,most_frequent, danconstant, dengan statistik yang dipelajari per kolom dari nilai yang tidak hilang. - Median lebih tahan pencilan daripada rata-rata, sehingga kolom yang miring lebih aman diisi dengan
median. - Statistik pengisian tersimpan pada
statistics_dan digunakan ulang saattransform, menjaga konsistensi antara data latih dan data uji.
Referensi#
- 6.4. Imputation of missing values — scikit-learn documentation — Mengulas strategi imputasi dan daftar estimator yang menerima NaN.
- SimpleImputer — scikit-learn documentation — Rujukan parameter strategy, fill_value, dan atribut statistics_.
- Getting started tutorials — pandas documentation — Tutorial pandas yang membahas pemeriksaan data tabel termasuk nilai yang hilang.