Mam więc plik danych (oddzielony średnikami), który zawiera dużo szczegółów i niekompletne wiersze (prowadząc Access i SQL do dławienia). Jest to zestaw danych na poziomie hrabstwa podzielony na segmenty, podsegmenty i podsegmenty (łącznie ~ 200 czynników) przez 40 lat. Krótko mówiąc, jest ogromny i nie zmieści się w pamięci, jeśli spróbuję go po prostu przeczytać.
Więc moje pytanie jest takie, biorąc pod uwagę, że chcę wszystkie hrabstwa, ale tylko jeden rok (i tylko najwyższy poziom segmentu ... prowadzący do około 100 000 wierszy na końcu), jaki byłby najlepszy sposób na uzyskanie ten pakiet zbiorczy w R?
Obecnie staram się odciąć nieistotne lata z Pythonem, omijając limit rozmiaru pliku, czytając i działając w jednej linii na raz, ale wolałbym rozwiązanie tylko R (pakiety CRAN OK). Czy istnieje podobny sposób wczytywania w plikach fragmentu na raz w R?
Wszelkie pomysły będą mile widziane.
Aktualizacja:
- Ograniczenia
- Musi używać mojego komputera, więc nie ma instancji EC2
- Jak najbardziej R-only. Szybkość i zasoby nie są w tym przypadku problemem ... pod warunkiem, że mój komputer nie eksploduje ...
- Jak widać poniżej, dane zawierają typy mieszane, na których będę musiał później operować
- Dane
- Dane mają pojemność 3,5 GB, około 8,5 miliona wierszy i 17 kolumn
- Kilka tysięcy wierszy (~ 2k) jest zniekształconych, a tylko jedna kolumna zamiast 17
- Są całkowicie nieistotne i można je porzucić
- Potrzebuję tylko ~ 100 000 wierszy z tego pliku (patrz poniżej)
Przykład danych:
County; State; Year; Quarter; Segment; Sub-Segment; Sub-Sub-Segment; GDP; ...
Ada County;NC;2009;4;FIRE;Financial;Banks;80.1; ...
Ada County;NC;2010;1;FIRE;Financial;Banks;82.5; ...
NC [Malformed row]
[8.5 Mill rows]
Chcę wyciąć kilka kolumn i wybrać dwa z 40 dostępnych lat (2009-2010 od 1980-2020), aby dane pasowały do R:
County; State; Year; Quarter; Segment; GDP; ...
Ada County;NC;2009;4;FIRE;80.1; ...
Ada County;NC;2010;1;FIRE;82.5; ...
[~200,000 rows]
Wyniki:
Po majstrowaniu przy wszystkich sugestiach zdecydowałem, że najlepiej sprawdzi się readLines, zaproponowane przez JD i Marka. Dałem Markowi czek, bo dał przykładową realizację.
Aby uzyskać ostateczną odpowiedź, odtworzyłem nieco dostosowaną wersję implementacji Marka, używając strsplit i cat, aby zachować tylko wybrane kolumny.
Należy również zauważyć, że jest to DUŻO mniej wydajne niż Python ... tak jak w przypadku, Python przeskakuje plik 3,5 GB w 5 minut, podczas gdy R zajmuje około 60 ... ale jeśli wszystko, co masz, to R, to jest to bilet.
## Open a connection separately to hold the cursor position
file.in <- file('bad_data.txt', 'rt')
file.out <- file('chopped_data.txt', 'wt')
line <- readLines(file.in, n=1)
line.split <- strsplit(line, ';')
# Stitching together only the columns we want
cat(line.split[[1]][1:5], line.split[[1]][8], sep = ';', file = file.out, fill = TRUE)
## Use a loop to read in the rest of the lines
line <- readLines(file.in, n=1)
while (length(line)) {
line.split <- strsplit(line, ';')
if (length(line.split[[1]]) > 1) {
if (line.split[[1]][3] == '2009') {
cat(line.split[[1]][1:5], line.split[[1]][8], sep = ';', file = file.out, fill = TRUE)
}
}
line<- readLines(file.in, n=1)
}
close(file.in)
close(file.out)
Błędy według podejścia:
- sqldf
- Z pewnością tego będę używał do tego typu problemów w przyszłości, jeśli dane są dobrze sformułowane. Jeśli jednak tak nie jest, dławiki SQLite.
- MapReduce
- Szczerze mówiąc, doktorzy trochę mnie onieśmielali, więc nie próbowałem tego. Wyglądało na to, że wymagało to, aby obiekt był również w pamięci, co podważyłoby sedno sprawy, gdyby tak było.
- bigmemory
- To podejście jest czysto połączone z danymi, ale może obsługiwać tylko jeden typ na raz. W rezultacie wszystkie moje wektory postaci spadły, gdy zostały umieszczone w dużej tabeli. Jeśli jednak muszę zaprojektować duże zestawy danych na przyszłość, rozważałbym użycie liczb tylko po to, aby utrzymać tę opcję przy życiu.
- skanowanie
- Scan wydawał się mieć podobne problemy jak duża pamięć, ale z całą mechaniką readLines. Krótko mówiąc, tym razem po prostu nie pasowało do rachunku.
sed
i / lubawk
utworzeniu skróconej wersji pliku CSV, którą możesz przeczytać bezpośrednio. Ponieważ jest to raczej obejście niż odpowiedź, zostawię to w komentarzu.fread
Funkcja jest znacznie szybsze niżread.table
. Użyj czegoś podobnegox = fread(file_path_here, data.table=FALSE)
do załadowania go jakodata.frame
obiektu.Odpowiedzi:
Moja próba z
readLines
. Ten fragment kodu tworzy sięcsv
z wybranymi latami.file_in <- file("in.csv","r") file_out <- file("out.csv","a") x <- readLines(file_in, n=1) writeLines(x, file_out) # copy headers B <- 300000 # depends how large is one pack while(length(x)) { ind <- grep("^[^;]*;[^;]*; 20(09|10)", x) if (length(ind)) writeLines(x[ind], file_out) x <- readLines(file_in, n=B) } close(file_in) close(file_out)
źródło
Nie jestem w tym ekspertem, ale możesz rozważyć wypróbowanie MapReduce , co w zasadzie oznaczałoby przyjęcie podejścia „dziel i rządź”. R ma kilka opcji, w tym:
Alternatywnie, R udostępnia kilka pakietów do obsługi dużych danych, które wychodzą poza pamięć (na dysk). Prawdopodobnie mógłbyś załadować cały zbiór danych do
bigmemory
obiektu i dokonać całkowitej redukcji w R. Zobacz http://www.bigmemory.org/, aby zapoznać się z zestawem narzędzi do obsługi tego.źródło
bigmemory
w takim przypadku łatwiej będzie Ci najpierw spróbować.Tak. Funkcja readChar () odczyta blok znaków bez zakładania, że są zakończone znakiem null. Jeśli chcesz czytać dane w jednym wierszu, możesz użyć funkcji readLines () . Jeśli czytasz blok lub linię, wykonaj operację, a następnie wypisz dane, możesz uniknąć problemu z pamięcią. Chociaż jeśli masz ochotę odpalić dużą instancję pamięci na EC2 Amazona, możesz uzyskać do 64 GB pamięci RAM. To powinno pomieścić plik i dużo miejsca na manipulowanie danymi.
Jeśli potrzebujesz większej prędkości, zalecenie Shane'a, aby użyć Map Reduce, jest bardzo dobre. Jeśli jednak zdecydujesz się na użycie dużej instancji pamięci na EC2, powinieneś przyjrzeć się pakietowi wielordzeniowemu, który używa wszystkich rdzeni na komputerze.
Jeśli chcesz wczytać wiele gigabajtów rozdzielonych danych do R, powinieneś przynajmniej zbadać pakiet sqldf, który pozwala na import bezpośrednio do sqldf z R, a następnie operowanie na danych z poziomu R. Odkryłem, że sqldf to jeden najszybszych sposobów importowania gigantycznych danych do R, jak wspomniano w poprzednim pytaniu .
źródło
Jest zupełnie nowy pakiet o nazwie colbycol, który pozwala odczytywać tylko wybrane zmienne z ogromnych plików tekstowych:
http://colbycol.r-forge.r-project.org/
Przekazuje wszystkie argumenty do read.table, więc kombinacja powinna pozwolić ci dość ciasne podzbiór.
źródło
ff
Pakiet jest przejrzysty sposób na radzenie sobie z dużych plików.Możesz zobaczyć stronę internetową pakietu i / lub prezentację na jej temat.
mam nadzieję, że to pomoże
źródło
Możesz zaimportować dane do bazy danych SQLite, a następnie użyć RSQLite do wybrania podzbiorów.
źródło
A co z używaniem
readr
iread_*_chunked
rodziną?Więc w twoim przypadku:
testfile.csv
County; State; Year; Quarter; Segment; Sub-Segment; Sub-Sub-Segment; GDP Ada County;NC;2009;4;FIRE;Financial;Banks;80.1 Ada County;NC;2010;1;FIRE;Financial;Banks;82.5 lol Ada County;NC;2013;1;FIRE;Financial;Banks;82.5
Rzeczywisty kod
require(readr) f <- function(x, pos) subset(x, Year %in% c(2009, 2010)) read_csv2_chunked("testfile.csv", DataFrameCallback$new(f), chunk_size = 1)
Dotyczy
f
to każdego fragmentu, pamiętając nazwy kolumn i łącząc na końcu przefiltrowane wyniki. Zobacz,?callback
co jest źródłem tego przykładu.To skutkuje:
# A tibble: 2 × 8 County State Year Quarter Segment `Sub-Segment` `Sub-Sub-Segment` GDP * <chr> <chr> <int> <int> <chr> <chr> <chr> <dbl> 1 Ada County NC 2009 4 FIRE Financial Banks 801 2 Ada County NC 2010 1 FIRE Financial Banks 825
Możesz nawet zwiększyć,
chunk_size
ale w tym przykładzie są tylko 4 linie.źródło
Czy rozważałeś wielką pamięć ? Sprawdź to i to .
źródło
Być może możesz przejść na MySQL lub PostgreSQL, aby uchronić się przed ograniczeniami MS Access.
Dość łatwo jest podłączyć R do tych systemów za pomocą złącza bazy danych opartego na DBI (dostępne w CRAN).
źródło
scan () ma zarówno argument nlines, jak i argument pomijania. Czy jest jakiś powód, dla którego możesz po prostu użyć tego do czytania fragmentów wierszy na raz, sprawdzając datę, aby zobaczyć, czy jest odpowiednia? Jeśli plik wejściowy jest uporządkowany według daty, możesz zapisać indeks, który mówi ci, jakie powinno być pominięcie i liczba linii, co przyspieszy proces w przyszłości.
źródło
Obecnie 3,5 GB po prostu nie jest tak duże, mogę uzyskać dostęp do maszyny z 244 GB pamięci RAM (r3,8xlarge) w chmurze Amazon za 2,80 USD / godzinę. Ile godzin zajmie Ci wymyślenie, jak rozwiązać problem za pomocą rozwiązań typu big data? Ile wart jest Twój czas? Tak, zajmie ci to godzinę lub dwie, zanim dowiesz się, jak korzystać z AWS - ale możesz nauczyć się podstaw na bezpłatnym poziomie, przesłać dane i przeczytać pierwsze 10 tys. Wierszy do R, aby sprawdzić, czy zadziałało, a następnie możesz uruchomić duża instancja pamięci, taka jak r3.8xlarge i czytaj to wszystko! Tylko mój 2c.
źródło
Teraz, 2017, sugerowałbym pójść na spark i sparkR.
składnię można zapisać w prosty, raczej podobny do dplyr sposób
całkiem dobrze pasuje do małej pamięci (małej jak na rok 2017)
Jednak rozpoczęcie może być przerażającym doświadczeniem ...
źródło
Poszedłbym po DB, a następnie zadałbym kilka zapytań, aby wyodrębnić potrzebne próbki przez DBI
Unikaj importowania pliku csv o rozmiarze 3,5 GB do SQLite. Lub przynajmniej dwukrotnie sprawdź, czy twoja OGROMNA baza danych mieści się w limitach SQLite, http://www.sqlite.org/limits.html
Masz cholernie duży DB. Wybrałbym MySQL, jeśli potrzebujesz szybkości. Ale przygotuj się na czekanie wiele godzin na zakończenie importu. Chyba że masz jakiś niekonwencjonalny sprzęt lub piszesz z przyszłości ...
Amazon EC2 może być dobrym rozwiązaniem również do tworzenia instancji serwera z R i MySQL.
warte moje dwa skromne grosze.
źródło