Data pelanggan berbentuk tabel — kolom nama berisi teks, kolom umur bilangan bulat, kolom belanja bilangan pecahan — secara alami disimpan sebagai structured array seperti pada Chapter Structured Array, dengan akses field yang bisa diperhalus lewat recarray pada Chapter Record Array. Masalah muncul ketika data itu harus lanjut ke pustaka lain: pandas dan scikit-learn menginginkan matriks dua dimensi bertipe seragam, bukan array satu dimensi berisi record campuran.

Modul numpy.lib.recfunctions adalah kotak peralatan untuk mengubah susunan field structured array. Cakupan bab ini:

  • structured_to_unstructured — meratakan record menjadi matriks biasa.
  • merge_arrays — menggabungkan dua structured array menjadi satu.
  • append_fields, drop_fields, rename_fields — menambah, membuang, dan mengganti nama field.

Satu hal perlu diatur lebih dulu: cara mengimpor modul ini dengan benar.

Mengimpor numpy.lib.recfunctions dengan Benar #

Berbeda dari sebagian besar modul NumPy, recfunctions tidak ikut termuat saat import numpy. Akibatnya, akses langsung seperti np.lib.recfunctions.structured_to_unstructured tanpa mengimpor modulnya menghasilkan AttributeError. Pola yang kita pakai sepanjang bab adalah impor eksplisit dengan alias rfn:

python
import numpy as np

try:
    f = np.lib.recfunctions.structured_to_unstructured
    print("akses langsung berhasil:", f.__name__)
except AttributeError as e:
    print("AttributeError:", e)
    import numpy.lib.recfunctions as rfn
    print("import langsung berhasil:", rfn.structured_to_unstructured.__name__)

Output yang Dihasilkan:

text
AttributeError: module 'numpy.lib' has no attribute 'recfunctions'
import langsung berhasil: structured_to_unstructured

Mari kita bedah:

  1. Baris 3-5: akses atribut recfunctions pada np.lib diuji lebih dulu; karena submodul belum termuat di memori, Python melempar AttributeError.
  2. Baris 6-8: penanganan error mencetak pesannya, lalu mengimpor submodul secara langsung. Sejak baris ini pula np.lib.recfunctions mulai dikenali, karena impor langsung sekaligus memuat modul tersebut.

structured_to_unstructured: dari Record ke Matriks #

Fungsi yang paling sering dipakai. Structured array yang field-nya semua numerik diratakan menjadi matriks dua dimensi biasa, dengan tipe hasil berupa promosi tipe seluruh field. Bentuk inilah yang diterima estimator pada Chapter NumPy dan scikit-learn:

python
import numpy as np
import numpy.lib.recfunctions as rfn

pelanggan = np.array(
    [("Budi", 34, 250000.0), ("Siti", 29, 180000.0), ("Dewi", 41, 320000.0)],
    dtype=[("nama", "U10"), ("umur", "i4"), ("belanja", "f8")],
)
angka = rfn.structured_to_unstructured(pelanggan[["umur", "belanja"]])
print(angka)
print(angka.dtype, angka.shape)
print(angka[:, 1].mean())

Output yang Dihasilkan:

text
[[3.4e+01 2.5e+05]
 [2.9e+01 1.8e+05]
 [4.1e+01 3.2e+05]]
float64 (3, 2)
250000.0

Penjelasan:

  1. Baris 9 (pelanggan[["umur", "belanja"]]): mengindeks structured array dengan daftar nama field menghasilkan structured array baru yang hanya berisi dua field numerik itu.
  2. Baris 10 (rfn.structured_to_unstructured(...)): dua field per record diratakan menjadi satu baris matriks; hasilnya float64 berbentuk (3, 2) — matriks biasa, bukan lagi kumpulan record.
  3. Baris 12: operasi seperti mean kini berjalan langsung pada kolom matriks.

Angka pada matriks tercetak dalam notasi ilmiah karena NumPy memakai satu format seragam untuk seluruh elemen array; pengaturan tampilan ini dibahas pada Chapter NumPy Print Options.

Kolom Teks vs Kolom Numerik #

Field string <U10 mengubah rencana. structured_to_unstructured tidak menolak field teks — seluruh tipe dipromosikan menjadi string lebar tetap, sehingga angka ikut berubah menjadi teks dan matriksnya tidak bisa dihitung:

python
import numpy as np
import numpy.lib.recfunctions as rfn

pelanggan = np.array(
    [("Budi", 34, 250000.0), ("Siti", 29, 180000.0), ("Dewi", 41, 320000.0)],
    dtype=[("nama", "U10"), ("umur", "i4"), ("belanja", "f8")],
)
semua = rfn.structured_to_unstructured(pelanggan)
print(semua.dtype, semua.shape)
print(semua[0])
label = pelanggan["nama"]
angka = rfn.structured_to_unstructured(pelanggan[["umur", "belanja"]])
print(label[0], angka[0, 1])

Output yang Dihasilkan:

text
<U32 (3, 3)
['Budi' '34' '250000.0']
Budi 250000.0

Penjelasan:

  1. Baris 9-11: ketiga field ikut diratakan; dtype hasil <U32 berasal dari promote_types("U10", "i4") yang kemudian dipromosikan lagi dengan "f8". Nilai 34 dan 250000.0 kini tersimpan sebagai teks.
  2. Baris 12-14: inilah pemisahan kolom: kolom teks nama diambil langsung dari structured array sebagai label, sedangkan matriks numerik dirakit dari subset field umur dan belanja. Elemen angka[0, 1] kembali menjadi bilangan pecahan 250000.0.

merge_arrays: Menggabungkan Dua Structured Array #

Data pelanggan sering datang terpisah: satu berkas memuat nama dan umur, berkas lain memuat total belanja dan jumlah kunjungan. rfn.merge_arrays menyandingkan dua structured array yang jumlah barisnya sama. Tanpa opsi tambahan, hasilnya field bertingkat dengan nama otomatis f0 dan f1; opsi flatten=True meratakannya menjadi field-field sejajar:

python
import numpy as np
import numpy.lib.recfunctions as rfn

dasar = np.array(
    [("Budi", 34), ("Siti", 29), ("Dewi", 41)],
    dtype=[("nama", "U10"), ("umur", "i4")],
)
belanja = np.array(
    [(250000.0, 4), (180000.0, 2), (320000.0, 7)],
    dtype=[("total", "f8"), ("kunjungan", "i4")],
)
gabungan = rfn.merge_arrays((dasar, belanja), flatten=True)
print(gabungan)
print(gabungan.dtype.names)

Output yang Dihasilkan:

text
[('Budi', 34, 250000., 4) ('Siti', 29, 180000., 2)
 ('Dewi', 41, 320000., 7)]
('nama', 'umur', 'total', 'kunjungan')

Penjelasan:

  1. Baris 13 (merge_arrays((dasar, belanja), flatten=True)): record kedua array disandingkan per indeks; flatten=True mencegah field bertingkat sehingga empat field tampil sejajar dalam satu dtype.
  2. Baris 15 (dtype.names): nama field hasil gabungan adalah gabungan nama kedua sumber; tanpa flatten, nama otomatisnya f0 dan f1.
  3. Jumlah baris kedua array wajib sama, karena penyandingan dilakukan per indeks record.

Menambah, Membuang, dan Mengganti Nama Field #

Tiga fungsi terakhir merapikan skema: append_fields menambah field baru, drop_fields membuang field yang tidak diperlukan, dan rename_fields mengganti nama tanpa menyentuh data:

python
import numpy as np
import numpy.lib.recfunctions as rfn

pelanggan = np.array(
    [("Budi", 34, 250000.0), ("Siti", 29, 180000.0)],
    dtype=[("nama", "U10"), ("umur", "i4"), ("belanja", "f8")],
)
dengan_level = rfn.append_fields(pelanggan, "level", ["silver", "emas"], dtypes="U10")
print(dengan_level.dtype.names)
print(dengan_level)
ringkas = rfn.drop_fields(dengan_level, "umur")
ringkas = rfn.rename_fields(ringkas, {"belanja": "total_belanja"})
print(ringkas.dtype.names)
print(ringkas)

Output yang Dihasilkan:

text
('nama', 'umur', 'belanja', 'level')
[('Budi', 34, 250000.0, 'silver') ('Siti', 29, 180000.0, 'emas')]
('nama', 'total_belanja', 'level')
[('Budi', 250000., 'silver') ('Siti', 180000., 'emas')]

Penjelasan:

  1. Baris 9 (append_fields(...)): field level ditambahkan di posisi akhir dengan data per baris dari list; parameter dtypes menetapkan tipenya. Untuk nilai isian yang sama di semua baris, kirim array berisi nilai itu — misalnya np.zeros(2) — karena NumPy 2.1.3 belum menyediakan replicate_fields, padanan fungsi ini di versi lebih baru.
  2. Baris 12 (drop_fields): field umur dibuang; sisa fieldnya nama, belanja, dan level.
  3. Baris 13 (rename_fields): kamus {nama_lama: nama_baru} hanya mengubah label; nilai setiap record tidak bergerak.

Sebagai penutup, peta fungsi yang sudah kita coba:

FungsiTugas
structured_to_unstructuredmeratakan field numerik menjadi matriks biasa
merge_arraysmenyandingkan dua structured array per baris
append_fieldsmenambah field baru
drop_fieldsmembuang field
rename_fieldsmengganti nama field

Dengan kolom teks dipisah dari matriks numerik, data pelanggan sudah berbentuk yang diharapkan pustaka analisis; jalur lengkapnya diuji pada Chapter NumPy dan scikit-learn.