如何使用 Python 计算时间加权平均值?

How to calculate time weighted average using Python?

所以我有一天中不规则间隔的数据。

Event Time Value
17-5-2021 03:00 84.9
17-5-2021 11:00 84.9
17-5-2021 15:00 84.7
17-5-2021 23:00 84.7
18-5-2021 03:00 84.5
18-5-2021 11:00 84.5
18-5-2021 15:00 84.9
18-5-2021 23:00 84.9

我想在上述数据上使用 python 计算时间加权平均值,因为值仅为 83.7 占 37.5%(24 小时中的 9 小时),如果计算正常平均值,它将占 50% 17-5-2021.

假设:如果我们没有特定时间间隔的值,则采用最后一个可用值,例如:17-5-2021 04:00 的值是 84.9,因为这是最后一个可用值。 任何输入都会有所帮助,因为我无法找到正确的方法来解决这个问题。 预期输出:

Please see the image for Calculation

最终结果

Event Time Weighted Average
17-5-2021 84.79166
18-5-2021 84.71666

一旦您正确地解析了数据,您就可以使用 datetime 将 dates/times 翻译成例如

from datetime import datetime
datetime.strptime('17-5-2021 03:00','%d-%m-%Y %H:%M')

这将创建一个 datetime 对象 datetime.datetime(2021, 5, 17, 3, 0)

然后可以在两个后续(有效)值之间计算 timedelta 对象,只需减去两个 datetime 对象即可。要获得该值的权重,您可以使用生成的 timedelta 对象的 .total_seconds() 方法。

例如,这两个条目 17-5-2021 11:00 84.9 17-5-2021 15:00 84.7 可用于计算第二个的权重

w=(datetime.strptime(t2,'%d-%m-%Y %H:%M')-datetime.strptime(t1,'%d-%m-%Y %H:%M')).total_seconds()

当然,

t1='17-5-2021 11:00'
t2='17-5-2021 15:00'

结果是w=14400。

假设您的数据在元组列表中,如

b="""17-5-2021 03:00        84.9
17-5-2021 11:00     84.9
17-5-2021 15:00     84.7
17-5-2021 23:00     84.7
18-5-2021 03:00     84.5
18-5-2021 11:00     84.5
18-5-2021 15:00     84.9
18-5-2021 23:00     84.9""".split()
items=[(' '.join(b[i:i+2]),float(b[i+2])) for i in range(0,len(b),3)]

items

的收益率
[('17-5-2021 03:00', 84.9), ('17-5-2021 11:00', 84.9), ('17-5-2021 15:00', 84.7), ('17-5-2021 23:00', 84.7), ('18-5-2021 03:00', 84.5), ('18-5-2021 11:00', 84.5), ('18-5-2021 15:00', 84.9), ('18-5-2021 23:00', 84.9)]

然后你可以把每个人的总和(w * val)除以最后的总持续时间,如

t1,val1=items[0]
dt1=datetime.strptime(t1,'%d-%m-%Y %H:%M')
dt0=dt1
result=0.
for item in items[1:]:
  t2,val2=item
  if val2==None: val2=val1 # if value doesn't exist, use previous
  dt2=datetime.strptime(t2,'%d-%m-%Y %H:%M')
  result+=val2*(dt2-dt1).total_seconds()
  dt1=dt2
  val1=val2

result/=(dt1-dt0).total_seconds()

如果该值不可用,我假设 None。当然,如果第一个值不存在,这将不起作用。

我只是提一下,对于您提供的 table,结果是 84.73636363636363

我认为你可以使用 pandas diffgroupbyrolling功能来实现这一点。您可以使用以下步骤来实现此目的:

  1. 将事件时间转换为日期时间
  2. 使用 diff 函数计算连续时间之间的时间差,使用 total_seconds 得到以秒为单位的差值,然后除以 3600 换算成小时。
  3. 通过取值和时间差的乘积计算加权值
  4. 使用滚动函数计算加权平均值。将 window 长度保持为 2。将其除以期间的总小时数。现在是 12 小时
  5. 使用 groupby 和变换计算加权值的每日平均值。时间开始是 12AM
  6. 通过设置 datetimeindex 并将 window 作为 1D 传递来计算滚动日平均值。
import pandas as pd

df = pd.read_csv('test.csv')
df['Event Time'] = pd.to_datetime(df['Event Time'])
df['Time Diff'] = df['Event Time'].diff(periods=1).dt.total_seconds()/3600
df['Time Diff'] = df['Time Diff'].fillna(4) 
# You dont need to do the above step in large data. Dropping would be better for large data
df['Weighted Value'] = df['Value']*df['Time Diff']
# calculate the weighted average based on number of periods
df['Weighted Average'] = df['Weighted Value'].rolling(2).sum()/12
# calculate average for each day.day starts at 12AM
df['Daily Weighted Fixed Window'] = df.groupby(df['Event Time'].dt.date)['Weighted Value'].transform('sum')/24
# calculate the weighted average for last one day (stats from current time minus 24 hours)
df.set_index('Event Time', inplace=True)
df['Daily Weighted Rolling'] = df['Weighted Value'].rolling('1D').sum()/24 
Event Time Value Time Diff Weighted Value Weighted Average Daily Weighted Fixed Window Daily Weighted Rolling
2021-05-17 03:00:00 84.9 4 339.6 nan 84.8 14.15
2021-05-17 11:00:00 84.9 8 679.2 84.9 84.8 42.45
2021-05-17 15:00:00 84.7 4 338.8 84.8333 84.8 56.5667
2021-05-17 23:00:00 84.7 8 677.6 84.7 84.8 84.8
2021-05-18 03:00:00 84.5 4 338 84.6333 84.7 84.7333
2021-05-18 11:00:00 84.5 8 676 84.5 84.7 84.6
2021-05-18 15:00:00 84.9 4 339.6 84.6333 84.7 84.6333
2021-05-18 23:00:00 84.9 8 679.2 84.9 84.7 84.7

我已经更新了答案。如果您需要更多信息,请告诉我。