Oldukça büyük Pandalar DataFrame ile uğraşıyorum - veri setim aşağıdaki df
düzene benziyor :
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
)
Not: Minimum bir örneğe sahip olmak amacıyla, kolayca alt gruplara ayrılabilir (örneğin ile df.loc[df['time'] <= 400, :]
), ancak yine de verileri simüle ettiğim için orijinal boyutun daha iyi bir genel bakış sağlayacağını düşündüm.
Tarafından tanımlanan her grup ['measurement_id', 'time', 'group']
için aşağıdaki işlevi çağırmak gerekir:
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 )
Performansı artırmak için iki yaklaşım denedim:
Panda paralel paket
İlk yaklaşım hesaplamaları pandarallel
paket kullanarak paralelleştirmekti :
pandarallel.initialize( progress_bar = True )
df \
.groupby( ['measurement_id', 'time', 'group'] ) \
.parallel_apply( lambda x: cluster( x['var'], x['object'] ) )
Bununla birlikte, çok fazla RAM tükettiği ve hesaplamalarda tüm çekirdekler kullanılmadığı için ( pandarallel.initialize()
yöntemde açıkça çekirdeklerin sayısını belirtmesine rağmen), bu durumun optimal olmadığı görülmektedir . Ayrıca, bunun için bir neden bulma şansım olmasa da, bazen hesaplamalar çeşitli hatalarla sonlandırılır (muhtemelen RAM eksikliği?).
PySpark Pandalar UDF
Spark için tamamen yeni olmama rağmen bir Spark Pandas UDF de verdim. İşte benim girişimim:
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()
Ne yazık ki, performans da tatmin edici değildi ve bu konuda okuduğumdan, bu sadece Python'da yazılmış UDF işlevini kullanmanın yükü ve tüm Python nesnelerini Spark nesnelerine ve geri dönüştürmeye ilişkin ihtiyaç olabilir.
Sorularım işte burada:
- Her iki yaklaşımım da olası darboğazları ortadan kaldıracak ve performansı artıracak şekilde ayarlanabilir mi? (örn. PySpark kurulumu, alt optimal işlemleri ayarlama vb.)
- Daha iyi bir alternatif var mı? Performans açısından sağlanan çözümlerle nasıl kıyaslanıyorlar?
dask
(((bu yüzden benim yorumum sadece araştırma için tavsiye.)