¿Cómo convertir una columna de marco de datos a tipo numérico?

Respuestas:

267

Dado que (todavía) nadie obtuvo una marca de verificación, supongo que tiene algún problema práctico en mente, principalmente porque no ha especificado a qué tipo de vector desea convertir numeric. Le sugiero que aplique la transformfunción para completar su tarea.

Ahora estoy a punto de demostrar cierta "anomalía de conversión":

# create dummy data.frame
d <- data.frame(char = letters[1:5], 
                fake_char = as.character(1:5), 
                fac = factor(1:5), 
                char_fac = factor(letters[1:5]), 
                num = 1:5, stringsAsFactors = FALSE)

Echemos un vistazo a data.frame

> d
  char fake_char fac char_fac num
1    a         1   1        a   1
2    b         2   2        b   2
3    c         3   3        c   3
4    d         4   4        d   4
5    e         5   5        e   5

y vamos a correr:

> sapply(d, mode)
       char   fake_char         fac    char_fac         num 
"character" "character"   "numeric"   "numeric"   "numeric" 
> sapply(d, class)
       char   fake_char         fac    char_fac         num 
"character" "character"    "factor"    "factor"   "integer" 

Ahora probablemente te preguntas "¿Dónde hay una anomalía?" Bueno, he encontré con cosas muy peculiares en R, y esto no es la cosa más confusión, si bien se puede confundir, especialmente si lee esto antes de rodar en la cama.

Aquí va: las dos primeras columnas son character. He llamado deliberadamente 2 nd uno fake_char. Encuentra la similitud de esta charactervariable con una que Dirk creó en su respuesta. En realidad es un numericalvector convertido a character. 3 rd y 4 º columna son factor, y el último es "puramente" numeric.

Si utiliza la transformfunción, puede convertirla fake_charen numeric, pero no en la charvariable misma.

> transform(d, char = as.numeric(char))
  char fake_char fac char_fac num
1   NA         1   1        a   1
2   NA         2   2        b   2
3   NA         3   3        c   3
4   NA         4   4        d   4
5   NA         5   5        e   5
Warning message:
In eval(expr, envir, enclos) : NAs introduced by coercion

pero si haces lo mismo fake_chary char_factendrás suerte, y saldrás sin NA:

> transform(d, fake_char = as.numeric(fake_char), 
               char_fac = as.numeric(char_fac))

  char fake_char fac char_fac num
1    a         1   1        1   1
2    b         2   2        2   2
3    c         3   3        3   3
4    d         4   4        4   4
5    e         5   5        5   5

Si guarda transformado data.framey busca modey class, obtendrá:

> D <- transform(d, fake_char = as.numeric(fake_char), 
                    char_fac = as.numeric(char_fac))

> sapply(D, mode)
       char   fake_char         fac    char_fac         num 
"character"   "numeric"   "numeric"   "numeric"   "numeric" 
> sapply(D, class)
       char   fake_char         fac    char_fac         num 
"character"   "numeric"    "factor"   "numeric"   "integer"

Entonces, la conclusión es: Sí, puede convertir un charactervector en numericuno, pero solo si sus elementos son "convertibles" numeric. Si solo hay un characterelemento en el vector, obtendrá un error al intentar convertir ese vector en numericaluno.

Y solo para probar mi punto:

> err <- c(1, "b", 3, 4, "e")
> mode(err)
[1] "character"
> class(err)
[1] "character"
> char <- as.numeric(err)
Warning message:
NAs introduced by coercion 
> char
[1]  1 NA  3  4 NA

Y ahora, solo por diversión (o práctica), intente adivinar el resultado de estos comandos:

> fac <- as.factor(err)
> fac
???
> num <- as.numeric(fac)
> num
???

Saludos cordiales a Patrick Burns! =)

aL3xa
fuente
66
'stringsAsFactors = FALSE' es importante para leer archivos de datos.
Robert Brisita
44
Sé que esto es viejo ... pero ... ¿por qué elegiste transform () sobre df $ fake_char <- as.integer (df $ fake_char)? Hay varias formas de hacer la misma operación en R y me atasco entendiendo la forma "correcta" de hacerlo. Gracias.
ripvlan
Entonces, ¿es absolutamente imposible convertir err <- c (1, "b", 3, 4, "e") en un vector numérico? En Excel, hay un botón que le permite "convertir a número". haciendo que cualquier valor de la columna sea numérico. Estoy tratando de imitar eso en r.
flightless13wings
¡Advertencia! = Error. No obtiene un error al convertir un número / carácter mixto a numérico, recibe una advertencia y algunos valores de NA.
Gregor Thomas
136

Algo que me ha ayudado: si tiene rangos de variables para convertir (o solo más de uno), puede usar sapply.

Un poco absurdo pero solo por ejemplo:

data(cars)
cars[, 1:2] <- sapply(cars[, 1:2], as.factor)

Supongamos que las columnas 3, 6-15 y 37 de su marco de datos deben convertirse a una numérica que podría:

dat[, c(3,6:15,37)] <- sapply(dat[, c(3,6:15,37)], as.numeric)
Arrendajo
fuente
1
as.factor en el código anterior hace que el carácter de la columna
MySchizoBuddy
1
sapply es mejor que transformar, cuando se manejan vectores de índices en lugar de nombres de variables
smci
@MySchizoBuddy es correcto, al menos con mis datos. El df original no tomará las columnas "convertidas" como factores; seguirán siendo personajes. Si ajusta la sapplyllamada en as.data.frame()el lado derecho, como @Mehrad Mahmoudian sugirió a continuación, funcionará.
knowah
¿Funcionará esto para una matriz? Lo estoy intentando con el mismo código exacto, pero cuando verifico la clase () de una columna después, todavía dice "carácter" y no "numérico"
namore
87

si xes el nombre de columna del marco de datos daty xes de tipo factor, use:

as.numeric(as.character(dat$x))
pangratz
fuente
3
agregar de as.characterhecho es lo que estaba buscando. De lo contrario, la conversión a veces sale mal. Al menos en mi caso.
Thieme Hennis
1
¿Por qué se necesita el as.character? Recibía un error: Error: (list) object cannot be coerced to type 'double'aunque estaba razonablemente seguro de que mi vector no tenía caracteres / signos de puntuación. Luego lo intenté as.numeric(as.character(dat$x))y funcionó. ¡Ahora no estoy seguro de si mi columna es de hecho solo enteros o no!
vagabundo
2
Si hace as.numeric a un factor, convertirá los niveles a numéricos, no a los valores reales. Por lo tanto, as.character es necesario para convertir primero el factor a character y luego as.numeric
MySchizoBuddy
Esta es la mejor respuesta aquí
mitoRibo
25

Hubiera agregado un comentario (no puedo calificar bajo)

Solo para agregar en user276042 y pangratz

dat$x = as.numeric(as.character(dat$x))

Esto anulará los valores de la columna x existente

Somum
fuente
16

Si bien su pregunta es estrictamente numérica, hay muchas conversiones que son difíciles de entender al comenzar R. Voy a tratar de abordar los métodos para ayudar. Esta pregunta es similar a esta pregunta .

La conversión de tipos puede ser una molestia en R porque (1) los factores no se pueden convertir directamente a numéricos, primero deben convertirse a la clase de caracteres, (2) las fechas son un caso especial que generalmente necesita tratar por separado, y (3) recorrer las columnas del marco de datos puede ser complicado. Afortunadamente, el "tidyverse" ha resuelto la mayoría de los problemas.

Esta solución se utiliza mutate_each()para aplicar una función a todas las columnas en un marco de datos. En este caso, queremos aplicar la type.convert()función, que convierte las cadenas en numéricas donde puede. Debido a que R ama los factores (no estoy seguro de por qué), las columnas de caracteres que deben permanecer como caracteres se cambian a factor. Para solucionar esto, la mutate_if()función se usa para detectar columnas que son factores y cambiar a caracteres. Por último, quería mostrar cómo se puede usar lubridate para cambiar una marca de tiempo en la clase de caracteres a fecha y hora porque a menudo esto también es un obstáculo para los principiantes.


library(tidyverse) 
library(lubridate)

# Recreate data that needs converted to numeric, date-time, etc
data_df
#> # A tibble: 5 × 9
#>             TIMESTAMP SYMBOL    EX  PRICE  SIZE  COND   BID BIDSIZ   OFR
#>                 <chr>  <chr> <chr>  <chr> <chr> <chr> <chr>  <chr> <chr>
#> 1 2012-05-04 09:30:00    BAC     T 7.8900 38538     F  7.89    523  7.90
#> 2 2012-05-04 09:30:01    BAC     Z 7.8850   288     @  7.88  61033  7.90
#> 3 2012-05-04 09:30:03    BAC     X 7.8900  1000     @  7.88   1974  7.89
#> 4 2012-05-04 09:30:07    BAC     T 7.8900 19052     F  7.88   1058  7.89
#> 5 2012-05-04 09:30:08    BAC     Y 7.8900 85053     F  7.88 108101  7.90

# Converting columns to numeric using "tidyverse"
data_df %>%
    mutate_all(type.convert) %>%
    mutate_if(is.factor, as.character) %>%
    mutate(TIMESTAMP = as_datetime(TIMESTAMP, tz = Sys.timezone()))
#> # A tibble: 5 × 9
#>             TIMESTAMP SYMBOL    EX PRICE  SIZE  COND   BID BIDSIZ   OFR
#>                <dttm>  <chr> <chr> <dbl> <int> <chr> <dbl>  <int> <dbl>
#> 1 2012-05-04 09:30:00    BAC     T 7.890 38538     F  7.89    523  7.90
#> 2 2012-05-04 09:30:01    BAC     Z 7.885   288     @  7.88  61033  7.90
#> 3 2012-05-04 09:30:03    BAC     X 7.890  1000     @  7.88   1974  7.89
#> 4 2012-05-04 09:30:07    BAC     T 7.890 19052     F  7.88   1058  7.89
#> 5 2012-05-04 09:30:08    BAC     Y 7.890 85053     F  7.88 108101  7.90
Matt Dancho
fuente
Tenga en cuenta que si usa en mutate_all(type.convert, as.is=TRUE)lugar de mutate_all(type.convert), puede eliminar / evitar mutate_if(is.factor, as.character)para acortar el comando. as.ises un argumento type.convert()que indica si debe convertir cadenas como caracteres o como factores. Por defecto, as.is=FALSEen type.convert()(es decir, convierte cadenas a la clase de factor en lugar de la clase de caracteres).
LC-datascientist
15

Tim tiene razón y Shane tiene una omisión. Aquí hay ejemplos adicionales:

R> df <- data.frame(a = as.character(10:15))
R> df <- data.frame(df, num = as.numeric(df$a), 
                        numchr = as.numeric(as.character(df$a)))
R> df
   a num numchr
1 10   1     10
2 11   2     11
3 12   3     12
4 13   4     13
5 14   5     14
6 15   6     15
R> summary(df)
  a          num           numchr    
 10:1   Min.   :1.00   Min.   :10.0  
 11:1   1st Qu.:2.25   1st Qu.:11.2  
 12:1   Median :3.50   Median :12.5  
 13:1   Mean   :3.50   Mean   :12.5  
 14:1   3rd Qu.:4.75   3rd Qu.:13.8  
 15:1   Max.   :6.00   Max.   :15.0  
R> 

Nuestro data.frameahora tiene un resumen de la columna de factores (conteos) y resúmenes numéricos de as.numeric()--- lo cual es incorrecto ya que obtuvo los niveles de factores numéricos --- y el resumen (correcto) de as.numeric(as.character()).

Dirk Eddelbuettel
fuente
1
El gusto es mio. Este es uno de los rincones más tontos del lenguaje, y creo que apareció en la pregunta anterior 'R Gotchas' aquí.
Dirk Eddelbuettel
14

Con el siguiente código, puede convertir todas las columnas del marco de datos a numérico (X es el marco de datos que queremos convertir sus columnas):

as.data.frame(lapply(X, as.numeric))

y para convertir toda la matriz en numérico, tiene dos formas: O:

mode(X) <- "numeric"

o:

X <- apply(X, 2, as.numeric)

Alternativamente, puede usar la data.matrixfunción para convertir todo en numérico, aunque tenga en cuenta que los factores podrían no convertirse correctamente, por lo que es más seguro convertir todo a characterprimero:

X <- sapply(X, as.character)
X <- data.matrix(X)

Usualmente uso este último si quiero convertir a matriz y numérico simultáneamente

Mehrad Mahmoudian
fuente
12

Si tiene problemas con:

as.numeric(as.character(dat$x))

Echa un vistazo a tus signos decimales. Si son "," en lugar de "." (por ejemplo, "5,3") lo anterior no funcionará.

Una posible solución es:

as.numeric(gsub(",", ".", dat$x))

Creo que esto es bastante común en algunos países que no hablan inglés.

Gorka
fuente
8

Manera universal usando type.convert()y rapply():

convert_types <- function(x) {
    stopifnot(is.list(x))
    x[] <- rapply(x, utils::type.convert, classes = "character",
                  how = "replace", as.is = TRUE)
    return(x)
}
d <- data.frame(char = letters[1:5], 
                fake_char = as.character(1:5), 
                fac = factor(1:5), 
                char_fac = factor(letters[1:5]), 
                num = 1:5, stringsAsFactors = FALSE)
sapply(d, class)
#>        char   fake_char         fac    char_fac         num 
#> "character" "character"    "factor"    "factor"   "integer"
sapply(convert_types(d), class)
#>        char   fake_char         fac    char_fac         num 
#> "character"   "integer"    "factor"    "factor"   "integer"
Artem Klevtsov
fuente
3
Esta es la solución más flexible: ¡merece algunos votos positivos!
Richard Border
Debería ser una respuesta superior. Simplemente elimine as.is = TRUEsi desea convertir su personaje a numérico o factores
qfazille
Tratar de cambiar montón de columnas en una hoja.de.datos que tiene el tipo matrixde cambios numéricos classes=matrixerróneos a cabo primer argumento debe ser de tipo caracter
add-punto y coma
1
Esta es la mejor respuesta en el tema.
yuk
3

Para convertir una columna de marco de datos a numérico solo tiene que hacer: -

factor a numérico: -

data_frame$column <- as.numeric(as.character(data_frame$column))
Aayush Agrawal
fuente
Nuevamente, esta respuesta no agrega nada al conjunto actual de respuestas. Además, no es la forma preferida de convertir un factor a numérico. Consulte stackoverflow.com/q/3418128 para conocer la forma preferida.
BenBarnes
Una mejor respuesta fue:sapply(data_frame,function(x) as.numeric(as.character(x)))
data-frame-gg
2

Aunque otros han cubierto el tema bastante bien, me gustaría agregar este pensamiento rápido / pista adicional. Puede usar regexp para verificar de antemano si los caracteres pueden consistir solo en números.

for(i in seq_along(names(df)){
     potential_numcol[i] <- all(!grepl("[a-zA-Z]",d[,i]))
}
# and now just convert only the numeric ones
d <- sapply(d[,potential_numcol],as.numeric)

Para expresiones regulares más sofisticadas y una razón clara para aprender / experimentar su poder, vea este sitio web realmente agradable: http://regexr.com/

Matt Bannert
fuente
1

Teniendo en cuenta que pueden existir columnas de caracteres, esto se basa en @Abdou en Obtener tipos de columnas de hoja de Excel y responde automáticamente :

makenumcols<-function(df){
  df<-as.data.frame(df)
  df[] <- lapply(df, as.character)
  cond <- apply(df, 2, function(x) {
    x <- x[!is.na(x)]
    all(suppressWarnings(!is.na(as.numeric(x))))
  })
  numeric_cols <- names(df)[cond]
  df[,numeric_cols] <- sapply(df[,numeric_cols], as.numeric)
  return(df)
}
df<-makenumcols(df)
Ferroao
fuente
0

En mi PC (R v.3.2.3), applyo sapplydar error. lapplyfunciona bien.

dt[,2:4] <- lapply(dt[,2:4], function (x) as.factor(as.numeric(x)))
JKim
fuente
0

Si el marco de datos tiene varios tipos de columnas, algunos caracteres, algunos numéricos, intente lo siguiente para convertir solo las columnas que contienen valores numéricos en numéricos:

for (i in 1:length(data[1,])){
  if(length(as.numeric(data[,i][!is.na(data[,i])])[!is.na(as.numeric(data[,i][!is.na(data[,i])]))])==0){}
  else {
    data[,i]<-as.numeric(data[,i])
  }
}
Philipp
fuente
0

con hablar :: convertir

Para convertir fácilmente múltiples columnas a diferentes tipos de datos que puede usar hablar::convert. Sintaxis simple: df %>% convert(num(a))convierte la columna a de df a numérica.

Ejemplo detallado

Vamos a convertir todas las columnas de mtcarsa carácter.

df <- mtcars %>% mutate_all(as.character) %>% as_tibble()

> df
# A tibble: 32 x 11
   mpg   cyl   disp  hp    drat  wt    qsec  vs    am    gear  carb 
   <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
 1 21    6     160   110   3.9   2.62  16.46 0     1     4     4    
 2 21    6     160   110   3.9   2.875 17.02 0     1     4     4    
 3 22.8  4     108   93    3.85  2.32  18.61 1     1     4     1    

Con hablar::convert:

library(hablar)

# Convert columns to integer, numeric and factor
df %>% 
  convert(int(cyl, vs),
          num(disp:wt),
          fct(gear))

resultados en:

# A tibble: 32 x 11
   mpg     cyl  disp    hp  drat    wt qsec     vs am    gear  carb 
   <chr> <int> <dbl> <dbl> <dbl> <dbl> <chr> <int> <chr> <fct> <chr>
 1 21        6  160    110  3.9   2.62 16.46     0 1     4     4    
 2 21        6  160    110  3.9   2.88 17.02     0 1     4     4    
 3 22.8      4  108     93  3.85  2.32 18.61     1 1     4     1    
 4 21.4      6  258    110  3.08  3.22 19.44     1 0     3     1   
davsjob
fuente
0

Para convertir el carácter a numérico, debe convertirlo en factor aplicando

BankFinal1 <- transform(BankLoan,   LoanApproval=as.factor(LoanApproval))
BankFinal1 <- transform(BankFinal1, LoanApp=as.factor(LoanApproval))

Tienes que hacer dos columnas con los mismos datos, porque una columna no puede convertirse en numérica. Si haces una conversión, da el siguiente error

transform(BankData, LoanApp=as.numeric(LoanApproval))
Warning message:
  In eval(substitute(list(...)), `_data`, parent.frame()) :
  NAs introduced by coercion

entonces, después de hacer dos columnas de los mismos datos aplican

BankFinal1 <- transform(BankFinal1, LoanApp      = as.numeric(LoanApp), 
                                    LoanApproval = as.numeric(LoanApproval))

transformará el carácter a numérico con éxito

jadhav suraj
fuente
0

dfEs su marco de datos. xes una columna de la dfque quieres convertir

as.numeric(factor(df$x))
Justin Lange
fuente
0

Si no le importa preservar los factores y desea aplicarlo a cualquier columna que se pueda convertir a numérico, utilicé el script a continuación. si df es su marco de datos original, puede usar el siguiente script.

df[] <- lapply(df, as.character)
df <- data.frame(lapply(df, function(x) ifelse(!is.na(as.numeric(x)), as.numeric(x),  x)))

Hice referencia a la solución de Shane y Joran por cierto

Michael Kassa
fuente