¿Por qué un factor como as.factor devuelve un carácter cuando se usa dentro?

Quiero convertir variables en factores usando apply() :

 a <- data.frame(x1 = rnorm(100), x2 = sample(c("a","b"), 100, replace = T), x3 = factor(c(rep("a",50) , rep("b",50)))) a2 <- apply(a, 2,as.factor) apply(a2, 2,class) 

resultados en:

  x1 x2 x3 "character" "character" "character" 

No entiendo por qué esto da como resultado vectores de caracteres en lugar de vectores de factores.

apply convierte tu data.frame en una matriz de caracteres. Use lapply :

 lapply(a, class) # $x1 # [1] "numeric" # $x2 # [1] "factor" # $x3 # [1] "factor" 

En el segundo comando, aplique el resultado de lapply matriz de caracteres, utilizando lapply :

 a2 <- lapply(a, as.factor) lapply(a2, class) # $x1 # [1] "factor" # $x2 # [1] "factor" # $x3 # [1] "factor" 

Pero para un simple puesto de observación, podrías usar str :

 str(a) # 'data.frame': 100 obs. of 3 variables: # $ x1: num -1.79 -1.091 1.307 1.142 -0.972 ... # $ x2: Factor w/ 2 levels "a","b": 2 1 1 1 2 1 1 1 1 2 ... # $ x3: Factor w/ 2 levels "a","b": 1 1 1 1 1 1 1 1 1 1 ... 

Explicación adicional según los comentarios:

¿Por qué funciona lapply mientras que apply no funciona?

Lo primero que se apply es convertir un argumento en una matriz. Entonces apply(a) es equivalente a apply(as.matrix(a)) . Como puede ver str(as.matrix(a)) le da:

 chr [1:100, 1:3] " 0.075124364" "-1.608618269" "-1.487629526" ... - attr(*, "dimnames")=List of 2 ..$ : NULL ..$ : chr [1:3] "x1" "x2" "x3" 

No hay más factores, por lo que la class devuelve "character" para todas las columnas.
lapply funciona en columnas, por lo que le proporciona lo que desea (hace algo así como class(a$column_name) para cada columna).

Puedes ver en ayuda para apply por qué apply y as.factor no funciona:

En todos los casos, el resultado es forzado por as.vector a uno de los tipos de vectores básicos antes de que se establezcan las dimensiones, de modo que (por ejemplo) los resultados del factor se forzarán a una matriz de caracteres.

Por qué sapply and as.factor no funciona se puede ver en help to sapply :

Valor (...) Un vector o matriz atómica o lista de la misma longitud que X (...) Si se produce la simplificación, el tipo de salida se determina a partir del tipo más alto de los valores de retorno en la jerarquía NULL

Nunca se obtiene una matriz de factores o data.frame.

¿Cómo convertir la salida a data.frame ?

Simple, use as.data.frame como escribió en el comentario:

 a2 <- as.data.frame(lapply(a, as.factor)) str(a2) 'data.frame': 100 obs. of 3 variables: $ x1: Factor w/ 100 levels "-2.49629293159922",..: 60 6 7 63 45 93 56 98 40 61 ... $ x2: Factor w/ 2 levels "a","b": 1 1 2 2 2 2 2 1 2 2 ... $ x3: Factor w/ 2 levels "a","b": 1 1 1 1 1 1 1 1 1 1 ... 

Pero si quiere reemplazar las columnas de caracteres seleccionadas con factor hay un truco:

 a3 <- data.frame(x1=letters, x2=LETTERS, x3=LETTERS, stringsAsFactors=FALSE) str(a3) 'data.frame': 26 obs. of 3 variables: $ x1: chr "a" "b" "c" "d" ... $ x2: chr "A" "B" "C" "D" ... $ x3: chr "A" "B" "C" "D" ... columns_to_change <- c("x1","x2") a3[, columns_to_change] <- lapply(a3[, columns_to_change], as.factor) str(a3) 'data.frame': 26 obs. of 3 variables: $ x1: Factor w/ 26 levels "a","b","c","d",..: 1 2 3 4 5 6 7 8 9 10 ... $ x2: Factor w/ 26 levels "A","B","C","D",..: 1 2 3 4 5 6 7 8 9 10 ... $ x3: chr "A" "B" "C" "D" ... 

Puede usarlo para reemplazar todas las columnas usando:

 a3 <- data.frame(x1=letters, x2=LETTERS, x3=LETTERS, stringsAsFactors=FALSE) a3[, ] <- lapply(a3, as.factor) str(a3) 'data.frame': 26 obs. of 3 variables: $ x1: Factor w/ 26 levels "a","b","c","d",..: 1 2 3 4 5 6 7 8 9 10 ... $ x2: Factor w/ 26 levels "A","B","C","D",..: 1 2 3 4 5 6 7 8 9 10 ... $ x3: Factor w/ 26 levels "A","B","C","D",..: 1 2 3 4 5 6 7 8 9 10 ...