¿Cómo leer datos cuando algunos números contienen comas como separador de miles?
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.
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)