计算统计数据的中间合并/联接数据帧的性能问题

2024-10-05 11:08:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个数据帧,它是由城市-机场组合对组成的,来自大约4000个机场。组合的数量是以百万计的,但是我使用的数据子集大约是150万对(dfu对的行)。你知道吗

数据流对:

    city1   city2
    0   sfo yyz
    1   sfo yvr
    2   sfo dfw
    3   sfo ewr
    4   sfo pdx

测向输出_结对(“记录”):

[{'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是每月数据,有些是每日数据):

数据统计1:

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('records'):

[{'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}]

现在,我有一个函数calstats,它由以下执行:

df_pairs.apply(calstats, axis=1, args=(v1,v2,v3,v4,v5,v6,v7, blah blah))

calcstats函数所做的第一件事是通过从stat dfs中为成对的每个城市选择数据并通过执行merge将它们并排排列成一行来构造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'))

然后,我使用3个中间/临时df(即tmp\u city\u pair\u df)来执行各种计算,如两个对之间的着陆差异、最大值(在所讨论的时间段中的差异)、最小值()等

我有各种各样的性能问题。你知道吗

第一个是构造3个中间df所需的总时间约为:0:00:00.048481。你知道吗

我在df_pairs中有大约1.5百万行,因此执行中间dfs的总成本是1,500,000 x 0:00:00.048481=72,721.5秒=20.2小时。你知道吗

因此,仅构建中间df就需要20小时,并且不包括在执行进一步计算时使用这些中间df所需的时间成本。你知道吗

我想知道是否有更有效的方法来做这件事。你知道吗

本质上,我所做的是在df_stats1df_stats2df_stats3中查找city1city2,并构造中间/临时df,我可以使用它们来执行对级计算。你知道吗

更新

我想提供更多的信息。你知道吗

因此,目的是在成对的基础上生成一个最终的数据帧,它看起来像下面的内容,我可以使用它进行进一步的处理。你知道吗

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

上面名为stat1到stat6的统计信息是原始数据中不存在的专有统计信息。你知道吗

原始数据由3个数据帧组成,我称之为:

df_stat1
df_stat2
df_stat3

df_stat1=过去24个月每个机场的每日数据(燃油、着陆、起飞、乘客)

df_stat2=df_stat1但汇总到月份(通过df.stat1.groupby(['city',pd.TimeGrouper('M')]

df_stat3=过去24个月每个机场的月度数据时间序列,包括着陆费、收入等信息

现在,为了得到最终的数据帧,需要进行各种计算。我想计算如下:

1) City1 Landings - City2 Landings (on a daily and monthly basis)
2) Sign of statistic in #1 (positive or negative)

例如,在最后一个数据帧中,stat1可以是:

上面#2中只有正值的总和。你知道吗

因此,您可以看到需要进行各种操作才能到达最终的数据帧。你知道吗

我不知道如何才能最好地利用pandas/python的矢量化功能。你知道吗

例如,要在上面的#2中只产生正值之和,我需要将每个城市对的每日数据时间序列(来自df#stat1)连接起来,计算城市1着陆和城市2着陆之间的差,然后将正值相加。你知道吗


Tags: 数据citydfdateindextimestampfuelstats1
1条回答
网友
1楼 · 发布于 2024-10-05 11:08:22

Python(和pandas)在构造大量对象时的性能很差。对于apply中的每一行,您的merge就是这样做的。相反,您可以尝试以下操作:

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

(或者,去努比

(lhs - rhs).values

()

要计算所有日期的聚合,请在循环中执行此操作(以便日期索引为0、1、…),然后更新聚合。你知道吗

为什么这样更有效?根据问题的具体情况,每天约有3000个日期,但约有1.5e6行。你知道吗

  1. 即使您正在循环(在数值Python中这是不受欢迎的),您也只进行了~3000次迭代,并且在每个迭代中以矢量方式处理~1.5e6个条目。

  2. 你不是在创建1.5e6次的小数据帧(如你的问题所示),你只创建了3000次(更大的)数据帧。

  3. 内存需求应该很小-只是每个聚合额外的~1.5e6。

相关问题 更多 >

    热门问题