J'ai beaucoup utilisé le tidyverse, mais pour certains projets, j'ai besoin de la vitesse de data.table. Jusqu'à présent, je comprends la plupart de la syntaxe DT, mais je souhaite supprimer les niveaux inutilisés dans data.table sans utiliser mutate_if
.
Avec dplyr
je peux utiliser mutate_if (dataframe, is.factor, droplevels)
et c'est tout. Cependant, je ne trouve pas de solution avec data.table.
J'ai essayé d'appliquer cette réponse en utilisant dataframe [ (.SD): = droplevels (.SD), .SDcols = sapply (dataframe, is. factor)]
Il renvoie l'erreur suivante: Erreur dans
[.data.table (DT_,
: = ((.SD), droplevels (.SD)), .SDcols = sapply (DT_,:
LHS de: = n'est pas des noms de colonnes ('caractère') ou des positions ('entier' ou 'numérique')
.
Je m'attends à avoir le même résultat que dans mutate_if
sans utiliser le tidyverse.
UPDATE
J'ai accepté G. Réponse de Grothendieck parce que le code était plus comme je m'y attendais.
L'exemple qu'il a utilisé était celui-ci:
> DT1[, C] [1] Q E A J D R Z O G V Levels: A D E G J O Q R V Z > DT1[, D] [1] Y E N T R O C I D Z Levels: C D E I N O R T Y Z
Les données que j'ai utilisées pour cet exemple étaient les suivantes:
# with base DT1 = droplevels(DT1) # or by reference DT1[, (names(DT1)) := droplevels(.SD)]
5 Réponses :
Pour ajouter à mon commentaire,
vous pouvez donner Vérifiez bien la vignette entière,
certains verbes sont impatients et certains sont paresseux. table.express
a > un essai,
bien que les exemples doivent être mis à jour car ils peuvent être simplifiés.
Voici un exemple équivalent à mutate_if
:library(data.table)
library(table.express)
data("iris")
DT <- as.data.table(iris)
DT %>%
start_expr %>%
mutate(Species = as.factor(Species)) %>%
mutate_sd(is.factor(.COL), droplevels) %>%
end_expr
Et ça?
x <- data.table( x=sample(letters[1:5],10,rep=T), y=factor(sample(letters[1:5],10,rep=T), levels=letters), w=factor(sample(letters[1:5],10,rep=T), levels=letters) ) factors <- colnames(x)[sapply(x, is.factor)] lapply(factors, function(z) x[, eval(z):=droplevels(get(z))])
Ce n'est pas une solution data.table
, mais cela peut être fait sans problème avec le rapply
de la base R :
## data data("iris") ## add dummy level levels(iris$Species) <- c(levels(iris$Species), "dummy") str(iris) #> 'data.frame': 150 obs. of 5 variables: #> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ... #> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ... #> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ... #> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ... #> $ Species : Factor w/ 4 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ... iris2 <- rapply(iris, f = droplevels, classes = "factor", how = "replace") str(iris2) #> 'data.frame': 150 obs. of 5 variables: #> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ... #> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ... #> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ... #> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ... #> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
Une autre option utilisant set()
Données d'entrée
DT[, levels(Species)] #[1] "setosa"
Obtenir les noms de colonne qui sont des facteurs et les remplacer par référence p >
cols <- DT[, names(Filter(is.factor, .SD))] for(j in cols) { set(DT, j = j, value = droplevels(DT[[j]])) } # could also be written as a one-liner - thanks to @MattSummersgill # for(j in cols) set(DT, j = j, value = droplevels(DT[[j]]))
Donner
library(data.table) DT <- as.data.table(iris) DT[, Species := as.factor(Species)] DT <- DT[Species == "setosa"] DT[, levels(Species)] #[1] "setosa" "versicolor" "virginica"
J'utilise également data.table :: set ()
de cette façon. Pour ce que ça vaut, je préfère faire la boucle sur une seule ligne si elle est inférieure à ~ 80 caractères. c'est-à-dire pour (j en cols) set (DT, j = j, value = droplevels (DT [[j]]))
En utilisant les données de la note à la fin
library(data.table) DT <- data.table(a = 1:5, b = factor(1:5, levels = 1:10), c = factor(6:10, levels = 1:10))
ou
wx <- which(sapply(DT, is.factor)) DT[, (wx) := lapply(.SD, droplevels), .SDcols = wx]
Vérifiez:
levels(DT$b) ## [1] "1" "2" "3" "4" "5" levels(DT$c) ## [1] "6" "7" "8" "9" "10"
Jetez un œil au tableau
.express
, il existe un équivalent demutate_if
(montré dans les exemples ici).Pourriez-vous montrer un exemple de vos données ainsi que votre résultat attendu?
BTW, c'est probablement un doublon de ceci , mais celui-ci n'est pas accepté comme réponse.