¿Cómo leer datos cuando algunos números contienen comas como separador de miles?

StackOverflow https://stackoverflow.com/questions/1523126

  •  19-09-2019
  •  | 
  •  

Pregunta

Tengo un archivo csv donde algunos de los valores numéricos se expresan como cadenas con comas como separador de miles, p. "1,513" en lugar de 1513.¿Cuál es la forma más sencilla de leer los datos en R?

Puedo usar read.csv(..., colClasses="character"), pero luego tengo que eliminar las comas de los elementos relevantes antes de convertir esas columnas a numéricas, y no puedo encontrar una manera clara de hacerlo.

¿Fue útil?

Solución 3

Quiero usar R en lugar de preprocesar los datos, ya que lo hace más fácil cuando se revisan los datos. Siguiendo la sugerencia de Shane de usar gsub, Creo que esto es lo más bueno que puedo:

x <- read.csv("file.csv",header=TRUE,colClasses="character")
col2cvt <- 15:41
x[,col2cvt] <- lapply(x[,col2cvt],function(x){as.numeric(gsub(",", "", x))})

Otros consejos

No estoy seguro de cómo tener read.csv interpretarlo correctamente, pero puede usar gsub para reemplazar "," con "", y luego convierta la cadena en numeric usando as.numeric:

y <- c("1,200","20,000","100","12,111")
as.numeric(gsub(",", "", y))
# [1]  1200 20000 100 12111

Esto era también respondió anteriormente en R-Help (y en Q2 aquí).

Alternativamente, puede preprocesar el archivo, por ejemplo con sed En Unix.

Puede tener lectura. Tabla o lectura. Primero cree una nueva definición de clase, luego cree una función de conversión y estén como un método "como" usando la función SETAS como SO:

setClass("num.with.commas")
setAs("character", "num.with.commas", 
        function(from) as.numeric(gsub(",", "", from) ) )

Luego ejecute Read.csv como:

DF <- read.csv('your.file.here', 
   colClasses=c('num.with.commas','factor','character','numeric','num.with.commas'))

Esta pregunta tiene varios años, pero me topé con ella, lo que significa que tal vez otros lo harán.

los readr La biblioteca / paquete tiene algunas características agradables. Una de ellas es una buena manera de interpretar columnas "desordenadas", como estas.

library(readr)
read_csv("numbers\n800\n\"1,800\"\n\"3500\"\n6.5",
          col_types = list(col_numeric())
        )

Esto rendimiento

Fuente: Marco de datos local [4 x 1

  numbers
    (dbl)
1   800.0
2  1800.0
3  3500.0
4     6.5

Un punto importante al leer en archivos: debe preprocesar, como el comentario anterior sobre sed, o tienes que procesar mientras leo. A menudo, si intenta arreglar las cosas después del hecho, hay algunos supuestos peligrosos que son difíciles de encontrar. (Por eso los archivos planos son tan malvados en primer lugar).

Por ejemplo, si no hubiera marcado el col_types, Habría obtenido esto:

> read_csv("numbers\n800\n\"1,800\"\n\"3500\"\n6.5")
Source: local data frame [4 x 1]

  numbers
    (chr)
1     800
2   1,800
3    3500
4     6.5

(Tenga en cuenta que ahora es un chr (character) en lugar de un numeric.)

O, más peligrosamente, si fuera lo suficientemente largo y la mayoría de los primeros elementos no contenían comas:

> set.seed(1)
> tmp <- as.character(sample(c(1:10), 100, replace=TRUE))
> tmp <- c(tmp, "1,003")
> tmp <- paste(tmp, collapse="\"\n\"")

(de modo que se parezcan los últimos elementos :)

\"5\"\n\"9\"\n\"7\"\n\"1,003"

¡Entonces encontrarás problemas para leer esa coma!

> tail(read_csv(tmp))
Source: local data frame [6 x 1]

     3"
  (dbl)
1 8.000
2 5.000
3 5.000
4 9.000
5 7.000
6 1.003
Warning message:
1 problems parsing literal data. See problems(...) for more details. 

a dplyr Solución usando mutate_all y tuberías

Digamos que tienes lo siguiente:

> dft
Source: local data frame [11 x 5]

   Bureau.Name Account.Code   X2014   X2015   X2016
1       Senate          110 158,000 211,000 186,000
2       Senate          115       0       0       0
3       Senate          123  15,000  71,000  21,000
4       Senate          126   6,000  14,000   8,000
5       Senate          127 110,000 234,000 134,000
6       Senate          128 120,000 159,000 134,000
7       Senate          129       0       0       0
8       Senate          130 368,000 465,000 441,000
9       Senate          132       0       0       0
10      Senate          140       0       0       0
11      Senate          140       0       0       0

y quiere eliminar las comas de las variables del año X2014-X2016, y convertirlas en numéricos. Además, digamos que X2014-X2016 se leen como factores (predeterminados)

dft %>%
    mutate_all(funs(as.character(.)), X2014:X2016) %>%
    mutate_all(funs(gsub(",", "", .)), X2014:X2016) %>%
    mutate_all(funs(as.numeric(.)), X2014:X2016)

mutate_all aplica las funciones dentro funs a las columnas especificadas

Lo hice secuencialmente, una función a la vez (si usa múltiples funciones dentro funs Luego crea columnas adicionales e innecesarias)

"Preproceso" en R:

lines <- "www, rrr, 1,234, ttt \n rrr,zzz, 1,234,567,987, rrr"

Puedo usar readLines en un textConnection.Luego elimine solo las comas que están entre los dígitos:

gsub("([0-9]+)\\,([0-9])", "\\1\\2", lines)

## [1] "www, rrr, 1234, ttt \n rrr,zzz, 1234567987, rrr"

También es útil saber, pero no es directamente relevante para esta pregunta, que las comas como separadores decimales pueden ser manejadas por read.csv2 (automágicamente) o read.table (con la configuración del parámetro 'dec').

Editar:Posteriormente descubrí cómo usar colClasses diseñando una nueva clase.Ver:

¿Cómo cargar df con separador 1000 en R como clase numérica?

Si el número está separado por "." y decimales por "," (1.200.000,00) en llamadas gsub debes set fixed=TRUE as.numeric(gsub(".","",y,fixed=TRUE))

Creo que el preprocesamiento es el camino a seguir. Podrías usar Notepad ++ que tiene una opción de reemplazo de expresión regular.

Por ejemplo, si su archivo fuera así:

"1,234","123","1,234"
"234","123","1,234"
123,456,789

Entonces, podrías usar la expresión regular "([0-9]+),([0-9]+)" y reemplácelo con \1\2

1234,"123",1234
"234","123",1234
123,456,789

Entonces podrías usar x <- read.csv(file="x.csv",header=FALSE) para leer el archivo.

Una forma muy conveniente es readr::read_delim-familia. Tomando el ejemplo de aquí: Importar CSV con múltiples separadores en R Puedes hacerlo de la siguiente manera:

txt <- 'OBJECTID,District_N,ZONE_CODE,COUNT,AREA,SUM
1,Bagamoyo,1,"136,227","8,514,187,500.000000000000000","352,678.813105723350000"
2,Bariadi,2,"88,350","5,521,875,000.000000000000000","526,307.288878142830000"
3,Chunya,3,"483,059","30,191,187,500.000000000000000","352,444.699742995200000"'

require(readr)
read_csv(txt) # = read_delim(txt, delim = ",")

Que resulta en el resultado esperado:

# A tibble: 3 × 6
  OBJECTID District_N ZONE_CODE  COUNT        AREA      SUM
     <int>      <chr>     <int>  <dbl>       <dbl>    <dbl>
1        1   Bagamoyo         1 136227  8514187500 352678.8
2        2    Bariadi         2  88350  5521875000 526307.3
3        3     Chunya         3 483059 30191187500 352444.7

Uso de la función read_delim, que es parte de readr Biblioteca, puede especificar un parámetro adicional:

locale = locale(decimal_mark = ",")

read_delim("filetoread.csv", ';", locale = locale(decimal_mark = ","))

*Semicolon en segunda línea significa que Read_Delim leerá valores separados por semicolon CSV.

Esto ayudará a leer todos los números con una coma como números adecuados.

Saludos

Mateusz Kania

También podemos usar readr::parse_number, Sin embargo, las columnas deben ser caracteres. Si queremos aplicarlo para varias columnas, podemos recorrer columnas usando lapply

df[2:3] <- lapply(df[2:3], readr::parse_number)
df

#  a        b        c
#1 a    12234       12
#2 b      123  1234123
#3 c     1234     1234
#4 d 13456234    15342
#5 e    12312 12334512

O usar mutate_at de dplyr para aplicarlo a variables específicas.

library(dplyr)
df %>% mutate_at(2:3, readr::parse_number)
#Or
df %>% mutate_at(vars(b:c), readr::parse_number)

datos

df <- data.frame(a = letters[1:5], 
                 b = c("12,234", "123", "1,234", "13,456,234", "123,12"),
                 c = c("12", "1,234,123","1234", "15,342", "123,345,12"), 
                 stringsAsFactors = FALSE)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top