This has to be simple in base R, but it is driving me crazy with dplyr (which overall has made my life much better!). Suppose you have the following 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
Created on 2020-06-11 by the reprex package (v0.3.0)
Then I simply want to replace in df1 a1 with a1/b1, a2 with a2/b2 and so on. This has to be general enough to handle the case when I have many columns. Any suggestion is appreciated.
You can use 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
Or if you want a tidyverse
solution you can use map2
in purrr
:
df1[-1] <- purrr::map2(df1[-1], df2, `/`)
You can use rowwise()
with 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
Another base R option
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With