2
votes

select () transformées / nouvelles variables dans un mutate ()

Considérez un df comme celui-ci:

df <- data.frame(colA = 1:10,
colB = 50:59,
colC = 100:109,
colD = letters[1:10])

Je veux transformer la variable "colA" puis calculer une somme en ligne de variables que je choisis par select () code > à l'intérieur de mutate () . Je fais ceci:

df %>%
 mutate(colA = colA * 60) %>%
 mutate(sum = rowSums(select(., colA, colB, colC)))

   colA colB colC colD sum
1    60   50  100    a 210
2   120   51  101    b 272
3   180   52  102    c 334
4   240   53  103    d 396
5   300   54  104    e 458
6   360   55  105    f 520
7   420   56  106    g 582
8   480   57  107    h 644
9   540   58  108    i 706
10  600   59  109    j 768

qui me donne un résultat incorrect:

df %>%
 mutate(colA_mod = colA * 60,
        sum = rowSums(select(., colA_mod, colB, colC)))

Si je crée une toute nouvelle variable :

   colA colB colC colD sum
1    60   50  100    a 151
2   120   51  101    b 154
3   180   52  102    c 157
4   240   53  103    d 160
5   300   54  104    e 163
6   360   55  105    f 166
7   420   56  106    g 169
8   480   57  107    h 172
9   540   58  108    i 175
10  600   59  109    j 178

J'obtiens:

Erreur: erreur d'évaluation: la position doit être comprise entre 0 et n.

Cependant, lorsque j'utilise deux mutate () s séparés, j'obtiens les bons résultats:

df %>%
 mutate(colA = colA * 60,
        sum = rowSums(select(., colA, colB, colC)))

Donc la question est, comment puis-je transformer une variable / créer une nouvelle variable et la sélectionner dans un mutate () ?

Exemple de données :

   colA colB colC colD
1     1   50  100    a
2     2   51  101    b
3     3   52  102    c
4     4   53  103    d
5     5   54  104    e
6     6   55  105    f
7     7   56  106    g
8     8   57  107    h
9     9   58  108    i
10   10   59  109    j


0 commentaires

3 Réponses :


1
votes

Une option consiste à ajouter colA séparément

rowSums(select(., colA_mod, colB, colC))

Lorsque vous utilisez select (., colA, colB, colC) , . est la trame de données d'origine et les colonnes sélectionnées proviennent également de la trame de données d'origine. Par conséquent, il ne dispose pas d'informations sur les valeurs mises à jour de colA . C'est la même raison pour laquelle vous obtenez l'erreur lors de votre deuxième tentative

library(dplyr)

df %>%
  mutate(colA = colA * 60,
         sum = rowSums(select(., colB, colC)) + colA)


#   colA colB colC colD sum
#1    60   50  100    a 210
#2   120   51  101    b 272
#3   180   52  102    c 334
#4   240   53  103    d 396
#5   300   54  104    e 458
#6   360   55  105    f 520
#7   420   56  106    g 582
#8   480   57  107    h 644
#9   540   58  108    i 706
#10  600   59  109    j 768

car la colonne colA_mod ne fait pas partie du dataframe d'origine ( df ).


1 commentaires

Possibilité très élégante! Cependant, je suis toujours curieux de savoir s'il existe un moyen de mettre à jour le df original référencé par . dans select () .



1
votes

Le fait de changer rowSums et select fera le travail:

   colA colB colC colD sum
1     1   50  100    a 210
2     2   NA  101    b 221
3     3   52  102    c 334
4     4   53  103    d 396
5     5   54  104    e 458
6     6   55  105    f 520
7     7   56  106    g 582
8     8   57  107    h 644
9     9   58  108    i 706
10   10   59  109    j 768

Si vous avez des NA, mettez-les d'abord à zéro. se comporte comme et na.rm:

df %>% 
  mutate(sum = rowSums(select(., colA:colC) * 
    matrix(rep(c(60,1,1), times = 10), byrow = T, ncol = 3), na.rm = T))

Sinon, voici une solution qui autorise rowSums et une mutation:

df %>% 
  replace(is.na(.), 0) %>%
  mutate(colA = colA * 60,
         sum = colA + colB + colC)


2 commentaires

Cela pourrait être une possibilité, cependant, dans mes données réelles, j'ai aussi des NA. Il est beaucoup plus pratique d'ajouter na.rm = TRUE dans rowSums () .


@tmfmnk a trouvé une solution qui permet aux rowSums



1
votes

Le . est un espace réservé pour ce qui a été envoyé dans le tube. Dans ce cas, votre mutation de colA ne met pas à jour ce qui est dans le pipeline dans l'appel mutate .

Vous pouvez ajouter un autre tube:

df %>%
  mutate(colA = colA * 60)%>%
  mutate(sum = rowSums(select(., colA, colB, colC)))


2 commentaires

Merci, cependant, j'ai également inclus cette possibilité dans ma question :) De plus, je veux vraiment le faire en un seul mutate () .


Oops. En gros, cependant, vous ne pouvez pas faire ce que vous voulez. Le . ne sera pas mis à jour avant le prochain tube avant %>% .