r语言 - 在 dplyr 中按向量划分所选列



这在基础R中必须很简单,但它让我对dplyr发疯(总的来说,它让我的生活变得更好! 假设您有以下提示

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

df1 <- tibble(x=seq(5)*19, a1=seq(5)*1, a2=seq(5)*2, a3=seq(5)*4)
df1
#> # A tibble: 5 x 4
#>       x    a1    a2    a3
#>   <dbl> <dbl> <dbl> <dbl>
#> 1    19     1     2     4
#> 2    38     2     4     8
#> 3    57     3     6    12
#> 4    76     4     8    16
#> 5    95     5    10    20

df2 <- tibble(b1=3, b2=0.5, b3=10)
df2
#> # A tibble: 1 x 3
#>      b1    b2    b3
#>   <dbl> <dbl> <dbl>
#> 1     3   0.5    10

创建于 2020-06-11 由 reprex 软件包 (v0.3.0(

然后我只想将 df1 a1 替换为 a1/b1,将 a2 替换为 a2/b2,依此类推。 这必须足够通用,以便在我有很多列时处理这种情况。 任何建议不胜感激。

您可以使用Map

df1[-1] <- Map(`/`, df1[-1], df2)
# A tibble: 5 x 4
#      x    a1    a2    a3
#  <dbl> <dbl> <dbl> <dbl>
#1    19 0.333     4   0.4
#2    38 0.667     8   0.8
#3    57 1        12   1.2
#4    76 1.33     16   1.6
#5    95 1.67     20   2  

或者,如果您想要一个tidyverse解决方案,您可以在purrr中使用map2

df1[-1] <- purrr::map2(df1[-1], df2, `/`)

您可以将rowwise()c_across()一起使用

df1 %>%
rowwise() %>% 
mutate(c_across(a1:a3) / df2, .keep = "unused") %>%
ungroup()
# # A tibble: 5 x 4
#       x    b1    b2    b3
#   <dbl> <dbl> <dbl> <dbl>
# 1    19 0.333     4   0.4
# 2    38 0.667     8   0.8
# 3    57 1        12   1.2
# 4    76 1.33     16   1.6
# 5    95 1.67     20   2  

另一个基本 R 选项

df1[-1] <- t(t(df1[-1]) / unlist(df2))
df1
# # A tibble: 5 x 4
#       x    a1    a2    a3
#   <dbl> <dbl> <dbl> <dbl>
# 1    19 0.333     4   0.4
# 2    38 0.667     8   0.8
# 3    57 1        12   1.2
# 4    76 1.33     16   1.6
# 5    95 1.67     20   2  

一种解决方案可能是:

bind_cols(select(df1, x),
sweep(select(df1, -x), 2, FUN = `/`, unlist(df2)))
x    a1    a2    a3
<dbl> <dbl> <dbl> <dbl>
1    19 0.333     4   0.4
2    38 0.667     8   0.8
3    57 1        12   1.2
4    76 1.33     16   1.6
5    95 1.67     20   2  

或者像这样,如果你有更多的列:

df1[,2:4] <- df1[,2:4] / df2 %>% slice(rep(1:n(), each = nrow(df1)))
# A tibble: 5 x 4
x    a1    a2    a3
<dbl> <dbl> <dbl> <dbl>
1    19 0.111     8  0.04
2    38 0.222    16  0.08
3    57 0.333    24  0.12
4    76 0.444    32  0.16
5    95 0.556    40  0.2 

另一个选项,它考虑变量的列名,并将它们与必须除以的数字配对。cur_column()mutate(across())中派上用场的功能 - 您要使用的功能

# vector of divisors
l <- as.list(as.numeric(df2[1,]))
df1 %>% 
mutate(across(starts_with("a"),
~ ./l[[na.omit(as.numeric(unlist(strsplit(cur_column(), "[^[:digit:]]"))))]]))

输出

# A tibble: 5 x 4
#       x    a1    a2    a3
#   <dbl> <dbl> <dbl> <dbl>
# 1    19 0.333     4   0.4
# 2    38 0.667     8   0.8
# 3    57 1        12   1.2
# 4    76 1.33     16   1.6
# 5    95 1.67     20   2  

一个带有base R的选项

df1[-1] <- df1[-1]/unlist(df2)[col(df1)]

最新更新