关于python:提高Pandas合并性能 |
您所在的位置:网站首页 › 大学生看的书推荐小说 › 关于python:提高Pandas合并性能 |
正如其他帖子所建议的那样,我特别不喜欢Pands Merge的性能问题,但是我有一个类,其中包含许多方法,这些方法对数据集进行了大量合并。 该班级大约有10个分组依据,大约15个合并。尽管groupby相当快,但在类的总执行时间为1.5秒的情况下,在这15个merge调用中大约为0.7秒。 我想在那些合并调用中提高性能。由于我将进行约4000次迭代,因此在单次迭代中总共节省了0.5秒,这将导致整体性能降低30分钟左右,这非常好。 有什么建议我应该尝试吗?我试过了: 赛顿 Numba和Numba较慢。 谢谢 编辑1: 添加示例代码段: 我的合并语句: 12345678910111213tmpDf = pd.merge(self.data, t1, on='APPT_NBR', how='left') tmp = tmpDf tmpDf = pd.merge(tmp, t2, on='APPT_NBR', how='left') tmp = tmpDf tmpDf = pd.merge(tmp, t3, on='APPT_NBR', how='left') tmp = tmpDf tmpDf = pd.merge(tmp, t4, on='APPT_NBR', how='left') tmp = tmpDf tmpDf = pd.merge(tmp, t5, on='APPT_NBR', how='left')并且,通过实现Joins,我合并了以下内容: 123456789101112131415dat = self.data.set_index('APPT_NBR') t1.set_index('APPT_NBR', inplace=True) t2.set_index('APPT_NBR', inplace=True) t3.set_index('APPT_NBR', inplace=True) t4.set_index('APPT_NBR', inplace=True) t5.set_index('APPT_NBR', inplace=True) tmpDf = dat.join(t1, how='left') tmpDf = tmpDf.join(t2, how='left') tmpDf = tmpDf.join(t3, how='left') tmpDf = tmpDf.join(t4, how='left') tmpDf = tmpDf.join(t5, how='left') tmpDf.reset_index(inplace=True)注意,所有这些都是名为def的函数的一部分:def merge_earlier_created_values(self): 而且,当我通过以下方式定时从profilehooks拨打电话时: 12@timedcall(immediate=True) def merge_earlier_created_values(self):我得到以下结果: 该方法的分析结果为: 12@profile(immediate=True) def merge_earlier_created_values(self):通过使用Merge进行功能分析如下: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950*** PROFILER RESULTS *** merge_earlier_created_values (E:\\Projects\\Predictive Inbound Cartoon Estimation-MLO\\Python\\CodeToSubmit\\helpers\\get_prev_data_by_date.py:122) function called 1 times 71665 function calls (70588 primitive calls) in 0.524 seconds Ordered by: cumulative time, internal time, call count List reduced from 563 to 40 due to restriction ncalls tottime percall cumtime percall filename:lineno(function) 1 0.012 0.012 0.524 0.524 get_prev_data_by_date.py:122(merge_earlier_created_values) 14 0.000 0.000 0.285 0.020 generic.py:1901(_update_inplace) 14 0.000 0.000 0.285 0.020 generic.py:1402(_maybe_update_cacher) 19 0.000 0.000 0.284 0.015 generic.py:1492(_check_setitem_copy) 7 0.283 0.040 0.283 0.040 {built-in method gc.collect} 15 0.000 0.000 0.181 0.012 generic.py:1842(drop) 10 0.000 0.000 0.153 0.015 merge.py:26(merge) 10 0.000 0.000 0.140 0.014 merge.py:201(get_result) 8/4 0.000 0.000 0.126 0.031 decorators.py:65(wrapper) 4 0.000 0.000 0.126 0.031 frame.py:3028(drop_duplicates) 1 0.000 0.000 0.102 0.102 get_prev_data_by_date.py:264(recreate_previous_cartons) 1 0.000 0.000 0.101 0.101 get_prev_data_by_date.py:231(recreate_previous_appt_scheduled_date) 1 0.000 0.000 0.098 0.098 get_prev_data_by_date.py:360(recreate_previous_freight_type) 10 0.000 0.000 0.092 0.009 internals.py:4455(concatenate_block_managers) 10 0.001 0.000 0.088 0.009 internals.py:4471() 120 0.001 0.000 0.084 0.001 internals.py:4559(concatenate_join_units) 266 0.004 0.000 0.067 0.000 common.py:733(take_nd) 120 0.000 0.000 0.061 0.001 internals.py:4569() 120 0.003 0.000 0.061 0.001 internals.py:4814(get_reindexed_values) 1 0.000 0.000 0.059 0.059 get_prev_data_by_date.py:295(recreate_previous_appt_status) 10 0.000 0.000 0.038 0.004 merge.py:322(_get_join_info) 10 0.001 0.000 0.036 0.004 merge.py:516(_get_join_indexers) 25 0.001 0.000 0.024 0.001 merge.py:687(_factorize_keys) 74 0.023 0.000 0.023 0.000 {pandas.algos.take_2d_axis1_object_object} 50 0.022 0.000 0.022 0.000 {method 'factorize' of 'pandas.hashtable.Int64Factorizer' objects} 120 0.003 0.000 0.022 0.000 internals.py:4479(get_empty_dtype_and_na) 88 0.000 0.000 0.021 0.000 frame.py:1969(__getitem__) 1 0.000 0.000 0.019 0.019 get_prev_data_by_date.py:328(recreate_previous_location_numbers) 39 0.000 0.000 0.018 0.000 internals.py:3495(reindex_indexer) 537 0.017 0.000 0.017 0.000 {built-in method numpy.core.multiarray.empty} 15 0.000 0.000 0.017 0.001 ops.py:725(wrapper) 15 0.000 0.000 0.015 0.001 frame.py:2011(_getitem_array) 24 0.000 0.000 0.014 0.001 internals.py:3625(take) 10 0.000 0.000 0.014 0.001 merge.py:157(__init__) 10 0.000 0.000 0.014 0.001 merge.py:382(_get_merge_keys) 15 0.008 0.001 0.013 0.001 ops.py:662(na_op) 234 0.000 0.000 0.013 0.000 common.py:158(isnull) 234 0.001 0.000 0.013 0.000 common.py:179(_isnull_new) 15 0.000 0.000 0.012 0.001 generic.py:1609(take) 20 0.000 0.000 0.012 0.001 generic.py:2191(reindex)使用Joins进行的分析如下: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454665079 function calls (63990 primitive calls) in 0.550 seconds Ordered by: cumulative time, internal time, call count List reduced from 592 to 40 due to restriction ncalls tottime percall cumtime percall filename:lineno(function) 1 0.016 0.016 0.550 0.550 get_prev_data_by_date.py:122(merge_earlier_created_values) 14 0.000 0.000 0.295 0.021 generic.py:1901(_update_inplace) 14 0.000 0.000 0.295 0.021 generic.py:1402(_maybe_update_cacher) 19 0.000 0.000 0.294 0.015 generic.py:1492(_check_setitem_copy) 7 0.293 0.042 0.293 0.042 {built-in method gc.collect} 10 0.000 0.000 0.173 0.017 generic.py:1842(drop) 10 0.000 0.000 0.139 0.014 merge.py:26(merge) 8/4 0.000 0.000 0.138 0.034 decorators.py:65(wrapper) 4 0.000 0.000 0.138 0.034 frame.py:3028(drop_duplicates) 10 0.000 0.000 0.132 0.013 merge.py:201(get_result) 5 0.000 0.000 0.122 0.024 frame.py:4324(join) 5 0.000 0.000 0.122 0.024 frame.py:4371(_join_compat) 1 0.000 0.000 0.111 0.111 get_prev_data_by_date.py:264(recreate_previous_cartons) 1 0.000 0.000 0.103 0.103 get_prev_data_by_date.py:231(recreate_previous_appt_scheduled_date) 1 0.000 0.000 0.099 0.099 get_prev_data_by_date.py:360(recreate_previous_freight_type) 10 0.000 0.000 0.093 0.009 internals.py:4455(concatenate_block_managers) 10 0.001 0.000 0.089 0.009 internals.py:4471() 100 0.001 0.000 0.085 0.001 internals.py:4559(concatenate_join_units) 205 0.003 0.000 0.068 0.000 common.py:733(take_nd) 100 0.000 0.000 0.060 0.001 internals.py:4569() 100 0.001 0.000 0.060 0.001 internals.py:4814(get_reindexed_values) 1 0.000 0.000 0.056 0.056 get_prev_data_by_date.py:295(recreate_previous_appt_status) 10 0.000 0.000 0.033 0.003 merge.py:322(_get_join_info) 52 0.031 0.001 0.031 0.001 {pandas.algos.take_2d_axis1_object_object} 5 0.000 0.000 0.030 0.006 base.py:2329(join) 37 0.001 0.000 0.027 0.001 internals.py:2754(apply) 6 0.000 0.000 0.024 0.004 frame.py:2763(set_index) 7 0.000 0.000 0.023 0.003 merge.py:516(_get_join_indexers) 2 0.000 0.000 0.022 0.011 base.py:2483(_join_non_unique) 7 0.000 0.000 0.021 0.003 generic.py:2950(copy) 7 0.000 0.000 0.021 0.003 internals.py:3046(copy) 84 0.000 0.000 0.020 0.000 frame.py:1969(__getitem__) 19 0.001 0.000 0.019 0.001 merge.py:687(_factorize_keys) 100 0.002 0.000 0.019 0.000 internals.py:4479(get_empty_dtype_and_na) 1 0.000 0.000 0.018 0.018 get_prev_data_by_date.py:328(recreate_previous_location_numbers) 15 0.000 0.000 0.017 0.001 ops.py:725(wrapper) 34 0.001 0.000 0.017 0.000 internals.py:3495(reindex_indexer) 83 0.004 0.000 0.016 0.000 internals.py:3211(_consolidate_inplace) 68 0.015 0.000 0.015 0.000 {method 'copy' of 'numpy.ndarray' objects} 15 0.000 0.000 0.015 0.001 frame.py:2011(_getitem_array)您可以看到,合并的速度比联接要快,尽管它的值很小,但是经过4000次迭代,这个小的值在几分钟内变成了一个巨大的数字。 谢谢 相关讨论 将您的合并列设置为索引,并使用df1.join(df2)代替。 合并列上的set_index确实可以加快速度。下面是julien-marrec的Answers的一个更现实的版本。 123456789101112131415161718192021222324import pandas as pd import numpy as np myids=np.random.choice(np.arange(10000000), size=1000000, replace=False) df1 = pd.DataFrame(myids, columns=['A']) df1['B'] = np.random.randint(0,1000,(1000000)) df2 = pd.DataFrame(np.random.permutation(myids), columns=['A2']) df2['B2'] = np.random.randint(0,1000,(1000000)) %%timeit x = df1.merge(df2, how='left', left_on='A', right_on='A2') #1 loop, best of 3: 664 ms per loop %%timeit x = df1.set_index('A').join(df2.set_index('A2'), how='left') #1 loop, best of 3: 354 ms per loop %%time df1.set_index('A', inplace=True) df2.set_index('A2', inplace=True) #Wall time: 16 ms %%timeit x = df1.join(df2, how='left') #10 loops, best of 3: 80.4 ms per loop当两个表中要连接的列的整数顺序不同时,您仍然可以期望将速度提高8倍。 相关讨论 简短的解释说明为什么通过索引而不是通过"普通"列进行合并更快:索引具有哈希表。意味着您可以在摊销的O(1)中查找它们。对于普通列,在最坏的情况下需要O(n),这意味着将两个dfs与len n合并会在最坏的情况下花费O(n ^ 2)。 在我的情况下,DataFrame.merge()明显更快(x5)。我正在从3m行数据框(如左)和900行数据框(如右)进行左联接。我的索引是字符串,这几乎是我能看到的唯一解释 请注意:速度的提高将取决于您的索引是否唯一。如果索引不是唯一的,则合并索引上的两个数据帧可能甚至需要更长的时间。 还是可以用于multindex? x = df1.set_index(['A','B'])。join(df2.set_index((['A','B']),how ='left')吗?我建议您将合并列设置为索引,并使用df1.join(df2)代替merge,这要快得多。 下面是一些包含概要分析的示例: 1234567In [1]: import pandas as pd import numpy as np df1 = pd.DataFrame(np.arange(1000000), columns=['A']) df1['B'] = np.random.randint(0,1000,(1000000)) df2 = pd.DataFrame(np.arange(1000000), columns=['A2']) df2['B2'] = np.random.randint(0,1000,(1000000))这是A和A2的常规左合并: 1234In [2]: %%timeit x = df1.merge(df2, how='left', left_on='A', right_on='A2') 1 loop, best of 3: 441 ms per loop使用连接: 1234In [3]: %%timeit x = df1.set_index('A').join(df2.set_index('A2'), how='left') 1 loop, best of 3: 184 ms per loop现在很明显,如果您可以在循环之前设置索引,则时间方面的收益将更大: 1234567# Do this before looping In [4]: %%time df1.set_index('A', inplace=True) df2.set_index('A2', inplace=True) CPU times: user 9.78 ms, sys: 9.31 ms, total: 19.1 ms Wall time: 16.8 ms然后在循环中,您会得到比这种情况快30倍的结果: 123In [5]: %%timeit x = df1.join(df2, how='left') 100 loops, best of 3: 14.3 ms per loop 相关讨论 这是左合并/联接。合并中的参数如何为" left",将与join一起使用? 不知何故,我的数据集性能没有太大改善。如果将所有合并转换为联接,则时间会增加约0.1-0.3秒。我将一些合并转换为联接,可以将时间减少约0.2秒。有什么我想念的吗?还是我需要产生类似代码的任何东西? 如果您要在问题中加入mcve,这将有助于测试您的特定应用程序。这也是为什么这个问题被标记为"偏离主题"的部分原因 请查看更新的问题,并希望此问题引起关注。如果是的话,如果您可以删除主题外的标记,那也很好,因为进行大量合并的人们可能会发现此标记很有用,因为没有太多与此问题类似的帖子。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |