나는 매우 큰 Pandas DataFrame을 다루고 있습니다. 내 데이터 세트는 다음 df
설정 과 유사합니다 .
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
)
참고 : 최소한의 예를 들기 위해 쉽게 서브 세트를 사용할 수 있지만 (예 :) df.loc[df['time'] <= 400, :]
어쨌든 데이터를 시뮬레이션하기 때문에 원래 크기가 더 나은 개요를 제공한다고 생각했습니다.
에 의해 정의 된 각 그룹에 ['measurement_id', 'time', 'group']
대해 다음 함수를 호출해야합니다.
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 )
성능을 향상시키기 위해 두 가지 접근 방식을 시도했습니다.
판다 렐렐 패키지
첫 번째 방법은 pandarallel
패키지를 사용하여 계산을 병렬화하는 것이 었습니다 .
pandarallel.initialize( progress_bar = True )
df \
.groupby( ['measurement_id', 'time', 'group'] ) \
.parallel_apply( lambda x: cluster( x['var'], x['object'] ) )
그러나 이것은 많은 RAM을 소비하고 계산에 모든 코어가 사용되는 것은 아니기 때문에 (최소한 pandarallel.initialize()
방법 으로 코어 수를 지정하더라도) 차선책으로 보입니다 . 또한 때로는 여러 가지 오류로 계산이 종료되지만 그 이유를 찾을 수있는 기회는 없었지만 (RAM이 부족할 수 있습니까?)
PySpark Pandas UDF
Spark에 완전히 익숙하지는 않지만 Spark Pandas UDF도 사용했습니다. 내 시도는 다음과 같습니다.
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()
불행히도 성능도 만족스럽지 못했고 주제에서 읽은 내용은 Python으로 작성된 UDF 함수를 사용하고 모든 Python 객체를 Spark 객체로 변환 해야하는 부담이있을 수 있습니다.
내 질문은 다음과 같습니다.
- 병목 현상을 제거하고 성능을 개선하기 위해 내 접근 방식 중 하나를 조정할 수 있습니까? (예 : PySpark 설정, 최적이 아닌 작업 조정 등)
- 더 나은 대안이 있습니까? 성능 측면에서 제공된 솔루션과 어떻게 비교됩니까?
dask
((내 의견은 연구를위한 조언