问题内容
我有一个极坐标数据框,其中有一列包含日期,其他列包含价格,我想计算 252 x 3 观测值窗口中每个列的百分位数。
为此,我正在这样做:
prices = prices.sort(by=["date"])
rank_cols = list(set(prices.columns).difference("date"))
percentiles = (
prices.sort(by=["date"])
.set_sorted("date")
.group_by_dynamic(
index_column=["date"], every="1i", start_by="window", period="756i"
)
.agg(
[
(pl.col(col).rank() * 100.0 / pl.col(col).count()).alias(
f"{col}_percentile"
)
for col in rank_cols
]
)
)
登录后复制
但是抛出的异常是:
traceback (most recent call last):
file "", line 6, in
file "/usr/local/lib/python3.10/site-packages/polars/dataframe/group_by.py", line 1047, in agg
self.df.lazy()
file "/usr/local/lib/python3.10/site-packages/polars/lazyframe/frame.py", line 1706, in collect
return wrap_df(ldf.collect())
polars.exceptions.invalidoperationerror: argument in operation 'group_by_dynamic' is not explicitly sorted
- if your data is already sorted, set the sorted flag with: '.set_sorted()'.
- if your data is not sorted, sort the 'expr/series/column' first.
登录后复制
在代码中,我已经按照建议执行了操作,但异常仍然存在。
编辑:
根据@hericks的建议进行一些更改。
import polars as pl
import pandas as pd
from datetime import datetime, timedelta
# generate 10 dates starting from today
start_date = datetime.now().date()
date_list = [start_date + timedelta(days=i) for i in range(10)]
# generate random prices for each date and column
data = {
'date': date_list,
'asset_1': [float(f"{i+1}.{i+2}") for i in range(10)],
'asset_2': [float(f"{i+2}.{i+3}") for i in range(10)],
'asset_3': [float(f"{i+3}.{i+4}") for i in range(10)],
}
prices = pl.dataframe(data)
prices = prices.cast({"date": pl.date})
rank_cols = list(set(prices.columns).difference("date"))
percentiles = (
prices.sort(by=["date"])
.set_sorted("date")
.group_by_dynamic(
index_column="date", every="1i", start_by="window", period="4i"
)
.agg(
[
(pl.col(col).rank() * 100.0 / pl.col(col).count()).alias(
f"{col}_percentile"
)
for col in rank_cols
]
)
)
登录后复制
现在我明白了
pyo3_runtime.panicexception: attempt to divide by zero
登录后复制
编辑2:
问题是日期的使用,我用整数更改了日期,然后就解决了问题。 (还添加了先取第一个寄存器)
import polars as pl
int_list = [i+1 for i in range(6)]
# Generate random prices for each date and column
data = {
'int_index': int_list,
'asset_1': [1.1, 3.4, 2.6, 4.8, 7.4, 3.2],
'asset_2': [4, 7, 8, 3, 4, 5],
'asset_3': [1, 3, 10, 20, 2, 4],
}
# Convert the Pandas DataFrame to a Polars DataFrame
prices = pl.DataFrame(data)
rank_cols = list(set(prices.columns).difference("int_index"))
percentiles = (
prices.sort(by="int_index")
.set_sorted("int_index")
.group_by_dynamic(
index_column="int_index", every="1i", start_by="window", period="4i"
)
.agg(
[
(pl.col(col).rank().first() * 100.0 / pl.col(col).count()).alias(
f"{col}_percentile"
)
for col in rank_cols
]
)
)
登录后复制
编辑3:
给出的想法是,索引 i 取索引 i、i+1、i+2、i+3 上的值,并计算寄存器 i 相对于这四个值的百分位等级。
例如,对于 asset_1 中的第一个索引 (1),示例(以及接下来的三个寄存器)为:
1.1、3.4、2.6、4.8,因此第一个寄存器的百分位数为 25
对于 asset_1,第二个索引 (2) 示例(以及接下来的三个寄存器)是:
3.4、2.6、4.8 和 7.4,因此百分位数为 50。
正确答案
我仍然有点猜测您期望的答案是什么,但您可能可以从这个答案开始
因此,考虑到您的示例数据:
import polars as pl
# generate random prices for each date and column
prices = pl.dataframe({
'int_index': range(6),
'asset_1': [1.1, 3.4, 2.6, 4.8, 7.4, 3.2],
'asset_2': [4, 7, 8, 3, 4, 5],
'asset_3': [1, 3, 10, 20, 2, 4],
})
┌───────────┬─────────┬─────────┬─────────┐
│ int_index ┆ asset_1 ┆ asset_2 ┆ asset_3 │
│ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ f64 ┆ i64 ┆ i64 │
╞═══════════╪═════════╪═════════╪═════════╡
│ 0 ┆ 1.1 ┆ 4 ┆ 1 │
│ 1 ┆ 3.4 ┆ 7 ┆ 3 │
│ 2 ┆ 2.6 ┆ 8 ┆ 10 │
│ 3 ┆ 4.8 ┆ 3 ┆ 20 │
│ 4 ┆ 7.4 ┆ 4 ┆ 2 │
│ 5 ┆ 3.2 ┆ 5 ┆ 4 │
└───────────┴─────────┴─────────┴─────────┘
登录后复制
使用 rolling()
创建窗口,然后(与您在问题中所做的相同) - rank().first()
除以 count()
、name.suffix()
为列分配新名称:
cols = pl.all().exclude('int_index')
percentiles = (
prices.sort(by="int_index")
.rolling(index_column="int_index", period="4i", offset="0i", closed="left")
.agg((cols.rank().first() * 100 / cols.count()).name.suffix('_percentile'))
)
┌───────────┬────────────────────┬────────────────────┬────────────────────┐
│ int_index ┆ asset_1_percentile ┆ asset_2_percentile ┆ asset_3_percentile │
│ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ f64 ┆ f64 ┆ f64 │
╞═══════════╪════════════════════╪════════════════════╪════════════════════╡
│ 0 ┆ 25.0 ┆ 50.0 ┆ 25.0 │
│ 1 ┆ 50.0 ┆ 75.0 ┆ 50.0 │
│ 2 ┆ 25.0 ┆ 100.0 ┆ 75.0 │
│ 3 ┆ 66.666667 ┆ 33.333333 ┆ 100.0 │
│ 4 ┆ 100.0 ┆ 50.0 ┆ 50.0 │
│ 5 ┆ 100.0 ┆ 100.0 ┆ 100.0 │
└───────────┴────────────────────┴────────────────────┴────────────────────┘
登录后复制
您还可以检查每个窗口内的内容:
(
prices.sort(by="int_index")
.rolling(index_column="int_index", period="4i", offset="0i", closed="left")
.agg(cols)
)
┌───────────┬───────────────────┬─────────────┬───────────────┐
│ int_index ┆ asset_1 ┆ asset_2 ┆ asset_3 │
│ --- ┆ --- ┆ --- ┆ --- │
│ i64 ┆ list[f64] ┆ list[i64] ┆ list[i64] │
╞═══════════╪═══════════════════╪═════════════╪═══════════════╡
│ 0 ┆ [1.1, 3.4, … 4.8] ┆ [4, 7, … 3] ┆ [1, 3, … 20] │
│ 1 ┆ [3.4, 2.6, … 7.4] ┆ [7, 8, … 4] ┆ [3, 10, … 2] │
│ 2 ┆ [2.6, 4.8, … 3.2] ┆ [8, 3, … 5] ┆ [10, 20, … 4] │
│ 3 ┆ [4.8, 7.4, 3.2] ┆ [3, 4, 5] ┆ [20, 2, 4] │
│ 4 ┆ [7.4, 3.2] ┆ [4, 5] ┆ [2, 4] │
│ 5 ┆ [3.2] ┆ [5] ┆ [4] │
└───────────┴───────────────────┴─────────────┴───────────────┘
登录后复制
以上就是Polar 计算百分位数的详细内容,更多请关注每日运维网(www.mryunwei.com)其它相关文章!