我想计算 Polars 列中每一行的分位数。 Polars 有一个分位数函数,用于计算对应于输入分位数的值(逆 CDF),但它似乎没有任何类型的经验 CDF 函数。
Polars 目前具备此功能吗?
最佳答案
原始答案,滚动到末尾以获得更简洁的解决方案
您可以通过按相关值排序然后获取 cum_count
/count
来导出 ecdf
例如,让我们将其与plotly 的 ecdf 进行比较
import polars as pl
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
df=pl.DataFrame({'a':np.random.normal(10,5,1000)})
df_ecdf = df.sort('a').with_columns(
ecdf=((pl.first().cum_count()+1)/(pl.count()))
)
myecdf=px.line(df_ecdf,
x='a', y='ecdf')
myecdf.update_traces(line_color='red')
pxecdf=px.ecdf(df,
x='a')
fig=go.Figure()
fig.add_trace(list(myecdf.select_traces())[0])
fig.add_trace(list(pxecdf.select_traces())[0])
fig.show()
Plotly 的 ecdf 似乎有更多的阶梯,我无法解释,如果我们放大到任意部分,它可以更容易看到......
也就是说,与 px.ecdf 相比,px.line 可能被过度平滑。
如果我们从 pxecdf
中提取数据,那么我们就可以进行数值比较。
compare=pl.DataFrame({'plotly_ecdf': pxecdf._data[0]['y'],
'plotly_x':pxecdf._data[0]['x']})
compare=df_ecdf.join(compare, left_on='a', right_on='plotly_x')
compare.select(diff=(pl.col('ecdf')-pl.col('plotly_ecdf')).abs().sum())
### returns 0
因此 px.ecdf 中的可见阶梯必须由 px.line 中的某些默认平滑驱动,该平滑不会应用于 px.ecdf,因为它们在数值上是相同的。
对评论的回应以及更简洁的做法
这里有一种方法,您可以仅通过表达式并行生成任意数量的列的 ecdf。
df=pl.DataFrame({'a':np.random.normal(10,5,1000),
'b':np.random.normal(10,5,1000),
'c':np.random.normal(10,5,1000)})
(
df
.with_columns(**{
f"{x}_ecdf":pl.int_range(1,pl.count()+1).sort_by(pl.arg_sort_by(x))/pl.count()
for x in df.columns # change df.columns to list of columns for subset only
})
)
┌───────────┬───────────┬───────────┬────────┬────────┬────────┐
│ a ┆ b ┆ c ┆ a_ecdf ┆ b_ecdf ┆ c_ecdf │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ f64 ┆ f64 ┆ f64 ┆ f64 ┆ f64 ┆ f64 │
╞═══════════╪═══════════╪═══════════╪════════╪════════╪════════╡
│ 3.115462 ┆ 15.602951 ┆ 1.041053 ┆ 0.085 ┆ 0.873 ┆ 0.033 │
│ 4.481795 ┆ 1.868424 ┆ 9.563978 ┆ 0.121 ┆ 0.044 ┆ 0.477 │
│ 12.686753 ┆ 11.747184 ┆ 9.464207 ┆ 0.673 ┆ 0.644 ┆ 0.462 │
│ 11.416048 ┆ 13.163161 ┆ -0.304657 ┆ 0.598 ┆ 0.739 ┆ 0.02 │
│ 18.453647 ┆ 11.83464 ┆ 8.279558 ┆ 0.956 ┆ 0.649 ┆ 0.359 │
└───────────┴───────────┴───────────┴────────┴────────┴────────┘
理论上,您实际上应该在惰性模式下执行此操作(或在另一个上下文中预先生成 int_range),否则它将为每个列生成 int_range
系列,而不是一次性生成并使用对于每一列。实际上,这可能并不重要,因为这是一个微不足道的操作。
关于python-polars - 计算 Polars 列中某个值的分位数,又称为 Polars CDF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77687322/