使用dplyr将选定列除以向量

8

在基本的R语言中,这个问题很简单,但我在使用dplyr时感到非常困惑(尽管总体来说dplyr让我的生活变得更好了!)。 假设您有以下的tibbles:

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

此内容由reprex包(v0.3.0)于2020-06-11创建。

然后我只想将df1中的a1替换为a1/b1,将a2替换为a2/b2等等。 这必须足够通用,以处理许多列的情况。 欢迎任何建议。


你只是想使用 dplyr::transmute() 吗? - markhogue
我正在寻找一种基于mutate(across(a1:a3))的解决方案,但我无法编写应用函数。 - larry77
@larry77,我认为mutate(across(a1:a3))不是正确的应用程序。 - Ronak Shah
我想你是对的。在我手头的一个更复杂的案例中,我最终采用了pivot_longer和left_join。 - larry77
6个回答

4
你可以使用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, `/`)

最接近我想法的。你知道如何使用mutate(across)来实现吗?Across是dplyr中最新的好东西。 - larry77

3
你可以使用 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  

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  

好的,我已经走到了这一步。我希望能找到一些关于mutate(across)的内容。 - larry77

0

如果你有更多的列,可以这样:

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 

0

另一个选项是考虑变量的列名,并将它们与它们需要被除以的数字配对。函数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  

0

使用 base R 的选项

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接