计算正态分布样本在极坐标组中最小的概率python

问题描述 投票:0回答:1

我有一个极坐标数据框:

df = pl.DataFrame(
    {
        "group": [1, 1, 1, 2, 2, 2, 2],
        "mean": [25.5, 25.2, 24.9, 50.5, 55.1, 54.2, 60],
        "std": [2.5, 3.5, 1.7, 10.2, 5.5, 7.8, 20.5],
    }
)

对于每一行,我们都有正态分布的平均值和标准差。我想添加一列,表示采样时该行在其组中具有最低值的概率。

严格要求该列添加可以输入到

with_columns
调用中的表达式。

我能够写出以下内容:

def probability_smallest_in_group(series):
    length = len(series)
    means = series.struct.field("mean").to_numpy()
    stds = series.struct.field("std").to_numpy()
    samples = 100_000
    pos = np.argsort(np.argsort(np.random.normal(means, stds, size=(samples, length))))
    result = (pos == 0).mean(axis=0)
    result = pl.Series(result)
    return result


df = df.with_columns(
    pl.struct(["mean", "std"])
    .apply(probability_smallest_in_group)
    .over("group")
    .alias("probability_smallest_in_group")
)

我相信这会输出正确的结果(大约)。然而,由于实际数据帧有几百万行,该解决方案是不可行的 - 导致荒谬的执行时间。

解决这个问题的更好方法是什么?有没有不涉及采样的解决方案?

非常感谢任何帮助,所以提前谢谢您!

python python-polars normal-distribution
1个回答
0
投票

你绝对可以在不采样的情况下做到这一点,说实话,我认为你的方法没有达到你想要的效果。窗口函数似乎没有批量调用您的自定义函数(要看到这一点,请在顶部添加一个

print(series)
。另外,我不确定让 rng 首先吐出最低值是否是同一件事就说你的房车是最低的。

我对我认为你正在尝试做的事情的回顾:在每个组中,你有很多随机变量,并且你想知道其中每个变量低于该组中所有其他随机变量的概率。

为了确定一个 RV 小于另一个 RV 的概率,您可以这样做this。但是,您不仅仅想要 rv1 < rv2, you want rv1 的概率

将其带回极坐标,您需要创建每组中所有 rv 的成对映射,然后获取其乘积。

您开始于:

df = pl.DataFrame(
    {
        "group": [1, 1, 1, 2, 2, 2, 2],
        "mean": [25.5, 25.2, 24.9, 50.5, 55.1, 54.2, 60],
        "std": [2.5, 3.5, 1.7, 10.2, 5.5, 7.8, 20.5],
    }
)

我们可以这样做:

from scipy.special import ndtr
df=df.with_columns(j=pl.int_range(0,pl.count()).over('group')).lazy()
(df
 .join(
     df, 
     how='cross')
 .filter((pl.col('group')==pl.col('group_right')) & (pl.col('j_right')!=pl.col('j')))
 .with_columns(
     left_smaller=ndtr(
         (-(pl.col('mean')-pl.col('mean_right')))/
         (pl.col('std').pow(2)+pl.col('std_right').pow(2)).pow(0.5))
     )
 .group_by(['group','j'])
 .agg(probability_smallest_in_group=pl.col('left_smaller').product())
 .join(df, on=['group','j'])
 .select('group','mean','std','probability_smallest_in_group')
)
shape: (7, 4)
┌───────┬──────┬──────┬───────────────────────────────┐
│ group ┆ mean ┆ std  ┆ probability_smallest_in_group │
│ ---   ┆ ---  ┆ ---  ┆ ---                           │
│ i64   ┆ f64  ┆ f64  ┆ f64                           │
╞═══════╪══════╪══════╪═══════════════════════════════╡
│ 1     ┆ 25.5 ┆ 2.5  ┆ 0.198956                      │
│ 1     ┆ 25.2 ┆ 3.5  ┆ 0.247683                      │
│ 1     ┆ 24.9 ┆ 1.7  ┆ 0.30711                       │
│ 2     ┆ 50.5 ┆ 10.2 ┆ 0.265239                      │
│ 2     ┆ 55.1 ┆ 5.5  ┆ 0.094526                      │
│ 2     ┆ 54.2 ┆ 7.8  ┆ 0.125587                      │
│ 2     ┆ 60.0 ┆ 20.5 ┆ 0.054846                      │
└───────┴──────┴──────┴───────────────────────────────┘

这使用 scipy.special 的

ndtr
函数来计算 0 点处的 cdf,这意味着左侧 rv 更小。它是一个 ufunc,因此可以直接与表达式一起使用(如上所示)。如果这太慢,您可以尝试通过将过滤器更改为仅采用
j_right>j
来利用对称性,获取这些行的 cdf,同时将其保存到中间变量。使用中间变量,您可以通过交换左右列并取
left_smaller
的补数来取回所有过滤的行。看起来像这样:

step1=(df
 .join(
     df, 
     how='cross')
 .filter((pl.col('group')==pl.col('group_right')) & (pl.col('j_right')>pl.col('j')))
 .with_columns(
     left_smaller=ndtr(
         (-(pl.col('mean')-pl.col('mean_right')))/
         (pl.col('std').pow(2)+pl.col('std_right').pow(2)).pow(0.5))
     ))

(pl.concat([step1,
           step1.select(
    'group',
    mean=pl.col('mean_right'),
    std=pl.col('std_right'),
    j=pl.col('j_right'),
    group_right=pl.col('group'),
    mean_right=pl.col('mean'),
    std_right=pl.col('std'),
    j_right=pl.col('j'),
    left_smaller=1-pl.col('left_smaller')
)]).group_by(['group','j'])
 .agg(probability_smallest_in_group=pl.col('left_smaller').product())
 .join(df, on=['group','j'])
 .select('group','mean','std','probability_smallest_in_group')
 .collect()
)
shape: (7, 4)
┌───────┬──────┬──────┬───────────────────────────────┐
│ group ┆ mean ┆ std  ┆ probability_smallest_in_group │
│ ---   ┆ ---  ┆ ---  ┆ ---                           │
│ i64   ┆ f64  ┆ f64  ┆ f64                           │
╞═══════╪══════╪══════╪═══════════════════════════════╡
│ 1     ┆ 25.5 ┆ 2.5  ┆ 0.198956                      │
│ 1     ┆ 25.2 ┆ 3.5  ┆ 0.247683                      │
│ 1     ┆ 24.9 ┆ 1.7  ┆ 0.30711                       │
│ 2     ┆ 50.5 ┆ 10.2 ┆ 0.265239                      │
│ 2     ┆ 55.1 ┆ 5.5  ┆ 0.094526                      │
│ 2     ┆ 54.2 ┆ 7.8  ┆ 0.125587                      │
│ 2     ┆ 60.0 ┆ 20.5 ┆ 0.054846                      │
└───────┴──────┴──────┴───────────────────────────────┘
© www.soinside.com 2019 - 2024. All rights reserved.