web-dev-qa-db-fra.com

dplyr mute ligne par ligne max de la plage des colonnes

Je peux utiliser ce qui suit pour renvoyer le maximum de 2 colonnes

newiris<-iris %>%
 rowwise() %>%
 mutate(mak=max(Sepal.Width,Petal.Length))

Ce que je veux faire est de trouver ce maximum sur une plage de colonnes afin de ne pas avoir à les nommer comme ceci

newiris<-iris %>%
 rowwise() %>%
 mutate(mak=max(Sepal.Width:Petal.Length))

Des idées?

20
user2502836

Au lieu de rowwise(), ceci peut être fait avec pmax

iris %>%
      mutate(mak=pmax(Sepal.Width,Petal.Length, Petal.Width))

Peut-être pouvons-nous utiliser interp à partir de library(lazyeval) si nous voulons référencer les noms de colonne stockés dans une vector.

library(lazyeval)
nm1 <- names(iris)[2:4]
iris %>% 
     mutate_(mak= interp(~pmax(v1), v1= as.name(nm1)))
25
akrun

Avec rlang et la quasiquotation, nous avons une autre option dplyr. Commencez par obtenir les noms de lignes pour lesquels nous voulons calculer le nombre maximal de parallèles:

iris_cols <- iris %>% select(Sepal.Length:Petal.Width) %>% names()

Ensuite, nous pouvons utiliser !!! et rlang::syms pour calculer le maximum parallèle pour chaque ligne de ces colonnes:

iris %>%
  mutate(mak=pmax(!!!rlang::syms(iris_cols)))
  • rlang::syms prend une entrée de chaîne (les noms de colonne) et la transforme en symbole
  • !!! entre guillemets et raccorde son argument, ici les noms de colonnes

Qui donne:

    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

9
Ben

Pour sélectionner certaines colonnes sans taper des noms entiers lors de l'utilisation de dplyr, je préfère le paramètre select de la fonction subset.

Vous pouvez obtenir le résultat souhaité comme ceci:

iris %>% subset(select = 2:4) %>% mutate(mak = do.call(pmax, (.))) %>%
  select(mak) %>% cbind(iris)
3
inscaven

Il semble que la réponse de @ akrun ne concerne que les cas dans lesquels vous pouvez taper le nom de toutes les variables, que ce soit en utilisant mutate directement avec mutate(pmax_value=pmax(var1, var2)) ou en utilisant une évaluation différée avec mutate_ et interp via mutate_(interp(~pmax(v1, v2), v1=as.name(var1), v2=as.name(var2)).

Je peux voir deux façons de procéder si vous souhaitez utiliser la syntaxe du côlon Sepal.Length:Petal.Width ou si vous avez un vecteur avec les noms de colonne.

Le premier est plus élégant. Vous rangez les données et prenez le maximum parmi les valeurs regroupées:

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

La méthode la plus difficile consiste à utiliser une formule interpolée. C'est bien si vous avez un vecteur de caractère avec les noms des variables sur lesquelles vous souhaitez appliquer une valeur maximale ou si la table est trop grande/trop large pour pouvoir être rangée.

# 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
0
Scott Olesen