【发布时间】:2015-06-17 12:55:20
【问题描述】:
我有一个大熊猫数据框(100 万行),我的代码需要更好的性能来处理这些数据。
下面是我的代码,也提供了profiling分析。
数据集的标题:
key_id, date, par1, par2, par3, par4, pop, price, value
对于每个键,我们有一行包含 5000 个可能的日期中的每一个
有 200 个 key_id * 5000 个日期 = 1000000 行
使用不同的变量 var1, ..., var4,我为每一行计算一个值,我想为每个 key_id 提取具有最佳值的前 20 个日期,然后计算所用变量集的流行度。
最后,我想找到优化这种受欢迎程度的变量。
def compute_value_col(dataset, val1=0, val2=0, val3=0, val4=0):
dataset['value'] = dataset['price'] + val1 * dataset['par1'] \
+ val2 * dataset['par2'] + val3 * dataset['par3'] \
+ val4 * dataset['par4']
return dataset
def params_to_score(dataset, top=10, val1=0, val2=0, val3=0, val4=0):
dataset = compute_value_col(dataset, val1, val2, val3, val4)
dataset = dataset.sort(['key_id','value'], ascending=True)
dataset = dataset.groupby('key_id').head(top).reset_index(drop=True)
return dataset['pop'].sum()
def optimize(dataset, top):
for i,j,k,l in product(xrange(10),xrange(10),xrange(10),xrange(10)):
print i, j, k, l, params_to_score(dataset, top, 10*i, 10*j, 10*k, 10*l)
optimize(my_dataset, 20)
我需要提高性能
这是运行 49 params_to_score 后的 %prun 输出
ncalls tottime percall cumtime percall filename:lineno(function)
98 2.148 0.022 2.148 0.022 {pandas.algos.take_2d_axis1_object_object}
49 1.663 0.034 9.852 0.201 <ipython-input-59-88fc8127a27f>:150(params_to_score)
49 1.311 0.027 1.311 0.027 {method 'get_labels' of 'pandas.hashtable.Float64HashTable' objects}
49 1.219 0.025 1.223 0.025 {pandas.algos.groupby_indices}
49 0.875 0.018 0.875 0.018 {method 'get_labels' of 'pandas.hashtable.PyObjectHashTable' objects}
147 0.452 0.003 0.457 0.003 index.py:581(is_unique)
343 0.193 0.001 0.193 0.001 {method 'copy' of 'numpy.ndarray' objects}
1 0.136 0.136 10.058 10.058 <ipython-input-59-88fc8127a27f>:159(optimize)
147 0.122 0.001 0.122 0.001 {method 'argsort' of 'numpy.ndarray' objects}
833 0.112 0.000 0.112 0.000 {numpy.core.multiarray.empty}
49 0.109 0.002 0.109 0.002 {method 'get_labels_groupby' of 'pandas.hashtable.Int64HashTable' objects}
98 0.083 0.001 0.083 0.001 {pandas.algos.take_2d_axis1_float64_float64}
49 0.078 0.002 1.460 0.030 groupby.py:1014(_cumcount_array)
我想我可以通过 key_id 将大数据帧拆分为小数据帧,以缩短排序时间,因为我想为每个 key_id 取前 20 个具有最佳值的日期,所以按键排序只是为了分隔不同的键.
但我需要任何建议,因为我需要运行数千个 params_to_score,我该如何提高此代码的效率?
编辑:@杰夫
非常感谢您的帮助!
我尝试使用 nsmallest 代替 sort & head,但奇怪的是,当我对以下两个函数进行基准测试时,它慢了 5-6 倍:
def to_bench1(dataset):
dataset = dataset.sort(['key_id','value'], ascending=True)
dataset = dataset.groupby('key_id').head(50).reset_index(drop=True)
return dataset['pop'].sum()
def to_bench2(dataset):
dataset = dataset.set_index('pop')
dataset = dataset.groupby(['key_id'])['value'].nsmallest(50).reset_index()
return dataset['pop'].sum()
在大约 100000 行的样本中,to_bench2 的执行时间为 0.5 秒,而 to_bench1 平均只需 0.085 秒。
在分析 to_bench2 后,我注意到与以前相比,isinstance 调用更多,但我不知道它们来自哪里......
【问题讨论】:
-
样本数据在这里会有所帮助,不必很大,但要足够大以比较不同方法的效率。
标签: python performance pandas profiling dataframe