python - Pandas.resample 为非整数倍频

标签 python numpy pandas resampling

我必须将数据集从 10 分钟间隔重新采样为 15 分钟间隔,以使其与另一个数据集同步。根据我在 stackoverflow 上的搜索,我有一些如何继续的想法,但没有一个提供干净清晰的解决方案。

问题

问题设置

#%% Import modules 
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

#%% make timestamps
periods = 12
startdate = '2010-01-01'
timestamp10min = pd.date_range(startdate, freq='10Min', periods=periods)


#%% Make DataFrame and fill it with some data
df = pd.DataFrame(index=timestamp10min)
y = -(np.arange(periods)-periods/2)**2
df['y'] = y 

期望的输出

现在我希望 10 分钟处的值保持不变,并且 **:15 和 **:45 处的值是 **:10、**:20 和 ** 的平均值: 40,**:50。问题的核心在于15分钟不是10分钟的整数倍。否则,只需应用 df.resample('10Min', how='mean') 就可以了。

可能的解决方案

  1. 只需使用 15 分钟重采样,并接受引入的小误差。

  2. 使用两种形式的重采样,即 close='left', label='left'close='right' , label='right' 。之后我可以对两个重新采样的表格进行平均。结果会给我带来一些结果误差,但比第一种方法要小。

  3. 将所有内容重新采样为 5 分钟数据,然后应用滚动平均值。类似的东西在这里应用:Pandas: rolling mean by time interval

  4. 使用不同数量的输入重新采样并求平均值:Use numpy.average with weights for resampling a pandas array 因此,我必须创建一个具有不同重量长度的新系列。权重应该在 1 和 2 之间交替吗?

  5. 将所有内容重新采样为 5 分钟数据,然后应用线性插值。此方法与方法3接近。 Pandas data frame: resample with linear interpolation 编辑:@Paul H 给出了一个可行的解决方案,仍然可读。谢谢!

所有的方法都不能真正令我满意。有些方法会导致小错误,而另一些方法对于外人来说很难阅读。

实现

方法 1、2 和 5 的实现以及所需的输出。与可视化相结合。

#%% start plot
plt.figure()
plt.plot(df.index, df['y'], label='original')

#%% resample the data to 15 minutes and plot the result
close = 'left'; label='left'
dfresamplell = pd.DataFrame()
dfresamplell['15min'] = df.y.resample('15Min', how='mean', closed=close, label=label)
labelstring = 'close ' + close + ' label ' + label        
plt.plot(dfresamplell.index, dfresamplell['15min'], label=labelstring)
        
close = 'right'; label='right'
dfresamplerr = pd.DataFrame()
dfresamplerr['15min'] = df.y.resample('15Min', how='mean', closed=close, label=label)
labelstring = 'close ' + close + ' label ' + label        
plt.plot(dfresamplerr.index, dfresamplerr['15min'], label=labelstring)

#%% make an average
dfresampleaverage = pd.DataFrame(index=dfresamplell.index)
dfresampleaverage['15min'] = (dfresamplell['15min'].values+dfresamplerr['15min'].values[:-1])/2
plt.plot(dfresampleaverage.index, dfresampleaverage['15min'], label='average of both resampling methods')

#%% desired output
ydesired = np.zeros(periods/3*2)
i = 0 
j = 0 
k = 0 
for val in ydesired:
    if i+k==len(y): k=0
    ydesired[j] = np.mean([y[i],y[i+k]]) 
    j+=1
    i+=1
    if k==0: k=1; 
    else: k=0; i+=1
plt.plot(dfresamplell.index, ydesired, label='ydesired')


#%% suggestion of Paul H
dfreindex = df.reindex(pd.date_range(startdate, freq='5T', periods=periods*2))
dfreindex.interpolate(inplace=True)
dfreindex = dfreindex.resample('15T', how='first').head()
plt.plot(dfreindex.index, dfreindex['y'], label='method Paul H')


#%% finalize plot
plt.legend()

角度的实现

作为奖励,我添加了用于角度插值的代码。这是通过使用复数来完成的。由于复数插值尚未实现,因此我将复数分为实部和虚部。对这些数字进行平均后可以再次转换为天使。对于某些角度,这是比简单地平均两个角度更好的重采样方法,例如:345 度和 5 度。

#%% make timestamps
periods = 24*6
startdate = '2010-01-01'
timestamp10min = pd.date_range(startdate, freq='10Min', periods=periods)

#%% Make DataFrame and fill it with some data
degrees = np.cumsum(np.random.randn(periods)*25) % 360
df = pd.DataFrame(index=timestamp10min)
df['deg'] = degrees
df['zreal'] = np.cos(df['deg']*np.pi/180)
df['zimag'] = np.sin(df['deg']*np.pi/180)

#%% suggestion of Paul H
dfreindex = df.reindex(pd.date_range(startdate, freq='5T', periods=periods*2))
dfreindex = dfreindex.interpolate()
dfresample = dfreindex.resample('15T', how='first')

#%% convert complex to degrees
def f(x):    
     return np.angle(x[0] + x[1]*1j, deg=True )
dfresample['degrees'] = dfresample[['zreal', 'zimag']].apply(f, axis=1)

#%% set all the values between 0-360 degrees
dfresample.loc[dfresample['degrees']<0] = 360 + dfresample.loc[dfresample['degrees']<0] 

#%% wrong resampling
dfresample['deg'] = dfresample['deg'] % 360

#%% plot different sampling methods
plt.figure()
plt.plot(df.index, df['deg'], label='normal', marker='v')
plt.plot(dfresample.index, dfresample['degrees'], label='resampled according @Paul H', marker='^')
plt.plot(dfresample.index, dfresample['deg'], label='wrong resampling', marker='<')
plt.legend()

最佳答案

我可能误解了这个问题,但这有效吗?

TL;DR 版本:

import numpy as np
import pandas

data = np.arange(0, 101, 8)
index_10T = pandas.DatetimeIndex(freq='10T', start='2012-01-01 00:00', periods=data.shape[0])
index_05T = pandas.DatetimeIndex(freq='05T', start=index_10T[0], end=index_10T[-1])
index_15T = pandas.DatetimeIndex(freq='15T', start=index_10T[0], end=index_10T[-1])
df1 = pandas.DataFrame(data=data, index=index_10T, columns=['A'])
print(df.reindex(index=index_05T).interpolate().loc[index_15T])

长版

设置假数据

import numpy as np
import pandas

data = np.arange(0, 101, 8)
index_10T = pandas.DatetimeIndex(freq='10T', start='2012-01-01 00:00', periods=data.shape[0])
df1 = pandas.DataFrame(data=data, index=index_10T, columns=['A'])
print(df1)


                      A
2012-01-01 00:00:00   0
2012-01-01 00:10:00   8
2012-01-01 00:20:00  16
2012-01-01 00:30:00  24
2012-01-01 00:40:00  32
2012-01-01 00:50:00  40
2012-01-01 01:00:00  48
2012-01-01 01:10:00  56
2012-01-01 01:20:00  64
2012-01-01 01:30:00  72
2012-01-01 01:40:00  80
2012-01-01 01:50:00  88
2012-01-01 02:00:00  96

然后构建一个新的 5 分钟索引并重新索引原始数据帧

index_05T = pandas.DatetimeIndex(freq='05T', start=index_10T[0], end=index_10T[-1])
df2 = df.reindex(index=index_05T)
print(df2)

                      A
2012-01-01 00:00:00   0
2012-01-01 00:05:00 NaN
2012-01-01 00:10:00   8
2012-01-01 00:15:00 NaN
2012-01-01 00:20:00  16
2012-01-01 00:25:00 NaN
2012-01-01 00:30:00  24
2012-01-01 00:35:00 NaN
2012-01-01 00:40:00  32
2012-01-01 00:45:00 NaN
2012-01-01 00:50:00  40
2012-01-01 00:55:00 NaN
2012-01-01 01:00:00  48
2012-01-01 01:05:00 NaN
2012-01-01 01:10:00  56
2012-01-01 01:15:00 NaN
2012-01-01 01:20:00  64
2012-01-01 01:25:00 NaN
2012-01-01 01:30:00  72
2012-01-01 01:35:00 NaN
2012-01-01 01:40:00  80
2012-01-01 01:45:00 NaN
2012-01-01 01:50:00  88
2012-01-01 01:55:00 NaN
2012-01-01 02:00:00  96

然后线性插值

print(df2.interpolate())
                      A
2012-01-01 00:00:00   0
2012-01-01 00:05:00   4
2012-01-01 00:10:00   8
2012-01-01 00:15:00  12
2012-01-01 00:20:00  16
2012-01-01 00:25:00  20
2012-01-01 00:30:00  24
2012-01-01 00:35:00  28
2012-01-01 00:40:00  32
2012-01-01 00:45:00  36
2012-01-01 00:50:00  40
2012-01-01 00:55:00  44
2012-01-01 01:00:00  48
2012-01-01 01:05:00  52
2012-01-01 01:10:00  56
2012-01-01 01:15:00  60
2012-01-01 01:20:00  64
2012-01-01 01:25:00  68
2012-01-01 01:30:00  72
2012-01-01 01:35:00  76
2012-01-01 01:40:00  80
2012-01-01 01:45:00  84
2012-01-01 01:50:00  88
2012-01-01 01:55:00  92
2012-01-01 02:00:00  96

构建一个 15 分钟索引并使用它来提取数据:

index_15T = pandas.DatetimeIndex(freq='15T', start=index_10T[0], end=index_10T[-1])
print(df2.interpolate().loc[index_15T])

                      A
2012-01-01 00:00:00   0
2012-01-01 00:15:00  12
2012-01-01 00:30:00  24
2012-01-01 00:45:00  36
2012-01-01 01:00:00  48
2012-01-01 01:15:00  60
2012-01-01 01:30:00  72
2012-01-01 01:45:00  84
2012-01-01 02:00:00  96

关于python - Pandas.resample 为非整数倍频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26594464/

相关文章:

python - 从 numpy 数组中提取不在索引列表中的元素

python - 如何迭代行索引并从Python数据集中找到具有最大行列式的组?

python - 使用 tkinter 时无限循环

python - Telegram Bot 如何在 curl 中设置解析模式?

Python Bottle SSE

python - Numpy 切片结果与 for 循环不同

python - 洛伦兹拟合两种编写代码的方式

python - 无法在 django 中找出正确的 json 查询集

python - Pandas ,选择一个列,其中第二列具有 NaN 值

python - 如何在 Pandas 数据框中找到 5 分钟的间隔?