Python:将数据与 运行 window 数据集的第 95 个百分位数进行比较
Python: Compare data against the 95th percentile of a running window dataset
我有一个包含数千行但只有 2 列的大型 DataFrame。 2 列的格式如下:
Dt
Val
2020-01-01
10.5
2020-01-01
11.2
2020-01-01
10.9
2020-01-03
11.3
2020-01-05
12.0
第一列是日期,第二列是值。对于每个日期,可能有零个、一个或多个值。
我需要做的是:根据刚刚过去的 30 天计算第 95 个百分位数,看看当前值是高于还是低于第 95 个百分位数.但是,过去 30 天必须至少有 50 个值可用。
例如,如果记录的日期为“2020-12-01”,值为“10.5”,那么我需要先查看日期范围为 2020-11-01 到 2020- 有多少个值可用- 11-30。如果在该日期范围内至少有 50 个值可用,那么我将要计算这些值的第 95 个百分位数并将 10.5 与该值进行比较。如果 10.5 大于第 95 个百分位值,则该记录的结果为“高于阈值”。如果 10.5 小于第 95 个百分位值,则该记录的结果为“低于阈值”。如果 2020-11-01 到 2020-11-30 日期范围内的值少于 50 个,则该记录的结果为“数据不足”。
我想尽可能避免 运行 循环,因为从资源和时间的角度来看,循环遍历数千条记录以逐条处理它们可能很昂贵。我希望有人可以在这里建议一个简单的 (r) python / pandas 解决方案。
对 DatetimeIndex 使用滚动获取过去 30 天内可用值的数量和第 95 个百分位数。这是一个滚动 3 天的示例 window:
import datetime
import pandas as pd
df = pd.DataFrame({'val':[1,2,3,4,5,6]},
index = [datetime.date(2020,10,1), datetime.date(2020,10,1), datetime.date(2020,10,2),
datetime.date(2020,10,3), datetime.date(2020,10,3), datetime.date(2020,10,4)])
df.index = pd.DatetimeIndex(df.index)
df['number_of_values'] = df.rolling('3D').count()
df['rolling_percentile'] = df.rolling('3D')['val'].quantile(0.9, interpolation='nearest')
那你就可以简单的比较一下:
# Above Threshold
(df['val']>df['rolling_percentile'])&(df['number_of_values']>=50)
# Below Threshold
(df['val']>df['rolling_percentile'])&(df['number_of_values']>=50)
# Insufficient Data
df['number_of_values']<50
要删除当前日期,close
参数一天不能超过一行,因此可以使用滚动应用:
def f(x, metric):
x = x[x.index!=x.index[-1]]
if metric == 'count':
return len(x)
elif metric == 'percentile':
return x.quantile(0.9, interpolation='nearest')
else:
return np.nan
df = pd.DataFrame({'val':[1,2,3,4,5,6]},
index = [datetime.date(2020,10,1), datetime.date(2020,10,1), datetime.date(2020,10,2),
datetime.date(2020,10,3), datetime.date(2020,10,3), datetime.date(2020,10,4)])
df.index = pd.DatetimeIndex(df.index)
df['count'] = df.rolling('3D')['val'].apply(f, args = ('count',))
df['percentile'] = df.rolling('3D')['val'].apply(f, args = ('percentile',))
val count percentile
2020-10-01 1 0.0 NaN
2020-10-01 2 0.0 NaN
2020-10-02 3 2.0 2.0
2020-10-03 4 3.0 3.0
2020-10-03 5 3.0 3.0
2020-10-04 6 3.0 5.0
我有一个包含数千行但只有 2 列的大型 DataFrame。 2 列的格式如下:
Dt | Val |
---|---|
2020-01-01 | 10.5 |
2020-01-01 | 11.2 |
2020-01-01 | 10.9 |
2020-01-03 | 11.3 |
2020-01-05 | 12.0 |
第一列是日期,第二列是值。对于每个日期,可能有零个、一个或多个值。
我需要做的是:根据刚刚过去的 30 天计算第 95 个百分位数,看看当前值是高于还是低于第 95 个百分位数.但是,过去 30 天必须至少有 50 个值可用。
例如,如果记录的日期为“2020-12-01”,值为“10.5”,那么我需要先查看日期范围为 2020-11-01 到 2020- 有多少个值可用- 11-30。如果在该日期范围内至少有 50 个值可用,那么我将要计算这些值的第 95 个百分位数并将 10.5 与该值进行比较。如果 10.5 大于第 95 个百分位值,则该记录的结果为“高于阈值”。如果 10.5 小于第 95 个百分位值,则该记录的结果为“低于阈值”。如果 2020-11-01 到 2020-11-30 日期范围内的值少于 50 个,则该记录的结果为“数据不足”。
我想尽可能避免 运行 循环,因为从资源和时间的角度来看,循环遍历数千条记录以逐条处理它们可能很昂贵。我希望有人可以在这里建议一个简单的 (r) python / pandas 解决方案。
对 DatetimeIndex 使用滚动获取过去 30 天内可用值的数量和第 95 个百分位数。这是一个滚动 3 天的示例 window:
import datetime
import pandas as pd
df = pd.DataFrame({'val':[1,2,3,4,5,6]},
index = [datetime.date(2020,10,1), datetime.date(2020,10,1), datetime.date(2020,10,2),
datetime.date(2020,10,3), datetime.date(2020,10,3), datetime.date(2020,10,4)])
df.index = pd.DatetimeIndex(df.index)
df['number_of_values'] = df.rolling('3D').count()
df['rolling_percentile'] = df.rolling('3D')['val'].quantile(0.9, interpolation='nearest')
那你就可以简单的比较一下:
# Above Threshold
(df['val']>df['rolling_percentile'])&(df['number_of_values']>=50)
# Below Threshold
(df['val']>df['rolling_percentile'])&(df['number_of_values']>=50)
# Insufficient Data
df['number_of_values']<50
要删除当前日期,close
参数一天不能超过一行,因此可以使用滚动应用:
def f(x, metric):
x = x[x.index!=x.index[-1]]
if metric == 'count':
return len(x)
elif metric == 'percentile':
return x.quantile(0.9, interpolation='nearest')
else:
return np.nan
df = pd.DataFrame({'val':[1,2,3,4,5,6]},
index = [datetime.date(2020,10,1), datetime.date(2020,10,1), datetime.date(2020,10,2),
datetime.date(2020,10,3), datetime.date(2020,10,3), datetime.date(2020,10,4)])
df.index = pd.DatetimeIndex(df.index)
df['count'] = df.rolling('3D')['val'].apply(f, args = ('count',))
df['percentile'] = df.rolling('3D')['val'].apply(f, args = ('percentile',))
val count percentile
2020-10-01 1 0.0 NaN
2020-10-01 2 0.0 NaN
2020-10-02 3 2.0 2.0
2020-10-03 4 3.0 3.0
2020-10-03 5 3.0 3.0
2020-10-04 6 3.0 5.0