【问题标题】:Upsampling (disaggregating) summed quarterly data to monthly data上采样(分解)将季度数据汇总到月度数据
【发布时间】:2018-07-10 13:04:17
【问题描述】:

我正在尝试从汇总的季度到月度对数据进行上采样,但下面代码产生的数字不是我需要的。我需要将这些数据点分解为月度数字(加起来到紧接着的下一个季度)。因此,每个新值都需要约为下一季度的三分之一。

i = ['2000-01-01','2000-04-01','2000-07-01','2000-10-01','2001-01-01','2001-04-01','2001-07-01','2001-10-01']
d = [0,54957.84767,0,0,0,56285.54879,0,0]

df = pd.DataFrame(index=i, data=d)
df.index = pd.to_datetime(df.index,infer_datetime_format=True)
df.index = df.index.to_period('Q')

df.resample('M').first().interpolate(method='cubic')

更新:假设一个玩具系列是 [0,0,9]。所以一月,二月,三月。 3 月底的值为 9。我希望插值结果为 [3,3,3]。因此,每个月的值都是 3,当您将它们聚合回季度时,它又会得到 9。

【问题讨论】:

  • 谢谢 - 更新了问题!
  • 如果没有第三个数据点,您想要的东西是不可能的。一家公司通常具有指数增长,但要拟合指数曲线,您至少需要三个点。对于两点,您只能进行线性插值,然后可能进行外推。

标签: python pandas data-analysis resampling


【解决方案1】:

仅使用两个数据点实际上不可能实现您想要做的事情。一家公司通常有一些多项式或指数增长,但只有两个数据点,你无法拟合出如此复杂的增长曲线。只有线性插值是可能的。

但是让我们假设你有第三点

import pandas as pd
date = pd.date_range('2000-4-1', periods=3, freq='4Q') # quarter _end_!
Qsales = [54957.84767, 56285.54879, 58277.10047]
df = pd.DataFrame({'Quarter sales':Qsales}, index=pd.Index(date, name='date'))
print(df)
import matplotlib.pyplot as plt
plt.plot(df.index, df['Quarter sales'])
plt.show()

这表明:

            Quarter sales
date                     
2000-06-30    54957.84767
2001-06-30    56285.54879
2002-06-30    58277.10047

现在我们可以做点什么了。让我们根据y = offset + factor * base^x 拟合指数曲线。 编辑:我在这里使用pd.datetime(2000, 1, 1) 作为零点。

#### curve fitting
import numpy as np
date_delta = (date - pd.datetime(2000, 1, 1)) /np.timedelta64(1,'M')
## convert data to x/y
x = date_delta.values
y = df['Quarter sales'].values
## expected function
def expFunc(x, offset, factor, base) : return offset + factor * base**x
## initial guess
guess = (53000, 1000, 1.05)
## call scipy curve fitting
from scipy.optimize import curve_fit
params = curve_fit(expFunc, x, y, guess)
## now first generate data for all quarters using interpolation
# generate new dates
date = pd.date_range('2000-1-1', periods=3*4, freq='Q') # quarter _end_!
date_delta = (date - pd.datetime(2000,1,1)) / np.timedelta64(1, 'M')
x = date_delta.values
Qsales = expFunc(x, params[0][0], params[0][1], params[0][2])
df = pd.DataFrame({'Quarter sales':Qsales}, index=pd.Index(date, name='date'))
print(df)
plt.plot(df.index, df['Quarter sales'])
plt.show()

这给出了:

            Quarter sales
date                     
2000-03-31   54702.538666
2000-06-30   54957.847670
2000-09-30   55243.580457
2000-12-31   55560.059331
2001-03-31   55902.585284
2001-06-30   56285.548790
2001-09-30   56714.147971
2001-12-31   57188.866281
2002-03-31   57702.655211
2002-06-30   58277.100470
2002-09-30   58919.999241
2002-12-31   59632.076706

现在,事情变得顺利了。但这还不够。您需要确定每月的销售额。好吧,因为您现在知道了曲线,所以您可以根据以下公式分配每月的增长:

#now further interpolate to months
date = pd.date_range('2000-1-1', periods=3*12, freq='M') # month _end_!
date_delta = (date - pd.datetime(2000, 1, 1)) / np.timedelta64(1,'M')
x = date_delta.values
# first determine the exponential factor per month
dateFactors = expFunc(x, params[0][0], params[0][1], params[0][2])
MFactorSeries = pd.Series(dateFactors, index=date)
# now sum the exponential factors to get them for the quarters
QFactorSeries = MFactorSeries.resample('Q').sum()
# and divide them by the quartarly sales to get a monthly sales base 
MSalesBase = np.divide(Qsales, QFactorSeries.values) 
#now some numpy tricks to get the monthly sales
Msales = np.multiply(dateFactors.reshape(12,3), MSalesBase.reshape(12,1)).flatten()
df = pd.DataFrame({'Monthly sales':Msales}, index=pd.Index(date, name='date'))
print(df)
plt.plot(df.index, df['Monthly sales'])
plt.show()

这给出了:

            Monthly sales
date                     
2000-01-31   18208.780004
2000-02-29   18233.319078
2000-03-31   18260.439584
2000-04-30   18290.245845
2000-05-31   18319.272021
2000-06-30   18348.329804
2000-07-31   18382.360436
2000-08-31   18414.515147
2000-09-30   18446.704874
2000-10-31   18484.774541
2000-11-30   18519.227954
2000-12-31   18556.056836
2001-01-31   18596.904560
2001-02-28   18632.486725
2001-03-31   18673.193999
2001-04-30   18718.262419
2001-05-31   18761.833781
2001-06-30   18805.452590
2001-07-31   18856.427507
2001-08-31   18904.698469
2001-09-30   18953.021996
2001-10-31   19010.040490
2001-11-30   19061.766635
2001-12-31   19117.059156
2002-01-31   19178.229496
2002-02-28   19231.653416
2002-03-31   19292.772298
2002-04-30   19360.251134
2002-05-31   19425.676408
2002-06-30   19491.172928
2002-07-31   19567.484781
2002-08-31   19639.973435
2002-09-30   19712.541026
2002-10-31   19797.887582
2002-11-30   19875.573492
2002-12-31   19958.615633

注意

我不是 pandas、scipy、numpy 等方面的专家。这正是我应该使用我的工程背景的方式。

【讨论】:

  • 非常感谢您提供此解决方案。这涵盖了我的部分问题,但这是由于我编写它的方式,而不是由于您的解决方案。您发布的内容确实回答了所提出的问题,因此我将接受它作为已回答的内容并发布一个新问题。再次感谢您。
【解决方案2】:

您可以这样做,但 method=cubic 由于 NaN 而无法正常工作。

df.resample('M').asfreq().interpolate()

输出:

                    0
2000-01      0.000000
2000-02  18319.282557
2000-03  36638.565113
2000-04  54957.847670
2000-05  36638.565113
2000-06  18319.282557
2000-07      0.000000
2000-08      0.000000
2000-09      0.000000
2000-10      0.000000
2000-11      0.000000
2000-12      0.000000
2001-01      0.000000
2001-02  18761.849597
2001-03  37523.699193
2001-04  56285.548790
2001-05  37523.699193
2001-06  18761.849597
2001-07      0.000000
2001-08      0.000000
2001-09      0.000000
2001-10      0.000000
2001-11      0.000000
2001-12      0.000000

【讨论】:

  • 但是缺少的月份呢?还是只转换具有相邻季度值的那些?
  • 缺少几个月?缺少哪些月份?
  • 所有归零的 - 例如 2000 年 7 月到 12 月。
  • 那里有零,所以它内插到零。我想这就是你想使用立方的原因。我现在明白了。
  • 我想如果我首先插值四分之一(不重新采样)将填补缺失的四分之一。从那时起,我可以重新采样到几个月,然后进行第二次插值,这可能会做到。
猜你喜欢
  • 2019-08-13
  • 1970-01-01
  • 2021-05-17
  • 2017-03-26
  • 2020-11-23
  • 1970-01-01
  • 1970-01-01
  • 2020-08-28
  • 1970-01-01
相关资源
最近更新 更多