前几天的文章,咱们曾经简略的介绍过Pandas 和Polars的速度比照。刚刚公布的Pandas 2.0速度失去了显著的晋升。然而本次测试发现NumPy数组上的一些基本操作依然更快。并且Polars 0.17.0,也在上周公布,并且也提到了性能的改善,所以咱们这里做一个更具体的对于速度方面的评测。
本文将比拟Pandas 2.0(应用Numpy和Pyarrow作为后端)和Polars 0.17.0的速度。并且介绍应用Polars库复现一些简略到简单的Pandas代码,这样也算是对Polars的一个简略介绍。另外测试将在4 cpu和32 GB RAM上进行。
装置
能够通过pip命令进行装置
pipinstallpolars==0.17.0# Latest version pipinstallpandas==2.0.0 # Latest pandas version
咱们须要应用上面的库:
importpandasaspd importpolarsaspl importnumpyasnp importtime
为了评估性能,咱们将应用一个由3000万行和15列组成的合成数据集。该数据集由8个分类特色和7个数字特色组成,是人工生成的。数据集的链接在最初会提供。
上面显示了该数据集的一个示例
读取数据集
比拟两个库读取parquet文件的工夫。我应用了上面的代码,并应用%%time来获取代码执行的工夫。
train_pd=pd.read_parquet('./train.parquet') #Pandas dataframe train_pl=pl.read_parquet('./train.parquet') #Polars dataframe
能够看到Polars和Pandas 2.0在速度方面体现类似(因为都是arrow)然而Pandas(应用Numpy后端)须要两倍的工夫来实现这个工作(这可能是因为有类型转换的起因,因为最终要把类型转成np的类型)。
聚合操作
上面的代码,该代码计算聚合(最小值、最大值、平均值)。
# pandas query train_pd[nums].agg(['min','max','mean','median','std') train[cats].agg(['nunique']) # Polars query train_pl.with_columns([ pl.col(nums).min().suffix('_min'), pl.col(nums).max().suffix('_max'), pl.col(nums).mean().suffix('_mean'), pl.col(nums).median().suffix('_median'), pl.col(nums).std().suffix('_std'), pl.col(cats).nunique().suffix('_unique'), ])
对于简略的聚合,Pandas在语法和性能方面会更好,然而差距并不大。
筛选操作
抉择操作波及依据条件进行查问和提取,例如上面代码
查问1:当nums_8小于10时,统计惟一值。
# Polars filter and select train_pl.filter(pl.col("num_8") <=10).select(pl.col(cats).n_unique()) # Pandas filter and select train_pd[train_pd['num_8']<=10][cats].nunique()
查问2:当cat_1 = 1时,计算所有数值列的平均值。
# Polars filter and select train_pl.filter(pl.col("cat_1") ==1).select(pl.col(nums).mean()) # Pandas filter and select train_pd[train_pd['cat_1']==1][nums].mean()
两个查问的后果如下:
在性能方面,Polars的数值filter速度要快2-5倍,而Pandas须要编写的代码更少。Pandas在解决字符串(分类特色)时速度较慢,这个咱们在以前的文章中曾经提到过,并且应用df.query函数在语法上更简洁,并且在大数据量的状况下会更快,这个如果有人有趣味,咱们再独自总结。
分组操作
分组操作是机器学习中用于创立聚合特色的基本操作之一,我在上面的通过user进行分组后,进行聚合来测试性能
函数1:统计cat_1的聚合特色
函数2:num_7的均值特色
函数3:所有数值列的均匀聚合特色
函数4:计算分类列的聚合个性
nums=['num_7','num_8', 'num_9', 'num_10', 'num_11', 'num_12', 'num_13', 'num_14','num_15'] cats=['cat_1', 'cat_2', 'cat_3', 'cat_4', 'cat_5', 'cat_6'] # Pandas Functions Function_1=train_pd.groupby(['user'])['cat_1'].agg('count') #Function 1 Function_2=train_pd.groupby(['user'])['num_7'].agg('mean') #Function 2 Function_3=train_pd.groupby(['user'])[nums].agg('mean') #Function 3 Function_4=train_pd.groupby(['user'])[cats].agg('count') #Function 4 # Polars Functions Function_1=train_pl.groupby('user').agg(pl.col('cat_1').count()) #Function 1 Function_2=train_pl.groupby('user').agg(pl.col('num_7').mean()) #Function 2 Function_3=train_pl.groupby('user').agg(pl.col(nums).mean()) #Function 3 Function_4=train_pl.groupby('user').agg(pl.col(cats).count()) #Function 4
能够看到Polars十分快。然而Pyarrow后端的Pandas 2.0在所有状况下都显著比Polars和Pandas 2.0 (numpy后端)慢。
咱们将分组变量的数量从1减少到5,看看后果:
# PANDAS: TESTING GROUPING SPEED ON 5 COLUMNS forcatin ['user', 'cat_1', 'cat_2', 'cat_3', 'cat_4']: cols+=[cat] st=time.time() temp=train_pd.groupby(cols)['num_7'].agg('mean') en=time.time() print(cat,':',en-st) # POLARS: TESTING GROUPING SPEED ON 5 COLUMNS forcatin ['user', 'cat_1', 'cat_2', 'cat_3', 'cat_4']: cols+=[cat] st=time.time() temp=train_pl.groupby(cols).agg(pl.col('num_7').mean()) en=time.time() print(cat,':',en-st) deltemp
下图中没有显示Pyarrow的Pandas 2.0,因为求值须要1000多秒。
对于group操作来说Polars是首选,然而Pandas在分组时默认删除空值,而Polars库则不会,这是一个小小的差别,在应用时须要留神。
排序操作
上面的代码,能够基于一个或多个列(升序或降序)疾速对数据进行排序。
cols=['user','num_8'] # columns to be used for sorting #Sorting in Polars train_pl.sort(cols,descending=False) # Sorting in Pandas train_pd.sort_values(by=cols,ascending=True)
从上图能够看出,对于排序和分组等简单状况,Polars依然是最快的库。Pandas对数据进行简略排序须要几分钟的工夫,但在polar中,简单的排序函数能够在不超过15秒的工夫内计算出来。
总结
本文对Pandas和polar之间性能差别做了一个比照总结。Pandas在语法上更有吸引力(因为用的多习惯了),而Polars在解决更大的数据时提供了更好的吞吐量。
然而因为Polars是一个较新的库,从Pandas过渡到其余库具是有挑战性的。通过理解这两种弱小工具之间的差别,咱们能够依据本人的特定需要抉择最佳选项,并实现更高效和无效的数据分析。
本文的数据下载:
https://avoid.overfit.cn/post/9d617b39040441e39433fc906cafefc9
作者:Priyanshu Chaudhary