ฉันกำลังจัดการกับ 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
แพคเกจ:
pandarallel.initialize( progress_bar = True )
df \
.groupby( ['measurement_id', 'time', 'group'] ) \
.parallel_apply( lambda x: cluster( x['var'], x['object'] ) )
อย่างไรก็ตามสิ่งนี้ดูเหมือนว่าจะเหมาะสมที่สุดเนื่องจากมันกินแรมจำนวนมากและไม่ได้ใช้คอร์ทั้งหมดในการคำนวณ (แม้จะระบุจำนวนของคอร์อย่างชัดเจนในpandarallel.initialize()
เมธอด) นอกจากนี้บางครั้งการคำนวณก็สิ้นสุดลงด้วยข้อผิดพลาดต่าง ๆ ถึงแม้ว่าฉันจะไม่มีโอกาสค้นพบเหตุผลสำหรับสิ่งนั้น (อาจเป็นเพราะขาด RAM?)
UDF ของ PySpark Pandas
ฉันให้ Spark Pandas UDF ไปด้วยแม้ว่าฉันจะยังใหม่กับ Spark ก็ตาม นี่คือความพยายามของฉัน:
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()
น่าเสียดายที่ประสิทธิภาพไม่น่าพอใจเช่นกันและจากสิ่งที่ฉันอ่านในหัวข้อนี้อาจเป็นเพียงภาระของการใช้ฟังก์ชั่น UDF ที่เขียนใน Python และความต้องการที่เกี่ยวข้องในการแปลงวัตถุ Python ทั้งหมดให้เป็นวัตถุ Spark และย้อนกลับ
ดังนั้นนี่คือคำถามของฉัน:
- ฉันสามารถปรับวิธีใดวิธีหนึ่งเพื่อกำจัดปัญหาคอขวดที่เป็นไปได้และปรับปรุงประสิทธิภาพได้หรือไม่ (เช่นการตั้งค่า PySpark การปรับการทำงานย่อยให้เหมาะสมเป็นต้น)
- พวกเขามีทางเลือกที่ดีกว่านี้อีกไหม? พวกเขาเปรียบเทียบกับโซลูชั่นที่ให้มาในแง่ของประสิทธิภาพได้อย่างไร
dask
(((ดังนั้นความคิดเห็นของฉันมันเป็นเพียงคำแนะนำสำหรับการวิจัย