Jak odczytać dane, gdy niektóre liczby zawierają przecinki jako separator tysięcy?

Mam plik csv, gdzie niektóre wartości liczbowe są wyrażone jako ciągi znaków z przecinkami jako separator tysięcy, np. "1,513" zamiast 1513. Jaki jest najprostszy sposób odczytu danych do R?

Mogę użyć read.csv(..., colClasses="character"), ale potem muszę usunąć przecinki z odpowiednich elementów przed konwersją tych kolumn na Liczby i nie mogę znaleźć na to porządnego sposobu.

 100
Author: Henrik, 2009-10-06

12 answers

Nie wiesz, jak poprawnie zinterpretować read.csv, ale możesz użyć gsub, aby zastąpić "," przez "", a następnie przekonwertować łańcuch na numeric używając as.numeric:

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

To było również odpowiedział wcześniej na R-Help (i w Q2 tutaj ).

Alternatywnie, możesz wstępnie przetworzyć plik, na przykład za pomocą sed w Uniksie.

 119
Author: Shane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-21 18:06:42

Można było przeczytać.table or read.plik csv wykonuje tę konwersję za Ciebie półautomatycznie. Najpierw Utwórz nową definicję klasy, a następnie utwórz funkcję konwersji i ustaw ją jako metodę "as", używając funkcji setAs w ten sposób:

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

Następnie uruchom read.csv like:

DF <- read.csv('your.file.here', 
   colClasses=c('num.with.commas','factor','character','numeric','num.with.commas'))
 50
Author: Greg Snow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-30 17:20:36

Chcę użyć R zamiast wstępnego przetwarzania danych, ponieważ ułatwia to poprawianie danych. Po sugestii Shane ' a, aby użyć gsub, myślę, że jest to tak schludne, jak Mogę zrobić:

x <- read.csv("file.csv",header=TRUE,colClasses="character")
col2cvt <- 15:41
x[,col2cvt] <- lapply(x[,col2cvt],function(x){as.numeric(gsub(",", "", x))})
 14
Author: Rob Hyndman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-06 03:15:28

[12]}to pytanie ma kilka lat, ale natknąłem się na nie, co oznacza, że może inni będą.

The readr biblioteka / pakiet ma kilka fajnych funkcji do niego. Jednym z nich jest dobry sposób na interpretację "brudnych" kolumn, takich jak te.

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

To daje

Źródło: lokalna ramka danych [4 x 1]

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

Ważny punkt podczas czytania w plikach: albo musisz wstępnie przetworzyć, jak powyższy komentarz dotyczący sed, albo musisz przetworzyć podczas czytania . Często, jeśli próbujesz naprawić rzeczy po fakcie, są pewne niebezpieczne założenia, które są trudne do znalezienia. (Dlatego płaskie pliki są tak złe w pierwszej kolejności.)

Na przykład, gdybym nie oznaczył col_types, dostałbym to:

> 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

(zauważ, że jest to teraz chr (character) zamiast numeric.)

Lub, bardziej niebezpiecznie, gdyby był wystarczająco długi i większość wczesnych elementów nie zawierała przecinki:

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

(tak aby ostatnie elementy wyglądały jak:)

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

Wtedy będziesz miał problemy z odczytaniem tego przecinka w ogóle!

> 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. 
 11
Author: Mike Williamson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-17 23:31:30

"Preprocess" w R:

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

Może używać readLines na textConnection. Następnie usuń tylko przecinki znajdujące się między cyframi:

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

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

Warto wiedzieć, ale nie bezpośrednio związane z tym pytaniem, że przecinki jako separatory dziesiętne mogą być obsługiwane przez read.csv2 (automagicznie) lub read.tabela (z ustawieniem parametru 'dec').

Edit: później odkryłem jak używać colClasses projektując nową klasę. Zobacz:

Jak załadować DF separatorem 1000 W R jako liczbowym zajęcia?

 6
Author: 42-,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:13

A dplyr rozwiązanie za pomocą mutate_each i rur

Powiedz, że masz:

> 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

I chcesz usunąć przecinki ze zmiennych roku X2014-X2016, oraz konwertuj je na liczbowe. Załóżmy również, że X2014-X2016 są odczytywane jako czynniki (domyślnie)

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

mutate_each Zastosowanie funkcji wewnątrz funs do podanych kolumn

Zrobiłem to sekwencyjnie, jedna funkcja na raz (jeśli używasz wielu funkcje wewnątrz funs wtedy tworzysz dodatkowe, niepotrzebne kolumny)

 4
Author: Paul Paczuski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-28 05:31:18

Jeśli liczba jest oddzielona przez "."i dziesiętne przez", " (1.200.000, 00) w wywołaniu gsub musisz set fixed=TRUE as.numeric(gsub(".","",y,fixed=TRUE))

 3
Author: aca,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-07 14:52:18

Myślę, że preprocessing jest drogą do zrobienia. Możesz użyć Notepad++, który ma opcję zamiany wyrażeń regularnych.

Na przykład, jeśli Twój plik byłby taki:

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

Następnie możesz użyć wyrażenia regularnego "([0-9]+),([0-9]+)" i zastąpić je \1\2

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

Następnie możesz użyć x <- read.csv(file="x.csv",header=FALSE), Aby odczytać plik.

 2
Author: Jacob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-25 17:31:58

Bardzo wygodnym sposobem jest readr::read_delim-rodzina. Biorąc stąd przykład: Importowanie pliku csv z wieloma separatorami do R można wykonać w następujący sposób:

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

Co daje oczekiwany wynik:

# 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
 1
Author: Rentrop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:16

Inne rozwiązanie:

 y <- c("1,200","20,000","100","12,111") 

 as.numeric(unlist(lapply( strsplit(y,","),paste, collapse="")))

Będzie jednak znacznie wolniejszy niż gsub.

 0
Author: liujx80,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-01 07:47:40

To nie jest tak skomplikowane, spróbuj tego: y

 0
Author: Colonelxy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 06:17:59

Używając funkcji read_delim, która jest częścią biblioteki readr , możesz podać dodatkowy parametr:

locale = locale(decimal_mark = ",")

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

*średnik w drugiej linii oznacza, że read_delim odczyta wartości oddzielone średnikiem csv.

To pomoże odczytać wszystkie liczby z przecinkiem jako liczby właściwe.

Pozdrawiam

Mateusz Kania

 -1
Author: Mateusz Kania,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-20 20:44:59