如何使用 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 diff、groupby 和 rolling功能来实现这一点。您可以使用以下步骤来实现此目的:
- 将事件时间转换为日期时间
- 使用 diff 函数计算连续时间之间的时间差,使用 total_seconds 得到以秒为单位的差值,然后除以 3600 换算成小时。
- 通过取值和时间差的乘积计算加权值
- 使用滚动函数计算加权平均值。将 window 长度保持为 2。将其除以期间的总小时数。现在是 12 小时
- 使用 groupby 和变换计算加权值的每日平均值。时间开始是 12AM
- 通过设置 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
我已经更新了答案。如果您需要更多信息,请告诉我。
所以我有一天中不规则间隔的数据。
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 diff、groupby 和 rolling功能来实现这一点。您可以使用以下步骤来实现此目的:
- 将事件时间转换为日期时间
- 使用 diff 函数计算连续时间之间的时间差,使用 total_seconds 得到以秒为单位的差值,然后除以 3600 换算成小时。
- 通过取值和时间差的乘积计算加权值
- 使用滚动函数计算加权平均值。将 window 长度保持为 2。将其除以期间的总小时数。现在是 12 小时
- 使用 groupby 和变换计算加权值的每日平均值。时间开始是 12AM
- 通过设置 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 |
我已经更新了答案。如果您需要更多信息,请告诉我。