Converter classs de coluna em data.table

Eu tenho um problema ao usar o data.table: Como converter classs de coluna? Aqui está um exemplo simples: Com data.frame não tenho problema em convertê-lo, com data.table eu não sei como:

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) 

Eu sinto falta de algo óbvio aqui?

Atualização devido ao post do Matthew: Eu usei uma versão mais antiga antes, mas mesmo depois de atualizar para o 1.6.6 (a versão que eu uso agora) eu ainda recebo um erro.

Atualização 2: digamos que eu queira converter cada coluna de “fator” de class em uma coluna “caractere”, mas não sei de antemão qual coluna é de qual class. Com um data.frame, posso fazer o seguinte:

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

Posso fazer algo semelhante com o data.table?

Atualização 3:

sessionInfo () R versão 2.13.1 (2011-07-08) Plataforma: x86_64-pc-mingw32 / x64 (64 bits)

 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 

Para uma única coluna:

 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 ... 

Usando lapply e 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" ... 

Tente isso

 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] 

Esta é uma maneira ruim de fazer isso! Só estou deixando esta resposta no caso de resolver outros problemas estranhos. Esses methods melhores são provavelmente o resultado de versões mais novas de dados … então vale a pena documentar desta maneira difícil. Além disso, este é um bom exemplo de syntax para a syntax do substitute eval .

 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) 

o que te dá

 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")= 

Eu tentei várias abordagens.

 # BY {dplyr} data.table(ID = c(rep("A", 5), rep("B",5)), Quarter = c(1:5, 1:5), value = rnorm(10)) -> df1 df1 %<>% dplyr::mutate(ID = as.factor(ID), Quarter = as.character(Quarter)) # check classes dplyr::glimpse(df1) # Observations: 10 # Variables: 3 # $ ID (fctr) A, A, A, A, A, B, B, B, B, B # $ Quarter (chr) "1", "2", "3", "4", "5", "1", "2", "3", "4", "5" # $ value (dbl) -0.07676732, 0.25376110, 2.47192852, 0.84929175, -0.13567312, -0.94224435, 0.80213218, -0.89652819... 

, ou então

 # from list to data.table using data.table::setDT list(ID = as.factor(c(rep("A", 5), rep("B",5))), Quarter = as.character(c(1:5, 1:5)), value = rnorm(10)) %>% setDT(list.df) -> df2 class(df2) # [1] "data.table" "data.frame" 

Eu forneço uma maneira mais geral e segura de fazer isso,

 ".." <- function (x) { stopifnot(inherits(x, "character")) stopifnot(length(x) == 1) get(x, parent.frame(4)) } set_colclass <- function(x, class){ stopifnot(all(class %in% c("integer", "numeric", "double","factor","character"))) for(i in intersect(names(class), names(x))){ f <- get(paste0("as.", class[i])) x[, (..("i")):=..("f")(get(..("i")))] } invisible(x) } 

A function .. garante que obtemos uma variável fora do escopo de data.table; set_colclass irá definir as classs dos seus cols. Você pode usá-lo assim:

 dt <- data.table(i=1:3,f=3:1) set_colclass(dt, c(i="character")) class(dt$i) 

Se você tem uma lista de nomes de coluna em data.table, você quer mudar a class de fazer:

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

experimentar:

 dt <- data.table(A = c(1:5), B= c(11:15)) x <- ncol(dt) for(i in 1:x) { dt[[i]] <- as.character(dt[[i]]) }