0

I have a data set that looks like the iris data set.

  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa

I would like across Sepal.Length:Petal.Width to subtract each value with the number 2 and then divide the outcome by 4. How can I do this in one line with mutate_across in dplyr instead of two?

iris %>% 
  mutate(across(c(Sepal.Length:Petal.Width), ~. -2 )) %>% 
  mutate(across(c(Sepal.Length:Petal.Width), ~. /4 )) 
AnilGoyal
  • 25,297
  • 4
  • 27
  • 45
LDT
  • 2,856
  • 2
  • 15
  • 32

5 Answers5

6
library(dplyr, warn.conflicts = F)
iris %>%
  mutate(across(1:4, ~  (. - 2)/4))
#>     Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
#> 1          0.775       0.375       -0.150      -0.450     setosa
#> 2          0.725       0.250       -0.150      -0.450     setosa
#> 3          0.675       0.300       -0.175      -0.450     setosa
#> 4          0.650       0.275       -0.125      -0.450     setosa
#> 5          0.750       0.400       -0.150      -0.450     setosa
#> 6          0.850       0.475       -0.075      -0.400     setosa
#> 7          0.650       0.350       -0.150      -0.425     setosa
#> 8          0.750       0.350       -0.125      -0.450     setosa
#> 9          0.600       0.225       -0.150      -0.450     setosa
#> 10         0.725       0.275       -0.125      -0.475     setosa
.
.

Created on 2021-07-06 by the reprex package (v2.0.0)

AnilGoyal
  • 25,297
  • 4
  • 27
  • 45
4

Subtraction and division functions can be directly applied to dataframes.

cols <- 1:4
iris[cols] <- (iris[cols] - 2)/4
head(iris)

#  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#1        0.775       0.375       -0.150       -0.45  setosa
#2        0.725       0.250       -0.150       -0.45  setosa
#3        0.675       0.300       -0.175       -0.45  setosa
#4        0.650       0.275       -0.125       -0.45  setosa
#5        0.750       0.400       -0.150       -0.45  setosa
#6        0.850       0.475       -0.075       -0.40  setosa
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
1

Another solution is using mutate_at:

iris %>%
  mutate_at(vars('Sepal.Length':'Petal.Width'), funs((. - 2) * 4))
denisafonin
  • 1,116
  • 1
  • 7
  • 16
  • Note that `_if`, `_at`, `_all` have officially been "superseded" (slightly weaker than deprecated) in `dplyr`, and you're encouraged to use `across()` instead. See `vignette("colwise")` : " These functions solved a pressing need and are used by many people, but are now superseded. That means that they’ll stay around, but won’t receive any new features and will only get critical bug fixes." – hdkrgr Jul 06 '21 at 11:51
1

An option with map_if

library(purrr)
library(dplyr)
map_if(iris, is.numeric, ~ (. - 2)/4) %>%
     bind_cols
akrun
  • 874,273
  • 37
  • 540
  • 662
0

We can try base R option like below

cols <- which(sapply(iris, is.numeric))
iris[cols] <- (iris[cols] - 2) / 4
ThomasIsCoding
  • 96,636
  • 9
  • 24
  • 81