You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在tidyverse中用across()按列应用自定义函数?

问题

在tidyverse中基于现有列使用自定义函数创建新列时,希望借助across()的动态重命名功能简化多变量处理,但当前代码未按预期按列执行函数:修改参数P的值时输出异常,尤其当P设为1时,函数似乎按元素而非按列执行,需要更简洁高效的实现方式。

Reprex

set.seed(123)
df <- tibble(id = 1:10,
             rosa = runif(10, min = 20.8, max = 36.5),
             lila = runif(10, min = 17, max = 37),
             blaue = runif(10, min = 23.3, max = 32.7))
df[c(2, 5, 8), c(2:4)] <- NA

当前代码

myfun <- function(x, P = 2, na.rm = FALSE){
    P ^ (min(x, na.rm = na.rm) - x)
}

P <- c(2, 1.5, 1.1) # 修改此参数会导致输出异常
names <- c("rosa", "lila", "blaue")
df %>%
    select(!!names) %>%
    mutate(across(.cols = !!names,
                  .fns = ~myfun(.x, P, na.rm = TRUE),
                  .names = "{.col}_P"))

当前输出

# A tibble: 10 × 6
    rosa  lila blaue    rosa_P     lila_P  blaue_P
   <dbl> <dbl> <dbl>     <dbl>      <dbl>    <dbl>
 1  25.3  36.1  31.7  0.0718    0.0000526  0.00793
 2  NA    NA    NA   NA        NA         NA      
 3  27.2  30.6  29.3  0.581     0.439      0.643  
 4  34.7  28.5  32.6  0.000110  0.0108     0.00401
 5  NA    NA    NA   NA        NA         NA      
 6  21.5  35.0  30.0  1         0.288      0.605  
 7  29.1  21.9  28.4  0.00524   1          0.0753 
 8  NA    NA    NA   NA        NA         NA      
 9  29.5  23.6  26.0  0.469     0.856      0.881  
10  28.0  36.1  24.7  0.0114    0.0000543  1      

警告信息:

1: Problem while computing `..1 = across(...)`.
ℹ longer object length is not a multiple of shorter object length 
2: Problem while computing `..1 = across(...)`.
ℹ longer object length is not a multiple of shorter object length 
3: Problem while computing `..1 = across(...)`.
ℹ longer object length is not a multiple of shorter object length 

预期输出

df %>%
select(!!names) %>%
mutate(rosa_P =  2^(min(rosa, na.rm = TRUE) - rosa)) %>%
mutate(lila_P =  1.5^(min(lila, na.rm = TRUE) - lila)) %>%
mutate(blaue_P = 1.1^(min(blaue, na.rm = TRUE) - blaue))

输出结果:

# A tibble: 10 × 6
    rosa  lila blaue    rosa_P   lila_P blaue_P
   <dbl> <dbl> <dbl>     <dbl>    <dbl>   <dbl>
 1  25.3  36.1  31.7  0.0718    0.00314   0.514
 2  NA    NA    NA   NA        NA        NA    
 3  27.2  30.6  29.3  0.0192    0.0302    0.643
 4  34.7  28.5  32.6  0.000110  0.0708    0.468
 5  NA    NA    NA   NA        NA        NA    
 6  21.5  35.0  30.0  1         0.00498   0.605
 7  29.1  21.9  28.4  0.00524   1         0.701
 8  NA    NA    NA   NA        NA        NA    
 9  29.5  23.6  26.0  0.00407   0.515     0.881
10  28.0  36.1  24.7  0.0114    0.00320   1    
解决方案

问题根源在于原代码把整个P向量传给了每一列的函数,R会自动循环补齐向量长度,导致计算逻辑偏离预期。我们需要让每一列对应一个专属的P值,实现方式如下:

方法一:保留自定义函数

myfun <- function(x, P = 2, na.rm = FALSE){
  P ^ (min(x, na.rm = na.rm) - x)
}

# 将P设置为命名向量,与列名一一对应
P_vec <- c(rosa = 2, lila = 1.5, blaue = 1.1)

df %>%
  select(all_of(names(P_vec))) %>%
  mutate(across(all_of(names(P_vec)),
                ~myfun(.x, P = P_vec[cur_column()], na.rm = TRUE),
                .names = "{.col}_P"))

方法二:移除自定义函数,简化代码

P_vec <- c(rosa = 2, lila = 1.5, blaue = 1.1)

df %>%
  select(all_of(names(P_vec))) %>%
  mutate(across(all_of(names(P_vec)),
                ~P_vec[cur_column()] ^ (min(.x, na.rm = TRUE) - .x),
                .names = "{.col}_P"))

核心逻辑说明

  • 将P设置为命名向量,确保列名与参数值一一绑定
  • 使用cur_column()获取当前处理的列名,精准匹配对应的P值
  • 彻底避免向量循环补齐导致的计算错误,保证每列用专属参数执行计算

内容的提问来源于stack exchange,提问作者doctorate

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 05:36:17