Tiga transformasi pada judul topik ini adalah kata kerja yang paling sering muncul pada pekerjaan DataFrame harian, yaitu select untuk memilih dan menyusun kolom, filter untuk menyaring baris, dan withColumn untuk menambah atau mengganti kolom. Topik ini membahas cara kerja ketiganya beserta ekspresi kolom yang menjadi bahasa dasarnya. Setelah membacanya, kolom dapat dirakit sebagai ekspresi, baris dapat disaring dengan kondisi tunggal maupun majemuk, dan kolom baru dapat ditambahkan dari logika kondisional.
Ekspresi kolom sebagai bahasa dasar#
Hampir semua transformasi DataFrame menerima objek Column, dan objek itulah yang disebut ekspresi kolom. Ekspresi kolom belum berisi data apa pun, melainkan deskripsi perhitungan yang akan dievaluasi pada setiap baris ketika sebuah action meminta hasil. Penulisannya dapat berupa akses df["nilai"], fungsi dari modul pyspark.sql.functions, atau hasil aritmetika di antara keduanya, misalnya df["nilai"] + 5.
Ekspresi yang sama dapat dirakit dengan beberapa gaya tulisan. Gaya df["nilai"] + 5 terasa seperti Python biasa, sedangkan gaya fungsi seperti F.col("nilai") + 5 tidak bergantung pada objek DataFrame tertentu sehingga lebih mudah dipakai ulang antar DataFrame. Kedua gaya menghasilkan rencana eksekusi yang sama, sehingga pilihannya menjadi soal keterbacaan tim, bukan soal kebenaran. Kebiasaan yang lazim adalah mengimpor modul fungsi dengan alias F dan memakai F.col() secara konsisten.
select: memilih dan menyusun kolom#
Metode select menghasilkan DataFrame baru yang kolomnya disusun sesuai argumen, baik berupa nama kolom, objek Column, maupun ekspresi yang diberi nama baru melalui .alias(). Skrip berikut memperagakan select bersama filter dan withColumn pada satu data siswa yang sama, sehingga perbandingan ketiganya terlihat berdampingan.
from pyspark.sql import SparkSession
from pyspark.sql import functions as F
spark = (
SparkSession.builder
.master("local[2]")
.appName("operasi-dasar")
.config("spark.sql.shuffle.partitions", "2")
.getOrCreate()
)
data = [
(1, "Ali", "10A", 85),
(2, "Budi", "10A", 90),
(3, "Citra", "10B", 78),
(4, "Dewi", "10B", 92),
]
df = spark.createDataFrame(data, "id long, nama string, kelas string, nilai long")
print("=== select kolom dan ekspresi ===")
df.select("nama", (df["nilai"] + 5).alias("nilai_plus")).orderBy("nama").show()
print("=== filter kondisi tunggal ===")
df.filter(df["nilai"] >= 85).orderBy("id").show()
print("=== filter kondisi majemuk ===")
df.filter((df["kelas"] == "10B") & (df["nilai"] >= 90)).orderBy("id").show()
print("=== withColumn status ===")
dengan_status = df.withColumn(
"status",
F.when(F.col("nilai") >= 85, "lulus").otherwise("remedial"),
)
dengan_status.orderBy("id").show()
spark.stop()WARNING: Using incubator modules: jdk.incubator.vector
=== select kolom dan ekspresi ===
+-----+----------+
| nama|nilai_plus|
+-----+----------+
| Ali| 90|
| Budi| 95|
|Citra| 83|
| Dewi| 97|
+-----+----------+
=== filter kondisi tunggal ===
+---+----+-----+-----+
| id|nama|kelas|nilai|
+---+----+-----+-----+
| 1| Ali| 10A| 85|
| 2|Budi| 10A| 90|
| 4|Dewi| 10B| 92|
+---+----+-----+-----+
=== filter kondisi majemuk ===
+---+----+-----+-----+
| id|nama|kelas|nilai|
+---+----+-----+-----+
| 4|Dewi| 10B| 92|
+---+----+-----+-----+
=== withColumn status ===
+---+-----+-----+-----+--------+
| id| nama|kelas|nilai| status|
+---+-----+-----+-----+--------+
| 1| Ali| 10A| 85| lulus|
| 2| Budi| 10A| 90| lulus|
| 3|Citra| 10B| 78|remedial|
| 4| Dewi| 10B| 92| lulus|
+---+-----+-----+-----+--------+Bagian pertama keluaran menunjukkan bahwa select tidak harus menyalin kolom apa adanya. Ekspresi df["nilai"] + 5 dihitung untuk setiap baris lalu hasilnya diberi nama nilai_plus melalui .alias(). Nama hasil ekspresi harus diberi secara sadar, karena tanpa .alias() Spark menamainya dengan teks ekspresinya sendiri yang panjang dan sulit dirujuk.
filter: menyaring baris dengan kondisi#
Metode filter menerima ekspresi kolom yang bernilai benar atau salah, lalu menyimpan baris yang nilainya benar. Kondisi majemuk dirakit dengan operator & untuk “dan”, | untuk “atau”, dan ~ untuk “tidak”, sedangkan kata kunci Python and, or, dan not tidak bekerja pada objek Column. Setiap kondisi yang digabung wajib diberi tanda kurung, karena & dan | memiliki urutan pengerjaan yang lebih tinggi daripada operator perbandingan pada Python. Bentuk (df["kelas"] == "10B") & (df["nilai"] >= 90) tanpa tanda kurung pembungkus tiap kondisi terbaca sebagai ekspresi yang salah dan memunculkan error yang sulit ditafsirkan.
Hasil pada keluaran memperlihatkan perbedaan kedua penyaringan. Kondisi tunggal df["nilai"] >= 85 menyisakan tiga baris, sedangkan kondisi majemuk menambah syarat kelas 10B sehingga hanya satu baris tersisa. Metode where adalah nama alternatif untuk filter dengan perilaku yang persis sama, dan keduanya dapat dipakai sesuai kebiasaan penulis kode.
withColumn: menambah kolom hasil perhitungan#
Metode withColumn(nama, ekspresi) menambahkan kolom baru, atau mengganti kolom lama apabila namanya sudah ada, pada setiap baris. Pada skrip di atas, kolom status dibangun dari fungsi F.when(...).otherwise(...) yang mengevaluasi kondisi per baris, sehingga menjadi padanan percabangan di dalam ekspresi kolom. Rantai when dapat disambung beberapa kali untuk banyak cabang, dan cabang terakhir sebaiknya ditutup dengan otherwise agar tidak ada baris yang tanpa sengaja bernilai NULL.
Perbedaannya dengan select terletak pada keluarannya. Metode select menghasilkan DataFrame yang hanya berisi kolom yang disebutkan, sedangkan withColumn mempertahankan seluruh kolom lama dan menambah satu kolom. Aturan praktisnya, select dipakai ketika bentuk akhir DataFrame ingin disusun ulang, dan withColumn dipakai ketika kolom tambahan diperlukan di samping kolom yang sudah ada.
Kedua metode juga membawa perbedaan efisiensi pembacaan pada data besar. select yang hanya menyebut kolom yang diperlukan mempersempit kolom yang dibaca dari penyimpanan berformat kolom seperti Parquet, sehingga jumlah data yang diangkat dari berkas berkurang. Sementara itu, withColumn tetap membawa semua kolom lama sampai tahap penyusunan akhir. Kebiasaan menyaring kolom sejak awal rantai transformasi karenanya bukan sekadar gaya, melainkan bagian dari efisiensi bacaan, dan topik Parquet secara mendalam mengulang hal ini dari sisi penyimpanan.
Kesalahan umum#
Kesalahan pertama adalah memakai and dan or Python pada kondisi DataFrame. Ekspresi df["a"] > 1 and df["b"] < 2 gagal dengan error yang menyebut kebenaran dari sebuah Column tidak terdefinisi, karena kebenaran hanya dapat dievaluasi per baris di dalam mesin Spark, bukan di sisi Python. Perbaikannya adalah memakai & dan | lengkap dengan tanda kurung pada setiap kondisi.
Kesalahan kedua adalah mengira select dan withColumn mengubah DataFrame asal. Keduanya mengembalikan DataFrame baru, sehingga hasilnya harus disimpan ke variabel, misalnya dengan_status = df.withColumn(...). Pola menyimpan ke variabel baru juga menjaga rantai transformasi tetap terbaca.
Kesalahan ketiga adalah membiarkan kolom hasil ekspresi tanpa .alias(). Nama otomatis dari Spark berupa teks ekspresi yang panjang, dan rujukan kolom tersebut pada transformasi berikutnya menjadi rapuh. Selalu beri nama hasil ekspresi secara eksplisit.
Ringkasan#
- Ekspresi kolom adalah objek
Columnyang mendeskripsikan perhitungan per baris dan menjadi bahasa bersama bagiselect,filter, danwithColumn. selectmenyusun kolom keluaran,filtermenyaring baris dengan ekspresi bernilai benar atau salah, danwithColumnmenambah atau mengganti satu kolom tanpa membuang kolom lain.- Kondisi majemuk memakai
&,|, dan~dengan tanda kurung pada setiap kondisi, bukanand,or, dannotmilik Python. - Semua transformasi mengembalikan DataFrame baru, sehingga hasilnya disimpan ke variabel sebelum dipakai.
Referensi#
- pyspark.sql.DataFrame — Apache Spark — Referensi metode select, filter, where, dan withColumn.
- pyspark.sql.functions — Apache Spark — Daftar fungsi kolom, termasuk when, otherwise, dan col.
- pyspark.sql.Column — Apache Spark — Referensi operator yang dapat dipakai pada ekspresi kolom.