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.
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.
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'))
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))})
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.
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?
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)
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))
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.
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
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
.
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
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
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