使用Pandas concat对多DataFrame的DatetimeIndex列求和异常问题
问题:聚合多带DatetimeIndex的DataFrame(外连接索引+同日期求和)
我有多个带有DatetimeIndex的DataFrame,它们的日期各不相同,但列结构一致。希望聚合这些DataFrame时,索引采用外连接方式保留所有日期,同一日期的列值进行求和。
最小可复现代码
#!/usr/bin/env python3 import os, sys import numpy as np import pandas as pd import datetime as dt days1 = pd.date_range(dt.date(2010,1,1), dt.date(2010,1,1) + dt.timedelta(7), freq='D') days2 = pd.date_range(dt.date(2010,1,3), dt.date(2010,1,3) + dt.timedelta(7), freq='D') days3 = pd.date_range(dt.date(2010,2,1), dt.date(2010,2,1) + dt.timedelta(7), freq='D') df1 = pd.DataFrame({'date': days1, 'alpha': np.array(8*[1]), 'beta': np.array(8*[10])}) df2 = pd.DataFrame({'date': days2, 'alpha': np.array(8*[2]), 'beta': np.array(8*[20])}) df3 = pd.DataFrame({'date': days3, 'alpha': np.array(8*[3]), 'beta': np.array(8*[30])}) df1 = df1.set_index('date') df2 = df2.set_index('date') df3 = df3.set_index('date') df1 = (pd.concat([df1,df2], axis=0)).groupby('date')['alpha', 'beta'].sum().reset_index() df1 = (pd.concat([df1,df3], axis=0)).groupby('date')['alpha', 'beta'].sum().reset_index() print(df1)
实际输出
date alpha beta 0 2010-01-01 1 10 1 2010-01-02 1 10 2 2010-01-03 3 30 3 2010-01-04 3 30 4 2010-01-05 3 30 5 2010-01-06 3 30 6 2010-01-07 3 30 7 2010-01-08 3 30 8 2010-01-09 2 20 9 2010-01-10 2 20
预期输出
date alpha beta 0 2010-01-01 1 10 1 2010-01-02 1 10 2 2010-01-03 3 30 3 2010-01-04 3 30 4 2010-01-05 3 30 5 2010-01-06 3 30 6 2010-01-07 3 30 7 2010-01-08 3 30 8 2010-01-09 2 20 9 2010-01-10 2 20 10 2010-02-01 3 30 11 2010-02-02 3 30 12 2010-02-03 3 30 13 2010-02-04 3 30 14 2010-02-05 3 30 15 2010-02-06 3 30 16 2010-02-07 3 30 17 2010-02-08 3 30
问题原因
第二次执行concat时,df1已经通过reset_index()将date转为普通列,而df3仍以date为DatetimeIndex。concat会自动对齐双方的索引,导致df3的内容被匹配到df1的整数索引上,最终groupby时丢失了df3的日期数据。
解决方案
方案1:一次性合并所有DataFrame再分组求和(推荐)
一次性合并所有目标DataFrame,再按日期索引分组求和,避免分步操作的索引不一致问题,效率更高:
#!/usr/bin/env python3 import numpy as np import pandas as pd import datetime as dt days1 = pd.date_range(dt.date(2010,1,1), dt.date(2010,1,1) + dt.timedelta(7), freq='D') days2 = pd.date_range(dt.date(2010,1,3), dt.date(2010,1,3) + dt.timedelta(7), freq='D') days3 = pd.date_range(dt.date(2010,2,1), dt.date(2010,2,1) + dt.timedelta(7), freq='D') df1 = pd.DataFrame({'date': days1, 'alpha': np.array(8*[1]), 'beta': np.array(8*[10])}).set_index('date') df2 = pd.DataFrame({'date': days2, 'alpha': np.array(8*[2]), 'beta': np.array(8*[20])}).set_index('date') df3 = pd.DataFrame({'date': days3, 'alpha': np.array(8*[3]), 'beta': np.array(8*[30])}).set_index('date') # 一次性合并所有DataFrame,按索引(日期)分组求和后重置索引 result = pd.concat([df1, df2, df3], axis=0).groupby(level=0).sum().reset_index() print(result)
方案2:保持统一索引状态分步处理
如果需要分步合并,确保每次合并的DataFrame都保持date为DatetimeIndex,不要提前重置索引:
#!/usr/bin/env python3 import numpy as np import pandas as pd import datetime as dt days1 = pd.date_range(dt.date(2010,1,1), dt.date(2010,1,1) + dt.timedelta(7), freq='D') days2 = pd.date_range(dt.date(2010,1,3), dt.date(2010,1,3) + dt.timedelta(7), freq='D') days3 = pd.date_range(dt.date(2010,2,1), dt.date(2010,2,1) + dt.timedelta(7), freq='D') df1 = pd.DataFrame({'date': days1, 'alpha': np.array(8*[1]), 'beta': np.array(8*[10])}).set_index('date') df2 = pd.DataFrame({'date': days2, 'alpha': np.array(8*[2]), 'beta': np.array(8*[20])}).set_index('date') df3 = pd.DataFrame({'date': days3, 'alpha': np.array(8*[3]), 'beta': np.array(8*[30])}).set_index('date') # 第一次合并后不重置索引,保持date为索引 df_combined = pd.concat([df1, df2], axis=0).groupby('date').sum() # 第二次合并时,双方都是DatetimeIndex,合并后再分组求和并重置索引 df_combined = pd.concat([df_combined, df3], axis=0).groupby('date').sum().reset_index() print(df_combined)
两种方案都能得到你想要的预期输出。
内容的提问来源于stack exchange,提问作者gman
相关产品推荐
相关产品推荐

