Use an object to select columns in dplyr [duplicate] - r

I can use the following to return the maximum of 2 columns
newiris<-iris %>%
rowwise() %>%
mutate(mak=max(Sepal.Width,Petal.Length))
What I want to do is find that maximum across a range of columns so I don't have to name each one like this
newiris<-iris %>%
rowwise() %>%
mutate(mak=max(Sepal.Width:Petal.Length))
Any ideas?

Instead of rowwise(), this can be done with pmax
iris %>%
mutate(mak=pmax(Sepal.Width,Petal.Length, Petal.Width))
May be we can use interp from library(lazyeval) if we want to reference the column names stored in a vector.
library(lazyeval)
nm1 <- names(iris)[2:4]
iris %>%
mutate_(mak= interp(~pmax(v1), v1= as.name(nm1)))

With rlang and quasiquotation we have another dplyr option. First, get the row names that we want to compute the parallel max for:
iris_cols <- iris %>% select(Sepal.Length:Petal.Width) %>% names()
Then we can use !!! and rlang::syms to compute the parallel max for every row of those columns:
iris %>%
mutate(mak=pmax(!!!rlang::syms(iris_cols)))
rlang::syms takes a string input (the column names), and turns it into a symbol
!!! unquotes and splices its argument, here the column names
Which gives:
Sepal.Length Sepal.Width Petal.Length Petal.Width Species mak
1 5.1 3.5 1.4 0.2 setosa 5.1
2 4.9 3.0 1.4 0.2 setosa 4.9
3 4.7 3.2 1.3 0.2 setosa 4.7
4 4.6 3.1 1.5 0.2 setosa 4.6
5 5.0 3.6 1.4 0.2 setosa 5.0
h/t: https://stackoverflow.com/a/47773379/1036500

Currently (dplyr 1.0.2), this works:
newiris<-iris %>%
rowwise() %>%
mutate(mak=max(c_across(Sepal.Width:Petal.Length)))
this also lets you use selection helpers (starts_with etc).

For selecting some columns without typing whole names when using dplyr I prefer select parameter from subset function.
You can get desired result like this:
iris %>% subset(select = 2:4) %>% mutate(mak = do.call(pmax, (.))) %>%
select(mak) %>% cbind(iris)

One approach is to pipe the data into select then call pmax using a function that makes pmax rowwise (this is very similar to #inscaven's answer that uses do.call, unfortunately there isn't a rowMaxs function in R so we have to use a function to make pmax rowwise -- below I used purrr::pmap)
library(dplyr)
library(purrr)
# to get the value of the max
iris$rowwisemax <- iris %>% select(Sepal.Width:Petal.Length) %>% pmap(pmax) %>% as.numeric
# to get the argmax
iris$whichrowwisemax <- iris %>% select(Sepal.Width:Petal.Length) %>% {names(.)[max.col(.)]}

It seems like #akrun's answer only addresses the cases when you can type in the names of all the variables, whether that's using mutate directly with mutate(pmax_value=pmax(var1, var2)) or when using lazy evaluation with mutate_ and interp via mutate_(interp(~pmax(v1, v2), v1=as.name(var1), v2=as.name(var2)).
I can see two ways to do this if you want to use the colon syntax Sepal.Length:Petal.Width or if you happen to have a vector with the column names.
The first is more elegant. You tidy the data and take the maximum among the values when grouped:
data(iris)
library(dplyr)
library(tidyr)
iris_id = iris %>% mutate(id=1:nrow(.))
iris_id %>%
gather('attribute', 'value', Sepal.Length:Petal.Width) %>%
group_by(id) %>%
summarize(max_attribute=max(value)) %>%
right_join(iris_id, by='id') %>%
head(3)
## # A tibble: 3 × 7
## id max_attribute Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <int> <dbl> <dbl> <dbl> <dbl> <dbl> <fctr>
## 1 1 5.1 5.1 3.5 1.4 0.2 setosa
## 2 2 4.9 4.9 3.0 1.4 0.2 setosa
## 3 3 4.7 4.7 3.2 1.3 0.2 setosa
The harder way is to use an interpolated formula. This is good if you have a character vector with the names of the variables to be max'ed over or if you the table is too tall/wide for it to be tidied.
# Make a character vector of the names of the columns we want to take the
# maximum over
target_columns = iris %>% select(-Species) %>% names
## [1] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width"
# Make a vector of dummy variables that will take the place of the real
# column names inside the interpolated formula
dummy_vars = sapply(1:length(target_columns), function(i) sprintf('x%i', i))
## [1] "x1" "x2" "x3" "x4"
# Paste those variables together to make the argument of the pmax in the
# interpolated formula
dummy_vars_string = paste0(dummy_vars, collapse=',')
## [1] "x1,x2,x3,x4"
# Make a named list that maps the dummy variable names (e.g., x1) to the
# real variable names (e.g., Sepal.Length)
dummy_vars_list = lapply(target_columns, as.name) %>% setNames(dummy_vars)
## $x1
## Sepal.Length
##
## $x2
## Sepal.Width
##
## $x3
## Petal.Length
##
## $x4
## Petal.Width
# Make a pmax formula using the dummy variables
max_formula = as.formula(paste0(c('~pmax(', dummy_vars_string, ')'), collapse=''))
## ~pmax(x1, x2, x3, x4)
# Interpolate the formula using the named variables
library(lazyeval)
iris %>%
mutate_(max_attribute=interp(max_formula, .values=dummy_vars_list)) %>%
head(3)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species max_attribute
## 1 5.1 3.5 1.4 0.2 setosa 5.1
## 2 4.9 3.0 1.4 0.2 setosa 4.9
## 3 4.7 3.2 1.3 0.2 setosa 4.7

Here is a base-R solution: A range of column names can be selected with subset(). The rowwise maximum values can be added with a combination of transform() and apply().
newiris <- transform(iris, mak = apply(subset(iris, select=Sepal.Width:Petal.Length), 1, max))

If one wants to use selection helpers like contains(), starts_with() we may use
library(dplyr)
iris |>
mutate(max_value = purrr::pmap_dbl(select(iris, contains("petal")), pmax, na.rm=TRUE))

Related

How to use mutate inside a function with formulas instead of .dots and mutate_?

I used to use mutate_ with .dots argument to evaluate a set of formulas inside a function using a mix of user supplied variables (in string format) and variables calculated inside the function (as the b variable below) as follows:
require(dplyr)
f <- function(data, a)
{
b <- "Sepal.Length"
mutate_call <- list(new_1 = lazyeval::interp( ~ a*10, a=as.name(a)),
new_2 = lazyeval::interp( ~ b*10, b=as.name(b)) )
data %>%
as_tibble() %>%
mutate_(.dots = mutate_call) %>%
head() %>%
print()
}
f(iris, "Sepal.Width")
however, when transitioning to recent dplyr version, this is no longer possible (unless I keep using the deprecated version mutate_). How can I achieve the same result as f does using mutate instead of mutate_?
It would much easier if I could keep using the formulas.
My suggestions would be to switch from formulas to expressions, then use the unquote-splice operator !!! with regular mutate():
f <- function(data, a)
{
# Convert strings to symbols
a <- as.name(a)
b <- as.name("Sepal.Length")
# Use rlang::exprs to define the expressions
# Use !! to replace a and b with the symbols stored inside them
mutate_call <- rlang::exprs(new_1 = !!a*10, new_2 = !!b*10)
data %>%
as_tibble() %>%
mutate(!!!mutate_call) %>% # <-- !!! effectively "pastes" the expressions
head() %>%
print()
}
f(iris, "Sepal.Width")
# # A tibble: 6 x 7
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species new_1 new_2
# <dbl> <dbl> <dbl> <dbl> <fct> <dbl> <dbl>
# 1 5.1 3.5 1.4 0.2 setosa 35 51
# 2 4.9 3 1.4 0.2 setosa 30 49
# 3 4.7 3.2 1.3 0.2 setosa 32 47
# 4 4.6 3.1 1.5 0.2 setosa 31 46

Return the largest value of selected columns in one row [duplicate]

I can use the following to return the maximum of 2 columns
newiris<-iris %>%
rowwise() %>%
mutate(mak=max(Sepal.Width,Petal.Length))
What I want to do is find that maximum across a range of columns so I don't have to name each one like this
newiris<-iris %>%
rowwise() %>%
mutate(mak=max(Sepal.Width:Petal.Length))
Any ideas?
Instead of rowwise(), this can be done with pmax
iris %>%
mutate(mak=pmax(Sepal.Width,Petal.Length, Petal.Width))
May be we can use interp from library(lazyeval) if we want to reference the column names stored in a vector.
library(lazyeval)
nm1 <- names(iris)[2:4]
iris %>%
mutate_(mak= interp(~pmax(v1), v1= as.name(nm1)))
With rlang and quasiquotation we have another dplyr option. First, get the row names that we want to compute the parallel max for:
iris_cols <- iris %>% select(Sepal.Length:Petal.Width) %>% names()
Then we can use !!! and rlang::syms to compute the parallel max for every row of those columns:
iris %>%
mutate(mak=pmax(!!!rlang::syms(iris_cols)))
rlang::syms takes a string input (the column names), and turns it into a symbol
!!! unquotes and splices its argument, here the column names
Which gives:
Sepal.Length Sepal.Width Petal.Length Petal.Width Species mak
1 5.1 3.5 1.4 0.2 setosa 5.1
2 4.9 3.0 1.4 0.2 setosa 4.9
3 4.7 3.2 1.3 0.2 setosa 4.7
4 4.6 3.1 1.5 0.2 setosa 4.6
5 5.0 3.6 1.4 0.2 setosa 5.0
h/t: https://stackoverflow.com/a/47773379/1036500
Currently (dplyr 1.0.2), this works:
newiris<-iris %>%
rowwise() %>%
mutate(mak=max(c_across(Sepal.Width:Petal.Length)))
this also lets you use selection helpers (starts_with etc).
For selecting some columns without typing whole names when using dplyr I prefer select parameter from subset function.
You can get desired result like this:
iris %>% subset(select = 2:4) %>% mutate(mak = do.call(pmax, (.))) %>%
select(mak) %>% cbind(iris)
One approach is to pipe the data into select then call pmax using a function that makes pmax rowwise (this is very similar to #inscaven's answer that uses do.call, unfortunately there isn't a rowMaxs function in R so we have to use a function to make pmax rowwise -- below I used purrr::pmap)
library(dplyr)
library(purrr)
# to get the value of the max
iris$rowwisemax <- iris %>% select(Sepal.Width:Petal.Length) %>% pmap(pmax) %>% as.numeric
# to get the argmax
iris$whichrowwisemax <- iris %>% select(Sepal.Width:Petal.Length) %>% {names(.)[max.col(.)]}
It seems like #akrun's answer only addresses the cases when you can type in the names of all the variables, whether that's using mutate directly with mutate(pmax_value=pmax(var1, var2)) or when using lazy evaluation with mutate_ and interp via mutate_(interp(~pmax(v1, v2), v1=as.name(var1), v2=as.name(var2)).
I can see two ways to do this if you want to use the colon syntax Sepal.Length:Petal.Width or if you happen to have a vector with the column names.
The first is more elegant. You tidy the data and take the maximum among the values when grouped:
data(iris)
library(dplyr)
library(tidyr)
iris_id = iris %>% mutate(id=1:nrow(.))
iris_id %>%
gather('attribute', 'value', Sepal.Length:Petal.Width) %>%
group_by(id) %>%
summarize(max_attribute=max(value)) %>%
right_join(iris_id, by='id') %>%
head(3)
## # A tibble: 3 × 7
## id max_attribute Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <int> <dbl> <dbl> <dbl> <dbl> <dbl> <fctr>
## 1 1 5.1 5.1 3.5 1.4 0.2 setosa
## 2 2 4.9 4.9 3.0 1.4 0.2 setosa
## 3 3 4.7 4.7 3.2 1.3 0.2 setosa
The harder way is to use an interpolated formula. This is good if you have a character vector with the names of the variables to be max'ed over or if you the table is too tall/wide for it to be tidied.
# Make a character vector of the names of the columns we want to take the
# maximum over
target_columns = iris %>% select(-Species) %>% names
## [1] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width"
# Make a vector of dummy variables that will take the place of the real
# column names inside the interpolated formula
dummy_vars = sapply(1:length(target_columns), function(i) sprintf('x%i', i))
## [1] "x1" "x2" "x3" "x4"
# Paste those variables together to make the argument of the pmax in the
# interpolated formula
dummy_vars_string = paste0(dummy_vars, collapse=',')
## [1] "x1,x2,x3,x4"
# Make a named list that maps the dummy variable names (e.g., x1) to the
# real variable names (e.g., Sepal.Length)
dummy_vars_list = lapply(target_columns, as.name) %>% setNames(dummy_vars)
## $x1
## Sepal.Length
##
## $x2
## Sepal.Width
##
## $x3
## Petal.Length
##
## $x4
## Petal.Width
# Make a pmax formula using the dummy variables
max_formula = as.formula(paste0(c('~pmax(', dummy_vars_string, ')'), collapse=''))
## ~pmax(x1, x2, x3, x4)
# Interpolate the formula using the named variables
library(lazyeval)
iris %>%
mutate_(max_attribute=interp(max_formula, .values=dummy_vars_list)) %>%
head(3)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species max_attribute
## 1 5.1 3.5 1.4 0.2 setosa 5.1
## 2 4.9 3.0 1.4 0.2 setosa 4.9
## 3 4.7 3.2 1.3 0.2 setosa 4.7
Here is a base-R solution: A range of column names can be selected with subset(). The rowwise maximum values can be added with a combination of transform() and apply().
newiris <- transform(iris, mak = apply(subset(iris, select=Sepal.Width:Petal.Length), 1, max))
If one wants to use selection helpers like contains(), starts_with() we may use
library(dplyr)
iris |>
mutate(max_value = purrr::pmap_dbl(select(iris, contains("petal")), pmax, na.rm=TRUE))

Difference between pull and select in dplyr?

It seems like dplyr::pull() and dplyr::select() do the same thing. Is there a difference besides that dplyr::pull() only selects 1 variable?
First, it makes sense to see what class each function creates.
library(dplyr)
mtcars %>% pull(cyl) %>% class()
#> 'numeric'
mtcars %>% select(cyl) %>% class()
#> 'data.frame'
So pull() creates a vector -- which, in this case, is numeric -- whereas select() creates a data frame.
Basically, pull() is the equivalent to writing mtcars$cyl or mtcars[, "cyl"], whereas select() removes all of the columns except for cyl but maintains the data frame structure
You could see select as an analogue of [ or magrittr::extract and pull as an analogue of [[ (or $) or magrittr::extract2 for data frames (an analogue of [[ for lists would be purr::pluck).
df <- iris %>% head
All of these give the same output:
df %>% pull(Sepal.Length)
df %>% pull("Sepal.Length")
a <- "Sepal.Length"; df %>% pull(!!quo(a))
df %>% extract2("Sepal.Length")
df %>% `[[`("Sepal.Length")
df[["Sepal.Length"]]
# all of them:
# [1] 5.1 4.9 4.7 4.6 5.0 5.4
And all of these give the same output:
df %>% select(Sepal.Length)
a <- "Sepal.Length"; df %>% select(!!quo(a))
df %>% select("Sepal.Length")
df %>% extract("Sepal.Length")
df %>% `[`("Sepal.Length")
df["Sepal.Length"]
# all of them:
# Sepal.Length
# 1 5.1
# 2 4.9
# 3 4.7
# 4 4.6
# 5 5.0
# 6 5.4
pull and select can take literal, character, or numeric indices, while the others take character or numeric only
One important thing is they differ on how they handle negative indices.
For select negative indices mean columns to drop.
For pull they mean count from last column.
df %>% pull(-Sepal.Length)
df %>% pull(-1)
# [1] setosa setosa setosa setosa setosa setosa
# Levels: setosa versicolor virginica
Strange result but Sepal.Length is converted to 1, and column -1 is Species (last column)
This feature is not supported by [[ and extract2 :
df %>% `[[`(-1)
df %>% extract2(-1)
df[[-1]]
# Error in .subset2(x, i, exact = exact) :
# attempt to select more than one element in get1index <real>
Negative indices to drop columns are supported by [ and extract though.
df %>% select(-Sepal.Length)
df %>% select(-1)
df %>% `[`(-1)
df[-1]
# Sepal.Width Petal.Length Petal.Width Species
# 1 3.5 1.4 0.2 setosa
# 2 3.0 1.4 0.2 setosa
# 3 3.2 1.3 0.2 setosa
# 4 3.1 1.5 0.2 setosa
# 5 3.6 1.4 0.2 setosa
# 6 3.9 1.7 0.4 setosa

dplyr rowwise mutate without hardcoding names

I want to do something like this
df <- iris %>%
rowwise %>%
mutate(new_var = sum(Sepal.Length, Sepal.Width))
Except I want to do it without typing the variable names, e.g.
names_to_add <- c("Sepal.Length", "Sepal.Width")
df <- iris %>%
rowwise %>%
[some function that uses names_to_add]
I attempted a few things e.g.
df <- iris %>%
rowwise %>%
mutate(new_var = sum(sapply(names_to_add, get, envir = as.environment(.))))
but still can't figure it out. I'll take an answer that plays around with lazyeval or something that's simpler. Note that the sum function here is just a placeholder and my actual function is much more complex, although it returns one value per row. I'd also rather not use data.table
You should check out all the functions that end with _ in dplyr. Example mutate_, summarise_ etc.
names_to_add <- ("sum(Sepal.Length, Sepal.Width)")
df <- iris %>%
rowwise %>% mutate_(names_to_add)
Edit
The results of the code:
df <- iris %>%
rowwise %>% mutate(new_var = sum(Sepal.Length, Sepal.Width))
names_to_add <- ("sum(Sepal.Length, Sepal.Width)")
df2 <- iris %>%
rowwise %>% mutate_(new_var = names_to_add)
identical(df, df2)
[1] TRUE
Edit
I edited the answer and it solves the problem. I wonder why it was donwvoted. We use SE (standard evaluation), passing a string as an input inside 'mutate_'. More info: vignette("nse","dplyr")
x <- "Sepal.Length + Sepal.Width"
df <- mutate_(iris, x)
head(df)
Output:
Sepal.Length Sepal.Width Petal.Length Petal.Width Species Sepal.Length + Sepal.Width
1 5.1 3.5 1.4 0.2 setosa 8.6
2 4.9 3.0 1.4 0.2 setosa 7.9
3 4.7 3.2 1.3 0.2 setosa 7.9
4 4.6 3.1 1.5 0.2 setosa 7.7
5 5.0 3.6 1.4 0.2 setosa 8.6
6 5.4 3.9 1.7 0.4 setosa 9.3

dplyr mutate rowwise max of range of columns

I can use the following to return the maximum of 2 columns
newiris<-iris %>%
rowwise() %>%
mutate(mak=max(Sepal.Width,Petal.Length))
What I want to do is find that maximum across a range of columns so I don't have to name each one like this
newiris<-iris %>%
rowwise() %>%
mutate(mak=max(Sepal.Width:Petal.Length))
Any ideas?
Instead of rowwise(), this can be done with pmax
iris %>%
mutate(mak=pmax(Sepal.Width,Petal.Length, Petal.Width))
May be we can use interp from library(lazyeval) if we want to reference the column names stored in a vector.
library(lazyeval)
nm1 <- names(iris)[2:4]
iris %>%
mutate_(mak= interp(~pmax(v1), v1= as.name(nm1)))
With rlang and quasiquotation we have another dplyr option. First, get the row names that we want to compute the parallel max for:
iris_cols <- iris %>% select(Sepal.Length:Petal.Width) %>% names()
Then we can use !!! and rlang::syms to compute the parallel max for every row of those columns:
iris %>%
mutate(mak=pmax(!!!rlang::syms(iris_cols)))
rlang::syms takes a string input (the column names), and turns it into a symbol
!!! unquotes and splices its argument, here the column names
Which gives:
Sepal.Length Sepal.Width Petal.Length Petal.Width Species mak
1 5.1 3.5 1.4 0.2 setosa 5.1
2 4.9 3.0 1.4 0.2 setosa 4.9
3 4.7 3.2 1.3 0.2 setosa 4.7
4 4.6 3.1 1.5 0.2 setosa 4.6
5 5.0 3.6 1.4 0.2 setosa 5.0
h/t: https://stackoverflow.com/a/47773379/1036500
Currently (dplyr 1.0.2), this works:
newiris<-iris %>%
rowwise() %>%
mutate(mak=max(c_across(Sepal.Width:Petal.Length)))
this also lets you use selection helpers (starts_with etc).
For selecting some columns without typing whole names when using dplyr I prefer select parameter from subset function.
You can get desired result like this:
iris %>% subset(select = 2:4) %>% mutate(mak = do.call(pmax, (.))) %>%
select(mak) %>% cbind(iris)
One approach is to pipe the data into select then call pmax using a function that makes pmax rowwise (this is very similar to #inscaven's answer that uses do.call, unfortunately there isn't a rowMaxs function in R so we have to use a function to make pmax rowwise -- below I used purrr::pmap)
library(dplyr)
library(purrr)
# to get the value of the max
iris$rowwisemax <- iris %>% select(Sepal.Width:Petal.Length) %>% pmap(pmax) %>% as.numeric
# to get the argmax
iris$whichrowwisemax <- iris %>% select(Sepal.Width:Petal.Length) %>% {names(.)[max.col(.)]}
It seems like #akrun's answer only addresses the cases when you can type in the names of all the variables, whether that's using mutate directly with mutate(pmax_value=pmax(var1, var2)) or when using lazy evaluation with mutate_ and interp via mutate_(interp(~pmax(v1, v2), v1=as.name(var1), v2=as.name(var2)).
I can see two ways to do this if you want to use the colon syntax Sepal.Length:Petal.Width or if you happen to have a vector with the column names.
The first is more elegant. You tidy the data and take the maximum among the values when grouped:
data(iris)
library(dplyr)
library(tidyr)
iris_id = iris %>% mutate(id=1:nrow(.))
iris_id %>%
gather('attribute', 'value', Sepal.Length:Petal.Width) %>%
group_by(id) %>%
summarize(max_attribute=max(value)) %>%
right_join(iris_id, by='id') %>%
head(3)
## # A tibble: 3 × 7
## id max_attribute Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## <int> <dbl> <dbl> <dbl> <dbl> <dbl> <fctr>
## 1 1 5.1 5.1 3.5 1.4 0.2 setosa
## 2 2 4.9 4.9 3.0 1.4 0.2 setosa
## 3 3 4.7 4.7 3.2 1.3 0.2 setosa
The harder way is to use an interpolated formula. This is good if you have a character vector with the names of the variables to be max'ed over or if you the table is too tall/wide for it to be tidied.
# Make a character vector of the names of the columns we want to take the
# maximum over
target_columns = iris %>% select(-Species) %>% names
## [1] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width"
# Make a vector of dummy variables that will take the place of the real
# column names inside the interpolated formula
dummy_vars = sapply(1:length(target_columns), function(i) sprintf('x%i', i))
## [1] "x1" "x2" "x3" "x4"
# Paste those variables together to make the argument of the pmax in the
# interpolated formula
dummy_vars_string = paste0(dummy_vars, collapse=',')
## [1] "x1,x2,x3,x4"
# Make a named list that maps the dummy variable names (e.g., x1) to the
# real variable names (e.g., Sepal.Length)
dummy_vars_list = lapply(target_columns, as.name) %>% setNames(dummy_vars)
## $x1
## Sepal.Length
##
## $x2
## Sepal.Width
##
## $x3
## Petal.Length
##
## $x4
## Petal.Width
# Make a pmax formula using the dummy variables
max_formula = as.formula(paste0(c('~pmax(', dummy_vars_string, ')'), collapse=''))
## ~pmax(x1, x2, x3, x4)
# Interpolate the formula using the named variables
library(lazyeval)
iris %>%
mutate_(max_attribute=interp(max_formula, .values=dummy_vars_list)) %>%
head(3)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species max_attribute
## 1 5.1 3.5 1.4 0.2 setosa 5.1
## 2 4.9 3.0 1.4 0.2 setosa 4.9
## 3 4.7 3.2 1.3 0.2 setosa 4.7
Here is a base-R solution: A range of column names can be selected with subset(). The rowwise maximum values can be added with a combination of transform() and apply().
newiris <- transform(iris, mak = apply(subset(iris, select=Sepal.Width:Petal.Length), 1, max))
If one wants to use selection helpers like contains(), starts_with() we may use
library(dplyr)
iris |>
mutate(max_value = purrr::pmap_dbl(select(iris, contains("petal")), pmax, na.rm=TRUE))

Resources