web-dev-qa-db-fra.com

Arrondir les colonnes sélectionnées de data.table dans R

J'ai les données et le code suivants pour arrondir les colonnes sélectionnées de ce data.table:

> dput(mydf)
structure(list(vnum1 = c(0.590165705411504, -1.39939534199836, 
0.720226053660755, -0.253198380120377, -0.783366825121657), vnum2 = c(0.706508400384337, 
0.526770398486406, 0.863136084517464, 0.838245498016477, 0.556775856064633
), vch1 = structure(c(2L, 4L, 1L, 3L, 3L), .Label = c("A", "B", 
"C", "E"), class = "factor")), .Names = c("vnum1", "vnum2", "vch1"
), row.names = c(NA, -5L), class = c("data.table", "data.frame"
))

> mydf[,round(.SD,1),]
Error in Math.data.frame(list(vnum1 = c(0.590165705411504, -1.39939534199836,  : 
  non-numeric variable in data frame: vch1

> cbind(mydf[,3,with=F], mydf[,1:2,with=F][,round(.SD,1),])
   vch1 vnum1 vnum2
1:    B   0.6   0.7
2:    E  -1.4   0.5
3:    A   0.7   0.9
4:    C  -0.3   0.8
5:    C  -0.8   0.6

Existe-t-il une meilleure méthode (code plus court)? Merci de votre aide.

27
rnso

Si cela ne vous dérange pas de remplacer votre mydf originale:

cols <- names(mydf)[1:2]
mydf[,(cols) := round(.SD,1), .SDcols=cols]
mydf

#   vnum1 vnum2 vch1
#1:   0.6   0.7    B
#2:  -1.4   0.5    E
#3:   0.7   0.9    A
#4:  -0.3   0.8    C
#5:  -0.8   0.6    C
23
thelatemail

Utiliser dplyr

Si vous souhaitez arrondir plusieurs colonnes à la fois:

mydf %>% mutate_at(vars(vnum1, vnum2), funs(round(., 1)))

Ou, si vous souhaitez modifier toutes les colonnes sauf "vch1":

mydf %>% mutate_at(vars(-vch1), funs(round(., 1)))

Ou, si vous souhaitez modifier toutes les colonnes commençant par "vnum":

mydf %>% mutate_at(vars(starts_with("vnum")), funs(round(., 1)))

Ou, si vous souhaitez modifier uniquement les colonnes numériques:

mydf %>% mutate_if(is.numeric, ~round(., 1))

Vous recevez:

  vnum1 vnum2 vch1
1   0.6   0.7    B
2  -1.4   0.5    E
3   0.7   0.9    A
4  -0.3   0.8    C
5  -0.8   0.6    C
41
Steven Beaupré

require (data.table)

Solution courte et claire:

mydf[, lapply(.SD, round, 1), vch1]

#   vch1 vnum1 vnum2
#1:    B   0.6   0.7
#2:    E  -1.4   0.5
#3:    A   0.7   0.9
#4:    C  -0.3   0.8
#5:    C  -0.8   0.6

Idem, mais avec des détails descriptifs:

mydf[, lapply(.SD, round, digits = 1), by = vch1]

Si j'ai plusieurs colonnes, dites: (vnum1, vnum2, vch1, vch2, vbin1, vbin2, vbin3) et je veux arrondir uniquement vnum1 et vnum2?

Dans ce cas, vous pouvez utiliser l'opérateur := et l'argument .SDcols = pour spécifier les colonnes à arrondir:

mydf[, 1:2 := lapply(.SD, round, digits = 1), by = vch1]

Si vous devez arrondir certaines colonnes et en exclure d’autres de la sortie, vous pouvez utiliser uniquement l’argument .SDcols = pour les exécuter simultanément:

mydf[, lapply(.SD, round, digits = 1), by = vch1, .SDcols = "vnum1"]

.SDcols = peut être fourni avec le nom de la colonne ou son numéro,
en une seule colonne par nom .SDcols = "vnum1" ou par numéro .SDcols = 1
en multi colonnes par noms .SDcols = c("vnum2", "vnum1") ou par nombres .SDcols = c(2, 1)
sous forme de colonnes par noms .SDcols = vnum1:vnum2 ou par nombres.SDcols = 1:2

6
Georgie Shimanovsky

Le plus court de loin:

mydf[, vch1, round(mydf[, 1:2], 1)]

#   vnum1 vnum2 vch1
#1:   0.6   0.7    B
#2:  -1.4   0.5    E
#3:   0.7   0.9    A
#4:  -0.3   0.8    C
#5:  -0.8   0.6    C

Méthode intéressante. Mais si j'ai plusieurs colonnes, dites: (vnum1, vnum2, vch1, vch2, vbin1, vbin2, vbin3) et si je veux arrondir uniquement vnum1 et vnum2? De plus, quelques explications sur son fonctionnement seront très utiles

Il regroupe des colonnes arrondies en utilisant "by =" de data.table.

Voici l'exemple basé sur cette méthode pour résoudre votre tâche de second niveau.

Jeu de données intégré:

>dt <- data.table(names = rownames(datasets::ability.cov$cov), datasets::ability.cov$cov)
>dt
#     names general picture  blocks   maze reading   vocab
#1: general  24.641   5.991  33.520  6.023  20.755  29.701
#2: picture   5.991   6.700  18.137  1.782   4.936   7.204
#3:  blocks  33.520  18.137 149.831 19.424  31.430  50.753
#4:    maze   6.023   1.782  19.424 12.711   4.757   9.075
#5: reading  20.755   4.936  31.430  4.757  52.604  66.762
#6:   vocab  29.701   7.204  50.753  9.075  66.762 135.292

Solution courte:

> dt_round <- dt[, .SD, by = round(dt[, blocks:maze], 1)]
> dt_round
#   blocks maze   names general picture reading   vocab
#1:   33.5  6.0 general  24.641   5.991  20.755  29.701
#2:   18.1  1.8 picture   5.991   6.700   4.936   7.204
#3:  149.8 19.4  blocks  33.520  18.137  31.430  50.753
#4:   19.4 12.7    maze   6.023   1.782   4.757   9.075
#5:   31.4  4.8 reading  20.755   4.936  52.604  66.762
#6:   50.8  9.1   vocab  29.701   7.204  66.762 135.292

Ordre initial des colonnes:

> whatever <- setcolorder(dt_round, names(dt))
> whatever
#     names general picture blocks maze reading   vocab
#1: general  24.641   5.991   33.5  6.0  20.755  29.701
#2: picture   5.991   6.700   18.1  1.8   4.936   7.204
#3:  blocks  33.520  18.137  149.8 19.4  31.430  50.753
#4:    maze   6.023   1.782   19.4 12.7   4.757   9.075
#5: reading  20.755   4.936   31.4  4.8  52.604  66.762
#6:   vocab  29.701   7.204   50.8  9.1  66.762 135.292
1
Georgie Shimanovsky

Je pense que parmi les solutions proposées, celle de Steven Baupre utilisant dplyr est la plus élégante et la plus applicable de manière sélective dans différentes colonnes d’un cadre de données, en particulier en physique informatique. 

library(dplyr)
gasCriticals %>%
  mutate_each(funs(round(., 0)), depth, pres, temp) %>%
  mutate_each(funs(round(., 2)), pres.pr, temp.pr, temp.r) %>%
  mutate_each(funs(round(., 1)), pres.pc, temp.pc)

Comme vous pouvez le constater, la pression et la température seront arrondies à 0 décimale; pression pseudo-réduite et température jusqu'à 2 déc; et enfin, pression pseudo-critique et température à 1 décimale. 

0
f0nzie