我可以使用以下代码返回2列中的最大值:
newiris<-iris %>%
rowwise() %>%
mutate(mak=max(Sepal.Width,Petal.Length))
我想要做的是在一系列列中找到最大值,这样我就不必像这样为每个列命名。newiris<-iris %>%
rowwise() %>%
mutate(mak=max(Sepal.Width:Petal.Length))
有什么想法吗?
使用pmax
函数即可替代rowwise()
。
iris %>%
mutate(mak=pmax(Sepal.Width,Petal.Length, Petal.Width))
如果我们想引用存储在vector
中的列名,可以使用来自library(lazyeval)
的interp
。
library(lazyeval)
nm1 <- names(iris)[2:4]
iris %>%
mutate_(mak= interp(~pmax(v1), v1= as.name(nm1)))
使用rlang
和quasiquotation,我们有另一种dplyr选项。首先,获取要计算并行最大值的行名称:
iris_cols <- iris %>% select(Sepal.Length:Petal.Width) %>% names()
然后我们可以使用!!!
和rlang::syms
来计算这些列的每一行的并行最大值:
iris %>%
mutate(mak=pmax(!!!rlang::syms(iris_cols)))
rlang::syms
将字符串输入(列名称)转换为符号!!!
取消引用并展开其参数,这里是列名称结果为:
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
目前(dplyr 1.0.2),这样做是可以的:
newiris<-iris %>%
rowwise() %>%
mutate(mak=max(c_across(Sepal.Width:Petal.Length)))
这样还可以使用选择器助手(如 starts_with 等)。
max()
替换为 which.max()
。 - Jeffrey Girard在使用dplyr
时,如果想要选择某些列而不用输入整个列名,我更喜欢使用subset
函数中的select
参数。
你可以像这样获得所需结果:
iris %>% subset(select = 2:4) %>% mutate(mak = do.call(pmax, (.))) %>%
select(mak) %>% cbind(iris)
select(2:4)
而不是 subset(select = 2:4)
。 - Artem Sokolov一种方法是将数据导入 select 然后使用一个使 pmax
在行上工作的函数调用 pmax
(这与 @inscaven 的答案非常相似,它使用了 do.call
,不幸的是 R 中没有 rowMaxs
函数,因此我们必须使用一个函数使 pmax
在行上工作 -- 下面我使用了 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(.)]}
{names(.)[max.col(.)]}
正是我所需要的。不过,这种语法是什么呢?你能给我指一下{}-语法的文档吗?我从未见过。 - Paul Schmidtmutate(pmax_value=pmax(var1, var2))
还是使用惰性求值与mutate_
和interp
通过mutate_(interp(~pmax(v1, v2), v1=as.name(var1), v2=as.name(var2))
。Sepal.Length:Petal.Width
或者碰巧有一个包含列名的向量,我可以看到两种方法来实现这一点。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
更加困难的方法是使用插值公式。如果您有一个包含要对其进行最大化处理的变量名称的字符向量,或者表格太高/宽而无法整理,则此方法非常有效。
# 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
contains()
,starts_with()
这样的选择器助手,我们可以使用library(dplyr)
iris |>
mutate(max_value = purrr::pmap_dbl(select(iris, contains("petal")), pmax, na.rm=TRUE))
dplyr现在包括 c_across 函数,该函数与 rowwise()一起使用,以启用选择助手的使用,例如 starts_with , ends_with , all_of 和 where(is.numeric)。这使得在复杂的数据管道中实现几种广泛方法更加简洁。
使用预选的字符向量包含列名:
useCols <- c("Sepal.Width", "Petal.Length")
newiris<-iris %>%
rowwise() %>%
mutate(mak = max(c_across(all_of(useCols))))
或者使用列名编程方式选择列,结合 starts_with
、ends_with
、contains
、matches
和 num_range
:
newiris<-iris %>%
rowwise() %>%
mutate(mak = max(c_across(starts_with("Sepal"))))
或者根据内容选择列,与 where
结合使用:
newiris<-iris %>%
rowwise() %>%
mutate(mak = max(c_across(where(~is.numeric(.x) && mean(.x) < 5))))
subset()
选择一系列列名。通过transform()
和apply()
的组合,可以添加每行的最大值。newiris <- transform(iris, mak = apply(subset(iris, select=Sepal.Width:Petal.Length), 1, max))
dplyr 1.0.1
,你的第二个例子可以完美运行。 - avidalvi