pandas 具有相同小时数的所有值之间的 RMSE

RMSE between all value with same hours with pandas

我有两个数据框:第一个代表模型模拟的输出,第二个代表真实值。我想计算具有相同小时数的所有值之间的 RMSE。基本上我应该计算 24 RMSE 值,每小时一个。

这些是我的数据框的第一列:

date;model
2017-01-01 00:00:00;53
2017-01-01 01:00:00;52
2017-01-01 02:00:00;51
2017-01-01 03:00:00;47.27
2017-01-01 04:00:00;45.49
2017-01-01 05:00:00;45.69
2017-01-01 06:00:00;48.07
2017-01-01 07:00:00;45.67
2017-01-01 08:00:00;45.48
2017-01-01 09:00:00;42.06
2017-01-01 10:00:00;46.86
2017-01-01 11:00:00;48.02
2017-01-01 12:00:00;49.57
2017-01-01 13:00:00;48.69
2017-01-01 14:00:00;46.91
2017-01-01 15:00:00;49.43
2017-01-01 16:00:00;50.45
2017-01-01 17:00:00;53.3
2017-01-01 18:00:00;59.07
2017-01-01 19:00:00;61.71
2017-01-01 20:00:00;56.26
2017-01-01 21:00:00;55
2017-01-01 22:00:00;54
2017-01-01 23:00:00;52
2017-01-02 00:00:00;53

date;real
2017-01-01 00:00:00;55
2017-01-01 01:00:00;55
2017-01-01 02:00:00;55
2017-01-01 03:00:00;48.27
2017-01-01 04:00:00;48.49
2017-01-01 05:00:00;48.69
2017-01-01 06:00:00;49.07
2017-01-01 07:00:00;49.67
2017-01-01 08:00:00;49.48
2017-01-01 09:00:00;50.06
2017-01-01 10:00:00;50.86
2017-01-01 11:00:00;50.02
2017-01-01 12:00:00;33.57
2017-01-01 13:00:00;33.69
2017-01-01 14:00:00;33.91
2017-01-01 15:00:00;33.43
2017-01-01 16:00:00;33.45
2017-01-01 17:00:00;33.3
2017-01-01 18:00:00;33.07
2017-01-01 19:00:00;33.71
2017-01-01 20:00:00;33.26
2017-01-01 21:00:00;33
2017-01-01 22:00:00;33
2017-01-01 23:00:00;33
2017-01-02 00:00:00;33

由于我考虑的是一年,每次 RMSE 计算我都必须考虑 365 的值。

到目前为止,我只能读取数据帧。一种选择是在 1-24 之间设置一个周期,并尝试通过 dfr[dfr.index.hour == i-th hours].

创建 24 个新数据帧

你有更优雅高效的解决方案吗?

谢谢

您需要向 by= 提供一个获取日期并提取小时的函数。

import pandas as pd
from time import strptime

df = pd.DataFrame([
['2017-01-01 00:00:00', 53],
['2017-01-01 01:00:00', 52],
['2017-01-02 00:00:00', 53],
['2017-01-03 01:00:00', 50],
['2017-01-04 00:00:00', 53]
], columns=['date', 'model'])

def group_fun(ix):
    return strptime(df['date'][ix], '%Y-%m-%d %H:%M:%S').tm_hour

print(df.groupby(by=group_fun).std())

   model
0  0.000000
1  1.414214

RMSE 取决于配对顺序,因此您应该先将 model 加入 real 数据,然后按小时分组并计算您的 RMSE:

def rmse(group):
    if len(group) == 0:
        return np.nan
    
    s = (group['model'] - group['real']).pow(2).sum()
    return np.sqrt(s / len(group))
    
result = (
    df1.merge(df2, on='date')
        .assign(hour=lambda x: x['date'].dt.hour)
        .groupby('hour')
        .apply(rmse)
)

结果:

hour
0     14.21267
1      3.00000
2      4.00000
3      1.00000
4      3.00000
5      3.00000
6      1.00000
7      4.00000
8      4.00000
9      8.00000
10     4.00000
11     2.00000
12    16.00000
13    15.00000
14    13.00000
15    16.00000
16    17.00000
17    20.00000
18    26.00000
19    28.00000
20    23.00000
21    22.00000
22    21.00000
23    19.00000
dtype: float64

说明

代码的作用如下:

  • merge:根据date索引
  • 将两个数据框组合在一起
  • assign:创建一个新列hour,从date索引中提取
  • groupby:根据 hour
  • 对行进行分组

apply 允许您编写自定义聚合器。所有 hour = 0 的行将被发送到 rmse 函数(我们的自定义函数),接下来将发送所有 hour = 1 的行。例如:

date                 hour  model  real
2017-01-01 00:00:00  0     ...    ...
2017-01-02 00:00:00  0     ...    ...
2017-01-03 00:00:00  0     ...    ...
2017-01-04 00:00:00  0     ...    ...
--------------------------------------
2017-01-01 01:00:00  1     ...    ...
2017-01-02 01:00:00  1     ...    ...
2017-01-03 01:00:00  1     ...    ...
2017-01-04 01:00:00  1     ...    ...
--------------------------------------
2017-01-01 02:00:00  2     ...    ...
2017-01-02 02:00:00  2     ...    ...
2017-01-03 02:00:00  2     ...    ...
2017-01-04 02:00:00  2     ...    ...
--------------------------------------
2017-01-01 03:00:00  3     ...    ...
2017-01-02 03:00:00  3     ...    ...
2017-01-03 03:00:00  3     ...    ...
2017-01-04 03:00:00  3     ...    ...

然后将每个块发送到我们的自定义函数:rmse(group=<a chunk>)。在函数中,我们将该块缩减为一个数字:它的 RMSE。这就是你如何得到 24 个 RMSE 数字的结果。