Data pegawai di sebuah perusahaan hampir selalu berbentuk tabel: kolom nama berisi teks, kolom umur berisi bilangan bulat, dan kolom gaji berisi bilangan pecahan. Array NumPy biasa tidak dapat menampung kombinasi itu dalam satu array, karena seluruh elemen array wajib bertipe sama — aturan yang dibahas pada Chapter Atribut dtype. Selama ini jalan keluarnya adalah membuat tiga array terpisah dan mengurus keselarasan indeksnya secara manual.

Structured array menyelesaikan masalah tersebut: satu array, tetapi setiap elemennya adalah record yang terdiri atas beberapa field dengan tipe masing-masing. Karena satu record utuh tersimpan berdampingan di memori, structured array sangat cocok untuk data yang dibaca atau ditulis baris demi baris — misalnya record dari file biner atau database — sebelum data naik level ke pandas.

Membuat Structured Array dengan dtype Field #

Kunci utamanya adalah structured dtype: definisi skema yang disusun dari list berisi pasangan (nama_field, spesifikasi_tipe). Spesifikasi tipe memakai kode string yang sama dengan dtype biasa — U10 untuk string Unicode maksimal 10 karakter, i4 untuk integer 32-bit, dan f8 untuk float 64-bit:

python
import numpy as np

dtype = np.dtype([("nama", "U10"), ("umur", "i4"), ("gaji", "f8")])
pegawai = np.array(
    [("Budi", 34, 8500000.0), ("Siti", 29, 9200000.0), ("Dewi", 41, 7800000.0)],
    dtype=dtype,
)
print(pegawai)
print(pegawai.dtype)
print(pegawai.dtype.itemsize)

Output yang Dihasilkan:

text
[('Budi', 34, 8500000.) ('Siti', 29, 9200000.) ('Dewi', 41, 7800000.)]
[('nama', '<U10'), ('umur', '<i4'), ('gaji', '<f8')]
52

Mari kita bedah:

  1. Baris 3 (np.dtype(...)): interpreter menerjemahkan list of tuples menjadi objek dtype dengan tiga field bernama. Setiap tuple menetapkan nama field dan tipe datanya.
  2. Baris 4-7 (np.array(...)): list of tuples dikonversi menjadi array satu dimensi berisi tiga record. NumPy mencocokkan posisi: "Budi" masuk field nama, 34 masuk field umur, dan seterusnya.
  3. Baris 9 (print(pegawai.dtype)): dtype tercetak sebagai list field; tanda < menandai urutan byte little-endian.
  4. Baris 10 (itemsize): satu record menempati 10 x 4 + 4 + 8 = 52 byte — string U10 memakai 4 byte per karakter.

Mengakses Field dan Record #

Field diakses dengan kurung siku dan nama field, mirip mengambil kolom tabel. Hasilnya adalah array biasa yang siap dihitung — bisa diagregasi, difilter, dan dijadikan dasar boolean indexing:

python
import numpy as np

dtype = np.dtype([("nama", "U10"), ("umur", "i4"), ("gaji", "f8")])
pegawai = np.array(
    [("Budi", 34, 8500000.0), ("Siti", 29, 9200000.0), ("Dewi", 41, 7800000.0)],
    dtype=dtype,
)
print(pegawai["nama"])
print(pegawai["gaji"].mean())
print(pegawai["umur"] > 30)
print(pegawai[pegawai["umur"] > 30])
print(pegawai[1])

Output yang Dihasilkan:

text
['Budi' 'Siti' 'Dewi']
8500000.0
[ True False  True]
[('Budi', 34, 8500000.) ('Dewi', 41, 7800000.)]
('Siti', 29, 9200000.0)

Penjelasan tiap baris penting:

  1. Baris 8 (pegawai["nama"]): hasilnya array string biasa; akses field tidak menyalin data, hanya membuat view dengan stride tertentu — perilaku yang dibahas mendalam pada Chapter View vs Copy.
  2. Baris 9: karena pegawai["gaji"] adalah array float64 biasa, method mean() langsung dapat dipakai.
  3. Baris 10-11: perbandingan field menghasilkan mask boolean, dan mask tersebut memfilter record utuh — bukan hanya satu field.
  4. Baris 12 (pegawai[1]): satu record dikembalikan sebagai objek numpy.void, lalu field per record dapat diakses dengan pegawai[1]["nama"].

Menyiapkan Array Kosong lalu Mengisinya #

Untuk data yang datang bertahap, kita bisa membuat wadah kosong dengan np.zeros dan structured dtype, lalu mengisi setiap field dengan operasi vektor. Nilai awalnya deterministik: string kosong, 0, dan 0.0:

python
import numpy as np

dtype = np.dtype([("nama", "U10"), ("umur", "i4"), ("gaji", "f8")])
staf = np.zeros(3, dtype=dtype)
print(staf)
staf["nama"] = ["Andi", "Rina", "Tono"]
staf["umur"] = [25, 31, 28]
staf["gaji"] = [6000000.0, 7500000.0, 6900000.0]
print(staf)
print(staf["umur"].sum())

Output yang Dihasilkan:

text
[('', 0, 0.) ('', 0, 0.) ('', 0, 0.)]
[('Andi', 25, 6000000.) ('Rina', 31, 7500000.) ('Tono', 28, 6900000.)]
84

Bedah singkat:

  1. Baris 4 (np.zeros(3, dtype=dtype)): interpreter mengalokasikan tiga record dan mengisi seluruh byte dengan nol, sehingga tiap field bernilai nol sesuai tipenya.
  2. Baris 6-8: penugasan per field menerima list biasa; NumPy melakukan konversi tipe secara otomatis ke spesifikasi field.
  3. Baris 10: field umur kembali sebagai array int32 biasa, sehingga sum() menghasilkan 84.

Mengurutkan Record Berdasarkan Field #

Method sort dan fungsi np.sort menerima argumen order berupa nama field. Seluruh record ikut berpindah bersama — urutan field di dalam satu record tidak pernah tercampur:

python
import numpy as np

dtype = np.dtype([("nama", "U10"), ("umur", "i4"), ("gaji", "f8")])
pegawai = np.array(
    [("Budi", 34, 8500000.0), ("Siti", 29, 9200000.0), ("Dewi", 41, 7800000.0)],
    dtype=dtype,
)
urut = np.sort(pegawai, order="gaji")
print(urut)
pegawai.sort(order="umur")
print(pegawai)

Output yang Dihasilkan:

text
[('Dewi', 41, 7800000.) ('Budi', 34, 8500000.) ('Siti', 29, 9200000.)]
[('Siti', 29, 9200000.) ('Budi', 34, 8500000.) ('Dewi', 41, 7800000.)]

Dua hal patut dicatat: np.sort mengembalikan array baru, sedangkan method pegawai.sort(...) mengurutkan array di tempat (in place). Untuk beberapa kriteria sekaligus, order menerima list, misalnya order=["umur", "gaji"].

Kapan Structured Array Layak Dipakai #

Structured array bukan pengganti pandas, melainkan lapisan penyimpanan yang lebih dekat ke memori. Perbandingan singkat:

PendekatanKekuatanBatasan
Structured arrayrecord utuh rapat di memori; baca/tulis baris cepat; tanpa dependensioperasi per kolom bergerak melompati memori (stride)
Beberapa array terpisahoperasi kolom paling cepat (contiguous)sinkronisasi indeks antar-array menjadi tanggung jawab kita
pandas DataFramekaya fitur analisis tabeldependensi tambahan; overhead memori lebih besar

Bab berikutnya, Record Array, menyempurnakan pola akses ini: field dapat dibaca lewat atribut seperti pegawai.nama tanpa tanda kurung siku.