假设我有一个数据帧,它有一个名为mean的列,我想将其用作随机数生成器的输入.来自R,这在管道中相对容易完成:

library(dplyr)

tibble(alpha = rnorm(1000),
       beta = rnorm(1000)) %>%
  mutate(mean = alpha + beta) %>%
  bind_cols(random_output = rnorm(n = nrow(.), mean = .$mean, sd = 1))
#> # A tibble: 1,000 × 4
#>     alpha   beta    mean random_output
#>     <dbl>  <dbl>   <dbl>         <dbl>
#>  1  0.231 -0.243 -0.0125         0.551
#>  2  0.213  0.647  0.861          0.668
#>  3  0.824 -0.353  0.471          0.852
#>  4  0.665 -0.916 -0.252         -1.81 
#>  5 -0.850  0.384 -0.465         -3.90 
#>  6  0.721  0.679  1.40           2.54 
#>  7  1.46   0.857  2.32           2.14 
#>  8 -0.242 -0.431 -0.673         -0.820
#>  9  0.234  0.188  0.422         -0.662
#> 10 -0.494 -2.15  -2.65          -3.01 
#> # ℹ 990 more rows

创建于2023-11-12年第reprex v2.0.2

在Python语言中,我可以创建一个中间数据帧并将其用作np.random.normal()的输入,然后将其绑定到数据帧,但这感觉很笨拙.有没有办法将random_output COL作为管道/链的一部分添加?

import polars as pl
import numpy as np

# create a df
df = (
    pl.DataFrame(
        {
            "alpha": np.random.standard_normal(1000),
            "beta": np.random.standard_normal(1000)
        }
    )
    .with_columns(
        (pl.col("alpha") + pl.col("beta")).alias("mean")
    )
    
)

# create an intermediate object
sim_vals = np.random.normal(df.get_column("mean"))

# bind the simulated values to the original df
(
    df.with_columns(random_output = pl.lit(sim_vals))
)
#> shape: (1_000, 4)
┌───────────┬───────────┬───────────┬───────────────┐
│ alpha     ┆ beta      ┆ mean      ┆ random_output │
│ ---       ┆ ---       ┆ ---       ┆ ---           │
│ f64       ┆ f64       ┆ f64       ┆ f64           │
╞═══════════╪═══════════╪═══════════╪═══════════════╡
│ -1.380249 ┆ 1.531959  ┆ 0.15171   ┆ 0.938207      │
│ -0.332023 ┆ -0.108255 ┆ -0.440277 ┆ 0.081628      │
│ -0.718319 ┆ -0.612187 ┆ -1.330506 ┆ -1.286229     │
│ 0.22067   ┆ -0.497258 ┆ -0.276588 ┆ 0.908147      │
│ …         ┆ …         ┆ …         ┆ …             │
│ 0.299117  ┆ -0.371846 ┆ -0.072729 ┆ 0.592632      │
│ 0.789633  ┆ 0.95712   ┆ 1.746753  ┆ 2.954801      │
│ -0.264415 ┆ -0.761634 ┆ -1.026049 ┆ -1.369753     │
│ 1.893911  ┆ 1.554736  ┆ 3.448647  ┆ 5.192537      │
└───────────┴───────────┴───────────┴───────────────┘

推荐答案

有四种方法(我能想到的),其中两种在 comments 中提到,一种我使用,最后一种我知道它存在,但并不亲自使用.

第一个(GET_COLUMN(COL)或[‘COL’])引用

使用df.get_column作为np.random.normal的参数,如果您使用pipe,则可以在链中这样做,例如

df.with_columns(
    mean=pl.col('alpha') + pl.col('beta')
).pipe(lambda df: (
    df.with_columns(
        rando=pl.lit(np.random.normal(df['mean']))
    )
))

第二个(Map_Batches)

使用map_batches作为表达式

df.with_columns(
    mean=pl.col('alpha') + pl.col('beta')
).with_columns(
    rando=pl.col('mean').map_batches(lambda col: pl.Series(np.random.normal(col)))
)

第三名(Numba)

如果您要进行许多随机化,但需要更多的设置(因此需要注意许多随机化),则此方法比前两种方法更快

numba允许您创建ufuncs,这些ufuncs是可以直接在表达式中使用的编译函数.

您可以创建仅使用默认标准差的函数

import numba as nb
@nb.guvectorize([(nb.float64[:], nb.float64[:])], '(n)->(n)', nopython=True)
def rando(means,  res):
    for i in range(len(means)):
        res[i]=np.random.normal(means[i])

然后你就可以做

df.with_columns(
    mean=pl.col('alpha') + pl.col('beta')
).with_columns(rand_nb=rando(pl.col('mean')))

更多阅读:

guvectorize

another numba example

limitation

第四部分(铁 rust 延伸)

不幸的是,对于这个答案(我假设我自己也是这样),我没有涉足RUST编程,但是有一个扩展接口,您可以通过它在RUST中创建函数并将它们部署为表达式.Here is documentation on doing that

性能

使用1M行的df我得到...

第一种方法:每循环71.1毫秒±8.06毫秒(平均值±标准差)戴夫.共7次运行,每次1次循环)

第二种方法:每循环70.7毫秒±7.88毫秒(平均值±标准差)戴夫.共7次运行,每次10次循环)

方法三:45.7ms±2.86ms/环(平均值±标准差)戴夫.共7次运行,每次10次循环)

需要注意的一点是,它不会更快,例如,除非您希望每行的平均值不同.

df.with_columns(z=rando(pl.repeat(5,pl.count()))):43.8毫秒±2.12毫秒/循环(平均值±标准戴夫.共7次运行,每次10次循环)

df.with_columns(z=pl.Series(np.random.normal(5,1,df.shape[0]))):39.6 ms ± 3.64 ms/循环(平均值±标准差)dev. 7次运行,每次10个循环)

Python相关问答推荐

如何处理必须存在于环境中但无法安装的Python项目依赖项?

pyautogui.locateOnScreen在Linux上的工作方式有所不同

基本链合同的地址是如何计算的?

在Python中为变量的缺失值创建虚拟值

如何使用矩阵在sklearn中同时对每个列执行matthews_corrcoef?

根据网格和相机参数渲染深度

提取两行之间的标题的常规表达

Python会扔掉未使用的表情吗?

TARete错误:类型对象任务没有属性模型'

Pandas 滚动最接近的价值

使可滚动框架在tkinter环境中看起来自然

按顺序合并2个词典列表

PyQt5,如何使每个对象的 colored颜色 不同?'

在Python argparse包中添加formatter_class MetavarTypeHelpFormatter时, - help不再工作""""

如何使Matplotlib标题以图形为中心,而图例框则以图形为中心

多指标不同顺序串联大Pandas 模型

处理具有多个独立头的CSV文件

如何创建引用列表并分配值的Systemrame列

如何找出Pandas 图中的连续空值(NaN)?

人口全部乱序 - Python—Matplotlib—映射