Como ler dados quando alguns números contêm vírgulas como separador de milhar?

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

  •  19-09-2019
  •  | 
  •  

Pergunta

Eu tenho um arquivo csv onde alguns dos valores numéricos são expressos como strings com vírgulas como separador de milhar, por exemplo. "1,513" em vez de 1513.Qual é a maneira mais simples de ler os dados em R?

Eu posso usar read.csv(..., colClasses="character"), mas preciso retirar as vírgulas dos elementos relevantes antes de converter essas colunas em numérico e não consigo encontrar uma maneira legal de fazer isso.

Foi útil?

Solução 3

Quero usar R em vez de pré-processar os dados, pois facilita a revisão dos dados.Seguindo a sugestão de Shane de usar gsub, acho que isso é o mais legal que posso fazer:

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

Outras dicas

Não tenho certeza sobre como ter read.csv interprete -o corretamente, mas você pode usar gsub para substituir "," com "", e depois converter a string para numeric usando as.numeric:

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

Isso foi Também respondeu anteriormente no R-Help (e em Q2 aqui).

Como alternativa, você pode pré-processar o arquivo, por exemplo com sed em Unix.

Você pode ter lido.table ou read.csv fazer essa conversão para você semi-automaticamente. Primeiro, crie uma nova definição de classe, depois crie uma função de conversão e defina -a como um método "AS" usando a função Setas como assim:

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

Em seguida, execute read.csv como:

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

Esta pergunta tem vários anos, mas eu tropecei nela, o que significa que talvez outros o façam.

o readr A biblioteca / pacote possui alguns bons recursos. Uma delas é uma boa maneira de interpretar colunas "bagunçadas", como essas.

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

Isso rende

Fonte: quadro de dados local [4 x 1

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

Um ponto importante ao ler em arquivos: você precisa pré-processar, como o comentário acima sed, ou você tem que processar enquanto lê. Freqüentemente, se você tentar consertar as coisas após o fato, há algumas suposições perigosas feitas que são difíceis de encontrar. (É por isso que os arquivos planos são tão maus em primeiro lugar.)

Por exemplo, se eu não tivesse sinalizado o col_types, Eu teria conseguido o seguinte:

> 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

(Observe que agora é um chr (character) em vez de um numeric.)

Ou, mais perigosamente, se fosse longo e a maioria dos primeiros elementos não continha vírgulas:

> 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 os últimos elementos parecem :)

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

Então você encontrará problemas para ler essa vírgula!

> 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 solução usando mutate_all e tubos

diga que você tem o seguinte:

> 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

e deseja remover vírgulas das variáveis ​​do ano x2014-x2016 e convertê-las em numéricas.Além disso, digamos x2014-x2016 são lidos como fatores (padrão)

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

mutate_all aplica a(s) função(ões) dentro funs para as colunas especificadas

Eu fiz isso sequencialmente, uma função de cada vez (se você usar várias funções dentro funs então você cria colunas adicionais desnecessárias)

"Pré-processar" em R:

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

Pode usar readLines com um textConnection.Em seguida, remova apenas as vírgulas que estão entre os dígitos:

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

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

Também é útil saber, mas não diretamente relevante para esta questão, que vírgulas como separadores decimais podem ser tratadas por read.csv2 (automagicamente) ou read.table (com configuração do parâmetro 'dec').

Editar:Mais tarde descobri como usar colClasses projetando uma nova classe.Ver:

Como carregar df com separador 1000 em R como classe numérica?

Se o número for separado por "". e decimais por "," (1.200.000,00) na chamada gsub você deve set fixed=TRUE as.numeric(gsub(".","",y,fixed=TRUE))

Eu acho que o pré -processamento é o caminho a percorrer. Você poderia usar Notepad ++ que tem uma opção de substituição de expressão regular.

Por exemplo, se o seu arquivo era assim:

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

Então, você pode usar a expressão regular "([0-9]+),([0-9]+)" e substitua -o por \1\2

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

Então você pode usar x <- read.csv(file="x.csv",header=FALSE) para ler o arquivo.

Uma maneira muito conveniente é readr::read_delim-família. Tomando o exemplo daqui: Importando CSV com vários separadores em R Você pode fazer isso da seguinte maneira:

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

O que resulta no 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

Usando a função read_delim, que faz parte de leitura Biblioteca, você pode especificar parâmetro adicional:

locale = locale(decimal_mark = ",")

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

*Semicolon na segunda linha significa que read_delim lerá valores separados do CSV Semicolon.

Isso ajudará a ler todos os números com uma vírgula como números adequados.

Cumprimentos

Mateusz Kania

Também podemos usar readr::parse_number, as colunas devem ser caracteres.Se quisermos aplicá-lo a múltiplas colunas, podemos percorrer as colunas 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

Ou use mutate_at de dplyr para aplicá-lo a variáveis ​​específicas.

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

dados

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top