Scoped functions do dplyr

Este post faz parte da série de post que estamos criando sobre o dplyr. Caso ainda não conheça o pacote, veja o post de introdução ao dplyr.

O dplyr apresenta uma série de funções similares aos verbos, que podem ser usadas para fazer operações sobre uma série de colunas, baseando-se nas suas classes ou nos seus nomes. Os sufixos _if, _at e _all são utilizados com as funções do dplyr de forma a realizar uma mesma operação a várias colunas, simultaneamente.

  • _all: Realiza as operações para todas as colunas do tibble ou dataframe.

  • _at: Realiza operações sobre um conjunto de variáveis com nomes específicos ou índices das colunas.

  • _if: Realiza operações sobre um conjunto de colunas para os quais a condição lógica é verdadeira.

As funções que podem ser utilizadas com o sufixo são:

  • mutate e transmute.
  • summarise.
  • filter.
  • group_by.
  • select e rename.
  • arrange.

Agora vamos mostrar alguns exemplos de aplicações dessas funções.

Aprendendo por exemplo:

Iremos utilizar o famoso conjunto de dados iris.

require(dplyr)

as_tibble(x = iris)
# A tibble: 150 x 5
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          <dbl>       <dbl>        <dbl>       <dbl> <fct>  
 1          5.1         3.5          1.4         0.2 setosa 
 2          4.9         3            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           3.6          1.4         0.2 setosa 
 6          5.4         3.9          1.7         0.4 setosa 
 7          4.6         3.4          1.4         0.3 setosa 
 8          5           3.4          1.5         0.2 setosa 
 9          4.4         2.9          1.4         0.2 setosa 
10          4.9         3.1          1.5         0.1 setosa 
# ... with 140 more rows

Sufixo _all

Vamos agrupar por espécie e calcular a média de todas as colunas (note que os argumentos adicionais da função são colocados depois da função):

iris %>% 
  group_by(Species) %>% 
  summarise_all(.funs = mean, na.rm = T)
# A tibble: 3 x 5
  Species    Sepal.Length Sepal.Width Petal.Length Petal.Width
  <fct>             <dbl>       <dbl>        <dbl>       <dbl>
1 setosa             5.01        3.43         1.46       0.246
2 versicolor         5.94        2.77         4.26       1.33 
3 virginica          6.59        2.97         5.55       2.03 

Agora iremos transformar todas as colunas de maneira a estarem na escala \([0, 1]\). Como a coluna de espécies não é numérica, então vamos tranformá-la numa variável de grupo. Assim a função _all não se aplicará para ela. Note que poderemos criar uma função para fazer a tarefa desejada.

iris %>% 
  group_by(Species) %>% 
  mutate_all(.funs = function(x){ x / max(x) })
# A tibble: 150 x 5
# Groups:   Species [3]
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          <dbl>       <dbl>        <dbl>       <dbl> <fct>  
 1        0.879       0.795        0.737       0.333 setosa 
 2        0.845       0.682        0.737       0.333 setosa 
 3        0.810       0.727        0.684       0.333 setosa 
 4        0.793       0.705        0.789       0.333 setosa 
 5        0.862       0.818        0.737       0.333 setosa 
 6        0.931       0.886        0.895       0.667 setosa 
 7        0.793       0.773        0.737       0.5   setosa 
 8        0.862       0.773        0.789       0.333 setosa 
 9        0.759       0.659        0.737       0.333 setosa 
10        0.845       0.705        0.789       0.167 setosa 
# ... with 140 more rows

Para o summarise_all e mutate_all, a função só será aplicada para as colunas que não sejam de grupos. Já o filter_all, faz o filtro para todas as variáveis. Sendo assim, iremos descartar a variável Species antes de fazer o filtro.

Vamos filtrar para que todas as variáveis sejam maiores que \(1,5\):

iris %>% 
  select(-Species) %>% 
  filter_all(.vars_predicate = all_vars(. > 1.5))
# A tibble: 52 x 4
   Sepal.Length Sepal.Width Petal.Length Petal.Width
          <dbl>       <dbl>        <dbl>       <dbl>
 1          6.3         3.3          4.7         1.6
 2          5.9         3.2          4.8         1.8
 3          6.7         3            5           1.7
 4          6           2.7          5.1         1.6
 5          6           3.4          4.5         1.6
 6          6.3         3.3          6           2.5
 7          5.8         2.7          5.1         1.9
 8          7.1         3            5.9         2.1
 9          6.3         2.9          5.6         1.8
10          6.5         3            5.8         2.2
# ... with 42 more rows

Agora filtraremos para que pelo menos uma das variáveis sejam maiores que \(7,5\):

iris %>% 
  select(-Species) %>% 
  filter_all(.vars_predicate = any_vars(. > 7.5))
# A tibble: 6 x 4
  Sepal.Length Sepal.Width Petal.Length Petal.Width
         <dbl>       <dbl>        <dbl>       <dbl>
1          7.6         3            6.6         2.1
2          7.7         3.8          6.7         2.2
3          7.7         2.6          6.9         2.3
4          7.7         2.8          6.7         2  
5          7.9         3.8          6.4         2  
6          7.7         3            6.1         2.3

Podemos, de duas maneiras, modificar os nomes de todas as colunas:

iris %>% 
  select_all(.funs = toupper) # ou rename_all(toupper)
# A tibble: 150 x 5
   SEPAL.LENGTH SEPAL.WIDTH PETAL.LENGTH PETAL.WIDTH SPECIES
          <dbl>       <dbl>        <dbl>       <dbl> <fct>  
 1          5.1         3.5          1.4         0.2 setosa 
 2          4.9         3            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           3.6          1.4         0.2 setosa 
 6          5.4         3.9          1.7         0.4 setosa 
 7          4.6         3.4          1.4         0.3 setosa 
 8          5           3.4          1.5         0.2 setosa 
 9          4.4         2.9          1.4         0.2 setosa 
10          4.9         3.1          1.5         0.1 setosa 
# ... with 140 more rows

O group_by_all torna todas as colunas do tibble em colunas de grupos. Já o arrange_all irá ordenar os dados de acordo com os valores de todas as colunas, em ordem crescente. Caso desejemos a ordenação descrescente, basta adicionar desc no segundo argumento.

Sufixo _at

Utilizando o sufixo _at, podemos selecionar as colunas para as quais as funções serão aplicadas, da mesma maneira como podemos escrever no select. Basta utilizar a função vars. Desta maneira, podemos calcular a média de todas as variáveis, exceto Species.

iris %>% 
  summarise_at(.vars = vars(-Species), .funs = mean)
# A tibble: 1 x 4
  Sepal.Length Sepal.Width Petal.Length Petal.Width
         <dbl>       <dbl>        <dbl>       <dbl>
1         5.84        3.06         3.76        1.20

Também podemos utilizar as help functions. Neste caso multiplicaremos por \(100\) as colunas que terminam com “Length”:

iris %>% 
  mutate_at(.vars = vars(ends_with("Length")), .funs =  funs(. * 100))
# A tibble: 150 x 5
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          <dbl>       <dbl>        <dbl>       <dbl> <fct>  
 1         510.         3.5          140         0.2 setosa 
 2         490.         3            140         0.2 setosa 
 3         470          3.2          130         0.2 setosa 
 4         460.         3.1          150         0.2 setosa 
 5         500          3.6          140         0.2 setosa 
 6         540          3.9          170         0.4 setosa 
 7         460.         3.4          140         0.3 setosa 
 8         500          3.4          150         0.2 setosa 
 9         440.         2.9          140         0.2 setosa 
10         490.         3.1          150         0.1 setosa 
# ... with 140 more rows

Note que ao invés de criar uma função que recebe x e retorna x * 100, nós utilizamos a função funs. O ponto funciona como cada uma das colunas, que, neste caso, é multiplicada por \(100\).

O mesmo raciocínio se aplica às outras funções: filter, arrange e group_by. Não foi encontrado uso de select_at e rename_at.

Sufixo _if

O sufixo _if permite que nós apliquemos as funções para colunas que tenham algum predicado.

Vamos calcular o máximo de todas as variáveis que são numéricas:

iris %>% 
  summarise_if(.predicate = is.numeric, .funs = max)
# A tibble: 1 x 4
  Sepal.Length Sepal.Width Petal.Length Petal.Width
         <dbl>       <dbl>        <dbl>       <dbl>
1          7.9         4.4          6.9         2.5

Da mesma maneira acontece com todas as outras funções.

Select vs Rename

As funções select_ e rename_, com algum dos sufixos, se diferenciam pelo fato de que com o select não é necessário passar uma função que mude os nomes, já com o rename é necessário incluir uma função que modifique os nomes das colunas.