134 votes

Convertir les classes de colonnes dans data.table

J'ai un problème avec data.table : Comment convertir les classes de colonnes ? Voici un exemple simple : Avec data.frame je n'ai pas de problème de conversion, avec data.table je ne sais pas comment faire :

df <- data.frame(ID=c(rep("A", 5), rep("B",5)), Quarter=c(1:5, 1:5), value=rnorm(10))
#One way: http://stackoverflow.com/questions/2851015/r-convert-data-frame-columns-from-factors-to-characters
df <- data.frame(lapply(df, as.character), stringsAsFactors=FALSE)
#Another way
df[, "value"] <- as.numeric(df[, "value"])

library(data.table)
dt <- data.table(ID=c(rep("A", 5), rep("B",5)), Quarter=c(1:5, 1:5), value=rnorm(10))
dt <- data.table(lapply(dt, as.character), stringsAsFactors=FALSE) 
#Error in rep("", ncol(xi)) : invalid 'times' argument
#Produces error, does data.table not have the option stringsAsFactors?
dt[, "ID", with=FALSE] <- as.character(dt[, "ID", with=FALSE]) 
#Produces error: Error in `[<-.data.table`(`*tmp*`, , "ID", with = FALSE, value = "c(1, 1, 1, 1, 1, 2, 2, 2, 2, 2)") : 
#unused argument(s) (with = FALSE)

Ai-je raté quelque chose d'évident ?

Mise à jour suite au post de Matthew : J'utilisais une version plus ancienne, mais même après la mise à jour vers la version 1.6.6 (la version que j'utilise maintenant), j'obtiens toujours une erreur.

Mise à jour 2 : Supposons que je veuille convertir chaque colonne de la classe "facteur" en une colonne "caractère", mais que je ne sache pas à l'avance quelle colonne appartient à quelle classe. Avec un data.frame, je peux faire ce qui suit :

classes <- as.character(sapply(df, class))
colClasses <- which(classes=="factor")
df[, colClasses] <- sapply(df[, colClasses], as.character)

Puis-je faire quelque chose de similaire avec data.table ?

Mise à jour 3 :

s R version 2.13.1 (2011-07-08) Plateforme : x86_64-pc-mingw32/x64 (64-bit)

locale:
[1] C

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] data.table_1.6.6

loaded via a namespace (and not attached):
[1] tools_2.13.1

123voto

Andrie Points 66979

Pour une seule colonne :

dtnew <- dt[, Quarter:=as.character(Quarter)]
str(dtnew)

Classes ‘data.table’ and 'data.frame':  10 obs. of  3 variables:
 $ ID     : Factor w/ 2 levels "A","B": 1 1 1 1 1 2 2 2 2 2
 $ Quarter: chr  "1" "2" "3" "4" ...
 $ value  : num  -0.838 0.146 -1.059 -1.197 0.282 ...

Utilisation lapply y as.character :

dtnew <- dt[, lapply(.SD, as.character), by=ID]
str(dtnew)

Classes ‘data.table’ and 'data.frame':  10 obs. of  3 variables:
 $ ID     : Factor w/ 2 levels "A","B": 1 1 1 1 1 2 2 2 2 2
 $ Quarter: chr  "1" "2" "3" "4" ...
 $ value  : chr  "1.487145280568" "-0.827845218358881" "0.028977182770002" "1.35392750102305" ...

63voto

Nera Points 651

Essayez ceci

DT <- data.table(X1 = c("a", "b"), X2 = c(1,2), X3 = c("hello", "you"))
changeCols <- colnames(DT)[which(as.vector(DT[,lapply(.SD, class)]) == "character")]

DT[,(changeCols):= lapply(.SD, as.factor), .SDcols = changeCols]

12voto

JWilliman Points 1089

Relèvement du commentaire de Matt Dowle à la réponse de Geneorama ( https://stackoverflow.com/a/20808945/4241780 ) pour le rendre plus évident (comme encouragé), vous pouvez utiliser for(...)set(...) .

library(data.table)

DT = data.table(a = LETTERS[c(3L,1:3)], b = 4:7, c = letters[1:4])
DT1 <- copy(DT)
names_factors <- c("a", "c")

for(col in names_factors)
  set(DT, j = col, value = as.factor(DT[[col]]))

sapply(DT, class)
#>         a         b         c 
#>  "factor" "integer"  "factor"

Créé le 2020-02-12 par le paquet reprex (v0.3.0)

Voir un autre commentaire de Matt à l'adresse suivante https://stackoverflow.com/a/33000778/4241780 pour plus d'informations.

Editer.

Comme indiqué par Espen et dans help(set) , j peut être "Nom(s) de colonne (caractère) ou nombre(s) (entier) à affecter à une valeur lorsque la (les) colonne(s) existe(nt) déjà". En d'autres termes names_factors <- c(1L, 3L) fonctionnera également.

3voto

Emil Lykke Jensen Points 319

Si vous avez une liste de noms de colonnes dans data.table, vous voulez changer la classe de do :

convert_to_character <- c("Quarter", "value")

dt[, convert_to_character] <- dt[, lapply(.SD, as.character), .SDcols = convert_to_character]

2voto

geneorama Points 620

C'est une MAUVAISE façon de faire ! Je ne laisse cette réponse que pour le cas où elle permettrait de résoudre d'autres problèmes bizarres. Ces meilleures méthodes sont probablement en partie le résultat de nouvelles versions de data.table... cela vaut donc la peine de documenter cette méthode difficile. De plus, c'est un bon exemple de syntaxe pour eval substitute syntaxe.

library(data.table)
dt <- data.table(ID = c(rep("A", 5), rep("B",5)), 
                 fac1 = c(1:5, 1:5), 
                 fac2 = c(1:5, 1:5) * 2, 
                 val1 = rnorm(10),
                 val2 = rnorm(10))

names_factors = c('fac1', 'fac2')
names_values = c('val1', 'val2')

for (col in names_factors){
  e = substitute(X := as.factor(X), list(X = as.symbol(col)))
  dt[ , eval(e)]
}
for (col in names_values){
  e = substitute(X := as.numeric(X), list(X = as.symbol(col)))
  dt[ , eval(e)]
}

str(dt)

qui vous donne

Classes ‘data.table’ and 'data.frame':  10 obs. of  5 variables:
 $ ID  : chr  "A" "A" "A" "A" ...
 $ fac1: Factor w/ 5 levels "1","2","3","4",..: 1 2 3 4 5 1 2 3 4 5
 $ fac2: Factor w/ 5 levels "2","4","6","8",..: 1 2 3 4 5 1 2 3 4 5
 $ val1: num  0.0459 2.0113 0.5186 -0.8348 -0.2185 ...
 $ val2: num  -0.0688 0.6544 0.267 -0.1322 -0.4893 ...
 - attr(*, ".internal.selfref")=<externalptr>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X