Pendahuluan
Pandas adalah pustaka Python yang sangat baik untuk manipulasi dan analisis data, menyediakan struktur data dan fungsi yang diperlukan untuk bekerja dengan data terstruktur. Meskipun Pandas dikenal karena fleksibilitas dan kemudahannya dalam penggunaan, namun dapat mengalami masalah performa saat menangani dataset yang besar. Untuk mengatasi keterbatasan ini, penting untuk memahami dan menerapkan teknik optimisasi pada alur kerja Pandas Anda.
Pengambilan Data yang Efisien
Pengambilan data yang efisien merupakan aspek penting dalam mengoptimalkan alur kerja Pandas. Untuk mengoptimalkan performa, pengguna harus dengan cermat memilih jenis data untuk setiap kolom, mengelola penggunaan memori, dan, jika perlu, menggunakan chunking dan iterasi untuk memproses data dalam bagian yang lebih kecil.
Jenis Data dan Manajemen Memori
Saat memuat data, Pandas secara otomatis menyimpulkan jenis data untuk setiap kolom berdasarkan data input. Namun, proses ini terkadang dapat menghasilkan hasil yang suboptimal, seperti memuat kolom yang berisi bilangan bulat sebagai float64 dtype, yang mengonsumsi lebih banyak memori.
Untuk mengoptimalkan penggunaan memori dan meningkatkan performa, Anda dapat secara eksplisit menentukan jenis data untuk setiap kolom dengan menggunakan parameter dtype
saat membaca data.
import pandas as pd
# Menentukan jenis data untuk setiap kolom
data = pd.read_csv('data.csv', dtype={'column1': 'int32', 'column2': 'category'})
Chunking dan Iterasi
Ketika bekerja dengan dataset yang besar, memuat seluruh data ke dalam memori mungkin tidak layak. Dalam kasus seperti ini, Anda dapat menggunakan parameter chunksize
untuk memproses data dalam bagian yang lebih kecil atau "chunk". Pendekatan ini memungkinkan Anda untuk mengiterasi dataset dan melakukan operasi pada setiap chunk secara terpisah, mengurangi jejak memori.
import pandas as pd
# Membaca data dalam chunk
chunk_size = 1000
data_reader = pd.read_csv('large_data.csv', chunksize=chunk_size)
for chunk in data_reader:
# Melakukan operasi pada setiap chunk
print(chunk.head())
Dengan memproses data dalam chunk yang lebih kecil, Anda dapat melakukan operasi pada dataset yang besar tanpa kehabisan memori. Namun, penting untuk diingat bahwa beberapa operasi, seperti pengurutan dan pengelompokan, mungkin memerlukan langkah atau teknik tambahan untuk memproses data secara efisien dalam chunk.
Peningkatan Performa
Peningkatan performa dapat dicapai melalui vektorisasi, yang melibatkan melakukan operasi pada seluruh array daripada secara berurutan. Metode ini memanfaatkan optimasi tingkat rendah dan menghindari overhead dari loop Python. Selain vektorisasi, pengguna dapat memanfaatkan fungsi NumPy dan metode bawaan Pandas, seperti method chaining, untuk meningkatkan performa.
Vektorisasi
Vektorisasi merujuk pada praktik melakukan operasi pada seluruh array atau struktur data, bukan melalui iterasi elemen satu per satu. Teknik ini memungkinkan Pandas untuk memanfaatkan optimasi tingkat rendah, termasuk optimasi yang disediakan oleh pustaka NumPy yang mendasari, untuk mencapai kinerja yang jauh lebih baik.
Dalam Pandas, operasi vektorisasi dapat dilakukan dengan menggunakan fungsi dan metode bawaan yang disediakan untuk objek Series dan DataFrame. Operasi ini meliputi operasi aritmatika, perbandingan, dan logika.
import pandas as pd
data = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
result = data * 2 # Perkalian vektorisasi
Menggunakan Fungsi NumPy
NumPy adalah pustaka yang kuat untuk komputasi numerik dalam Python dan merupakan dasar bagi Pandas. Dengan memanfaatkan fungsi NumPy, dapat meningkatkan performa operasi Pandas. Banyak fungsi NumPy yang kompatibel dengan objek Series dan DataFrame Pandas, memungkinkan integrasi yang mulus antara dua pustaka.
import numpy as np
import pandas as pd
data = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
result = np.sqrt(data) # Menerapkan fungsi akar kuadrat pada setiap elemen
Data Kategoris
Data kategoris, seperti string atau faktor, dapat disimpan dan dimanipulasi secara efisien menggunakan tipe data Categorical Pandas. Tipe data Categorical menyimpan data sebagai bilangan bulat dengan pemetaan nilai bilangan bulat yang terpisah ke label kategori, yang dapat secara signifikan mengurangi penggunaan memori dan meningkatkan performa, terutama untuk operasi seperti pengurutan, pengelompokan, dan penggabungan.
import pandas as pd
data = pd.Series(['apple', 'banana', 'apple', 'orange'], dtype='category')
Method Chaining
Method chaining adalah teknik pemrograman yang kuat yang memungkinkan Anda melakukan beberapa operasi pada struktur data dalam satu pernyataan yang singkat dan ringkas. Dalam Pandas, banyak metode DataFrame dan Series mengembalikan objek baru, yang dapat dimodifikasi atau diubah dengan panggilan metode tambahan.
Dengan menggunakan method chaining, dapat mengurangi jumlah variabel perantara dalam kode Anda, membuatnya lebih mudah dibaca dan efisien. Teknik ini juga dapat meningkatkan performa dengan mengurangi kebutuhan untuk membuat beberapa objek sementara selama pengolahan data Anda.
import pandas as pd
data = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
result = (
data.assign(C=lambda df: df['A'] * 2)
.query('C > 3')
.sort_values(by='C', ascending=False)
)
Dalam contoh ini, kita membuat kolom baru 'C', menyaring baris yang memiliki nilai 'C' lebih besar dari 3, dan mengurutkan baris yang tersisa berdasarkan kolom 'C' secara menurun, semuanya dalam satu pernyataan.
Pemrosesan Paralel
Pemrosesan paralel dapat secara signifikan meningkatkan performa saat bekerja dengan dataset besar. Pustaka seperti Dask dan Swifter dapat digunakan untuk memparalelkan operasi Pandas, sedangkan modul multiprocessing
di pustaka standar Python juga dapat digunakan untuk mendistribusikan beban kerja di beberapa proses.
Menggunakan Dask untuk Pemrosesan Paralel
Dask adalah pustaka komputasi paralel yang fleksibel untuk Python yang dapat digunakan untuk memparalelkan operasi Pandas. Dask menyediakan Dask DataFrame, yang merupakan DataFrame paralel besar yang terdiri dari DataFrame Pandas yang lebih kecil, dibagi menjadi indeks. Dask DataFrame meniru API Pandas, sehingga mudah untuk memperbesar alur kerja Pandas Anda ke dataset yang lebih besar.
import dask.dataframe as dd
# Read data into a Dask DataFrame
dask_data = dd.read_csv('large_data.csv')
# Perform operations on the Dask DataFrame
result = dask_data.groupby('column1').mean()
# Compute the result and return a Pandas DataFrame
result_pd = result.compute()
Menggunakan Swifter untuk Operasi Dipercepat
Swifter adalah pustaka yang bertujuan untuk secara efisien menerapkan fungsi apa pun yang diberikan ke DataFrame atau Series Pandas. Ini dicapai dengan secara otomatis memilih strategi optimal, baik vektorisasi atau pemrosesan paralel dengan Dask, berdasarkan data dan fungsi masukan. Swifter dapat signifikan meningkatkan performa operasi yang tidak secara alami divektorisasi di Pandas, seperti fungsi khusus yang diterapkan menggunakan metode apply
.
import pandas as pd
import swifter
data = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
# Mendefinisikan fungsi khusus untuk mengkuadratkan nilai masukan
def square(x):
return x**2
# Menerapkan fungsi khusus menggunakan Swifter
data['C'] = data['A'].swifter.apply(square)
Multiprocessing dengan Pandas
Pustaka standar Python, yaitu modul multiprocessing
, dapat digunakan untuk memparalelkan operasi Pandas dengan mendistribusikan beban kerja di beberapa proses. Pendekatan ini dapat sangat berguna untuk tugas yang membutuhkan banyak komputasi, seperti menerapkan fungsi khusus pada dataset besar.
import pandas as pd
from multiprocessing import Pool, cpu_count
data = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
# Mendefinisikan fungsi khusus untuk mengkuadratkan nilai masukan
def square(x):
return x**2
# Memecah data menjadi beberapa bagian untuk pemrosesan paralel
num_partitions = cpu_count() # Jumlah core CPU
num_cores = cpu_count()
data_split = np.array_split(data, num_partitions)
# Define a function to apply the custom function to each chunk
def process_data(data_chunk):
return data_chunk['A'].apply(square)
# Paralelkan operasi menggunakan multiprocessing
with Pool(num_cores) as pool:
results = pool.map(process_data, data_split)
# Menggabungkan hasil menjadi satu DataFrame Pandas
data['C'] = pd.concat(results)