Saya berurusan dengan Pandas DataFrame yang cukup besar - dataset saya menyerupai df
pengaturan berikut :
import pandas as pd
import numpy as np
#--------------------------------------------- SIZING PARAMETERS :
R1 = 20 # .repeat( repeats = R1 )
R2 = 10 # .repeat( repeats = R2 )
R3 = 541680 # .repeat( repeats = [ R3, R4 ] )
R4 = 576720 # .repeat( repeats = [ R3, R4 ] )
T = 55920 # .tile( , T)
A1 = np.arange( 0, 2708400, 100 ) # ~ 20x re-used
A2 = np.arange( 0, 2883600, 100 ) # ~ 20x re-used
#--------------------------------------------- DataFrame GENERATION :
df = pd.DataFrame.from_dict(
{ 'measurement_id': np.repeat( [0, 1], repeats = [ R3, R4 ] ),
'time':np.concatenate( [ np.repeat( A1, repeats = R1 ),
np.repeat( A2, repeats = R1 ) ] ),
'group': np.tile( np.repeat( [0, 1], repeats = R2 ), T ),
'object': np.tile( np.arange( 0, R1 ), T )
}
)
#--------------------------------------------- DataFrame RE-PROCESSING :
df = pd.concat( [ df,
df \
.groupby( ['measurement_id', 'time', 'group'] ) \
.apply( lambda x: np.random.uniform( 0, 100, 10 ) ) \
.explode() \
.astype( 'float' ) \
.to_frame( 'var' ) \
.reset_index( drop = True )
], axis = 1
)
Catatan: Untuk tujuan memiliki contoh minimal, dapat dengan mudah dimasukkan kembali (misalnya dengan df.loc[df['time'] <= 400, :]
), tetapi karena saya mensimulasikan data, saya pikir ukuran aslinya akan memberikan gambaran yang lebih baik.
Untuk setiap grup yang ditentukan oleh ['measurement_id', 'time', 'group']
saya perlu memanggil fungsi berikut:
from sklearn.cluster import SpectralClustering
from pandarallel import pandarallel
def cluster( x, index ):
if len( x ) >= 2:
data = np.asarray( x )[:, np.newaxis]
clustering = SpectralClustering( n_clusters = 5,
random_state = 42
).fit( data )
return pd.Series( clustering.labels_ + 1, index = index )
else:
return pd.Series( np.nan, index = index )
Untuk meningkatkan kinerja saya mencoba dua pendekatan:
Paket pandarallel
Pendekatan pertama adalah memparalelkan perhitungan menggunakan pandarallel
paket:
pandarallel.initialize( progress_bar = True )
df \
.groupby( ['measurement_id', 'time', 'group'] ) \
.parallel_apply( lambda x: cluster( x['var'], x['object'] ) )
Namun, ini tampaknya kurang optimal karena mengkonsumsi banyak RAM dan tidak semua core digunakan dalam perhitungan (bahkan meskipun menentukan jumlah core secara eksplisit dalam pandarallel.initialize()
metode ini). Juga, kadang-kadang perhitungan diakhiri dengan berbagai kesalahan, walaupun saya belum punya kesempatan untuk menemukan alasan untuk itu (mungkin kekurangan RAM?).
PySpark Pandas UDF
Saya juga mencoba Spark Pandas UDF, meskipun saya benar-benar baru di Spark. Inilah usaha saya:
import findspark; findspark.init()
from pyspark.sql import SparkSession
from pyspark.conf import SparkConf
from pyspark.sql.functions import pandas_udf, PandasUDFType
from pyspark.sql.types import *
spark = SparkSession.builder.master( "local" ).appName( "test" ).config( conf = SparkConf() ).getOrCreate()
df = spark.createDataFrame( df )
@pandas_udf( StructType( [StructField( 'id', IntegerType(), True )] ), functionType = PandasUDFType.GROUPED_MAP )
def cluster( df ):
if len( df['var'] ) >= 2:
data = np.asarray( df['var'] )[:, np.newaxis]
clustering = SpectralClustering( n_clusters = 5,
random_state = 42
).fit( data )
return pd.DataFrame( clustering.labels_ + 1,
index = df['object']
)
else:
return pd.DataFrame( np.nan,
index = df['object']
)
res = df \
.groupBy( ['id_half', 'frame', 'team_id'] ) \
.apply( cluster ) \
.toPandas()
Sayangnya, kinerjanya juga tidak memuaskan, dan dari apa yang saya baca pada topik, ini mungkin hanya beban menggunakan fungsi UDF, yang ditulis dalam Python dan kebutuhan terkait untuk mengubah semua objek Python menjadi objek Spark dan kembali.
Jadi inilah pertanyaanku:
- Bisakah salah satu pendekatan saya disesuaikan untuk menghilangkan kemungkinan kemacetan dan meningkatkan kinerja? (misalnya pengaturan PySpark, menyesuaikan operasi sub-optimal, dll.)
- Apakah ada alternatif yang lebih baik? Bagaimana mereka membandingkan dengan solusi yang disediakan dalam hal kinerja?
dask
(((jadi komentar saya itu hanya saran untuk penelitian.