我有一个数据框,由来自约4000个机场的全部机场的城市机场组合对组成。组合的数量是数百万,但我使用的数据子集约为150万对(df_pairs行)。
df_pairs:
city1 city2
0 sfo yyz
1 sfo yvr
2 sfo dfw
3 sfo ewr
4 sfo pdx
输出df_pairs.to_dict('记录'):
[{'index': 0, 'city1': 'sfo', 'city2': 'yyz'},
{'index': 1, 'city1': 'sfo', 'city2': 'yvr'},
{'index': 2, 'city1': 'sfo', 'city2':'dfw'},
{'index': 3, 'city1': 'sfo', 'city2':'ewr'},
{'index': 4, 'city1': 'sfo', 'city2': 'pdx'}]
对于df_pairs
中的每个城市对(行),我想执行各种对级别的计算。
我还有3个额外的数据框,其中包含有关每个机场的各种数字和分类信息。
它们看起来像(虽然有些dfs是月度数据和其他日常数据):
df_stats1:
city fuel landings takeoffs passengers
date
2014-05-01 sfo 2.32 4.26 4.87 6.58
2014-05-01 yyz 14.00 1.50 20.00 5.00
2014-05-01 yvr 24.78 2.90 50.55 6.64
2014-05-01 dfw 2.40 4.06 4.06 6.54
2014-05-01 ewr 30.35 9.96 64.24 6.66
2014-05-01 pdx 60.35 5.45 4.12 6.98
输出df_stats1.reset_index()。to_dict('记录'):
[{'date': Timestamp('2014-05-01 00:00:00'),
'city': 'sfo',
'landings': 4.26,
'passengers': 6.58,
'fuel': 2.32,
'takeoffs': 4.87},
{'date': Timestamp('2014-05-01 00:00:00'),
'city': 'yyz',
'landings': 1.5,
'passengers': 5.00,
'fuel': 14.00,
'takeoffs': 20.00},
{'date': Timestamp('2014-05-01 00:00:00'),
'city': 'yvr',
'landings': 2.9,
'passengers': 6.64,
'fuel': 24.78,
'takeoffs': 50.55},
{'date': Timestamp('2014-05-01 00:00:00'),
'city': 'dfw',
'landings': 4.06,
'passengers': 6.54,
'fuel': 2.4,
'takeoffs': 4.06},
{'date': Timestamp('2014-05-01 00:00:00'),
'city': 'ewr',
'landings': 9.96,
'passengers': 6.66,
'fuel': 30.35,
'takeoffs': 64.24},
{'date': Timestamp('2014-05-01 00:00:00'),
'city': 'pdx',
'landings': 5.45,
'passengers': 6.98,
'fuel': 60.35,
'takeoffs': 4.12}]
现在,我有一个由{/ p>执行的函数calstats
df_pairs.apply(calstats, axis=1, args=(v1,v2,v3,v4,v5,v6,v7, blah blah))
calcstats
函数做的第一件事就是构造3个中间/临时数据帧,方法是从stat dfs中选择对中每个城市的数据,并通过执行{{1}将它们并排排列。 }}。
其中一个中间/临时dfs的示例:
merge
然后我使用3个中间/临时dfs(即tmp_city_pair_df)来执行各种计算,例如对之间的着陆差异,最大值(在所讨论的时间段内的这种差异),min()等。
我遇到了各种性能问题。
首先,构建3个中间dfs所需的总时间约为:city1_df = df_stats1[df_stats1['city'] == row['city1']]
city2_df = df_stats1[df_stats1['city'] == row['city2']]
tmp_city_pair_df = city1_df.merge(city2_df, left_index=True, right_index=True, how = 'right', suffixes=('_1','_2'))
。
我在0:00:00.048481
中的行数约为1.5
,因此执行中间dfs的总费用为df_pairs
= 1,500,000 x 0:00:00.048481
秒= 72,721.5
小时。< / p>
因此构建中间dfs需要20.2
小时,并且不包括在执行进一步计算时使用这些中间dfs所需的时间成本。
我想知道是否有更有效的方法来做到这一点。
基本上,我正在做的是在20
,city1
和city2
中查找df_stats1
和df_stats2
并构建中间/临时我可以使用dfs来执行对级计算。
更新
我想提供更多信息。
因此,目的是在一对基础上生成一个最终的数据帧,看起来如下所示,我可以用它进行进一步处理。
df_stats3
上面名为stat1到stat6的统计信息是原始数据中不存在的专有统计信息。
原始数据由3个数据帧组成,我称之为:
city1 city2 stat1, stat2, stat3, stat4, stat5, stat6 ...
0 sfo yyz, x, x, x, x, x, x
1 sfo yvr, y, y, y, y, y, y
2 sfo dfw, z, z, z, z, z, z
3 sfo ewr, a, a, a, a, a, a
4 sfo pdx, b, b, b, b, b, b
df_stat1
df_stat2
df_stat3
=过去24个月每个机场的每日数据(燃料,着陆,起飞,乘客)
df_stat1
= df_stat2
但汇总到月份(通过df_stat1
df.stat1.groupby(['city',pd.TimeGrouper('M')]
=过去24个月内每个机场的月度数据时间序列,包括着陆费,收入等信息
现在,要进入最终的数据帧,需要进行各种计算。我想计算像:
这样的东西df_stat3
例如,在最终的数据框中,1) City1 Landings - City2 Landings (on a daily and monthly basis)
2) Sign of statistic in #1 (positive or negative)
可以是:
上述#2中唯一正值的总和。
因此,您可以看到需要进行各种操作才能到达最终的数据帧。
我不知道如何才能最好地利用pandas / python的矢量化功能。
例如,要生成上面#2中唯一正值的和,我需要为每个城市对加入每日数据时间序列(来自df_stat1),计算City1着陆与City2着陆之间的减法,然后求和积极的价值观。
答案 0 :(得分:1)
Python(和pandas)在构建大量对象时表现不佳。 merge
中每行的apply
就是这样做的。相反,您可以尝试以下方法:
tmp = pd.merge(df_pairs, df_stats.add_suffix('_1'), left_on='city1', right_on='city_1', how='left')
pd.merge(tmp, df_stats.add_suffix('_2'), left_on='city2', right_on='city_2', how='left')
这将首先有效地执行合并(这里的双线结构是为了节省空间,并且仅在df_pairs
中的所有对上进行合并。)
此外,您现在可以按矢量进行所有分析,在任何情况下都应该快得多。如果您添加有关所需分析的更多详细信息,则可以进一步解决此问题。
修改强>
根据对问题和评论的编辑,这里是处理日常数据的概述。具体来说,让我们处理登陆日期的每日差异(您可以适应各种变化,例如,只有正差异)。
假设您从
开始landings_by_date = df_stats1[['city', 'date', 'landings']].set_index(['city', 'date']).unstack()
landings_by_date.columns = landings_by_date.columns.get_level_values(1)
要查找特定日期的着陆日期差异,例如第一个(索引0),您可以
lhs = pd.merge(df_pairs, landings_by_date.ix[:, [0]], left_on='city1', right_index=True, how='left').set_index(['city1', 'city2'])
rhs = pd.merge(df_pairs, landings_by_date.ix[:, [0]], left_on='city2', right_index=True, how='left').set_index(['city1', 'city2'])
lhs - rhs
(或者,为了下降到numpy,
(lhs - rhs).values
)
要计算所有日期的某些聚合,请在循环上执行此操作(以便日期索引为0,1,...),并更新聚合。
为什么这会更有效率?根据您问题的具体情况,每日日期约为3000,但约为1.5e6行。
即使你正在循环(这在数值Python中是不受欢迎的),你只需要进行约3000次迭代,并在每次迭代中进行矢量运算~1.5e6条目。
你不是在创建小型数据框架〜1.5e6次(如你的问题所示),你只创建(更大)数据框架约3000次。
内存需求应该很小 - 每个聚合额外增加约1.5e6。