2012-03-23 8 views
8

Mam 15 milionów plików CSV, każdy z dwiema kolumnami (liczbą całkowitą i zmiennoprzecinkową) oraz od 5 do 500 wierszy. Każdy plik wyglądał:Najszybszym sposobem na import milionów plików w R?

3453,0.034 
31,0.031 
567,0.456 
... 

Obecnie jestem iteracji po wszystkich plików, a przy użyciu read.csv() importować każdy plik do wielkiej listy. Oto uproszczona wersja:

allFileNames = Sys.glob(sprintf("%s/*/*/results/*/*", dir)) 

s$scores = list() 

for (i in 1:length(allFileNames)){ 
     if ((i %% 1000) == 0){ 
      cat(sprintf("%d of %d\n", i, length(allFileNames))) 
     } 

     fileName = allFileNames[i] 
     approachID = getApproachID(fileName) 
     bugID = getBugID(fileName) 

     size = file.info(fileName)$size 
     if (!is.na(size) && size > 0){ # make sure file exists and is not empty 
      tmp = read.csv(fileName, header=F, colClasses=c("integer", "numeric")) 
      colnames(tmp) = c("fileCode", "score") 
      s$scores[[approachID]][[bugID]] = tmp 
     } else { 
      # File does not exist, or is empty. 
      s$scores[[approachID]][[bugID]] = matrix(-1, ncol=2, nrow=1) 
     } 
    } 

tmp = read.csv(fileName, header=F, colClasses=c("integer", "numeric") 

Później w moim kodu, wracam za każdym matrycy na liście, i obliczyć pewne dane.

Po rozpoczęciu tego procesu importowania wygląda na to, że jego realizacja potrwa od 3 do 5 dni. Czy jest to szybszy sposób?

EDYCJA: Dodałem więcej szczegółów na temat mojego kodu.

+1

możliwe duplikat [szybko przeczytaniu bardzo dużych tabel jak dataframes w R] (http://stackoverflow.com/questions/1727772/quickly-reading-very-large-tables-as-dataframes-in-r) – joran

+1

Co próbujesz zrobić? Zbudować pojedynczą macierz ze wszystkimi danymi, albo odczytać i przetwarzać każdą matrycę osobno? –

+0

Ma to znaczenie przy ładowaniu wielu plików naraz: http://stackoverflow.com/questions/3764292/ – Ben

Odpowiedz

6

Korzystanie scan (jako stan Joshua w komentarzu) mogłoby być szybsze (3-4 razy):

scan(fileName, what=list(0L,0.0), sep=",", dec=".", quiet=TRUE) 

Główną różnicą jest to, że lista scan powraca z dwóch elementów i read.csv zwrotów data.frame.

+0

Miałem na myśli coś takiego: 'List [[1]] <- matrix (scan (fileName, what = 0, sep =", "), ncol = 2, byrow = TRUE)'. –

+1

Dzięki chłopaki. Jak wspomniałem w innym komentarzu, przełączając się na '' tmp <- matrix (scan (fileName, what = 0, sep = ",", quiet = T), ncol = 2, byrow = TRUE) '', mój kod jest działa około dwa razy szybciej. Po wykonaniu 'system.time()' 'wydaje się, że większość wymaganego czasu jest w IO, więc myślę, że będę musiał trochę poczekać. – stepthom

7

nie jestem jasne, na swój cel, ale jeśli starasz się czytać tych wszystkich plików w jednej strukturze danych R, to widzę dwa główne problemy z wydajnością: czasy dostępu

  1. File - od momentu zażądania read.csv na maszynie rozpoczyna się niezliczona liczba złożonych procesów, polegająca na sprawdzeniu, czy plik istnieje, znalezieniu lokalizacji tego pliku w pamięci lub na dysku (i w razie potrzeby odczytaniu danych do pamięci), a następnie interpretując dane w R. Spodziewam się, że będzie to prawie stałe spowolnienie, gdy czytasz w milionach plików.
  2. Rozwijanie struktury pojedynczych danych przy każdym odczytaniu nowego pliku. Za każdym razem, gdy chcesz dodać kilka wierszy do macierzy, prawdopodobnie będziesz musiał ponownie rozdzielić fragment wielkości o podobnej wielkości, aby zapisać większą macierz. Jeśli powiększasz swoją tablicę 15 milionów razy, na pewno zauważysz spowolnienie wydajności. Z tym problemem wydajność będzie się stopniowo pogarszać w miarę, jak będziesz czytał więcej plików.

Wykonaj szybkie profilowanie i zobacz, jak długo trwa czytanie. Jeśli stopniowo zwalniają, gdy czytasz więcej plików, skupmy się na problemie nr 2. Jeśli jest ciągle wolny, to martw się o problem nr 1.

dotyczące zagadnień, powiedziałbym, można zacząć od dwóch rzeczy:

  1. Połącz pliki CSV w innym języku programowania. Prosty skrypt powłoki prawdopodobnie wykonałby tę pracę, gdybyś tylko przeglądał pliki i łączył je w jeden duży plik. Jak wspomnieli Joshua i Richie poniżej, możesz być w stanie zoptymalizować to bez konieczności odchylania się do innego języka, używając bardziej wydajnych funkcji scan() lub readlines().
  2. Wstępnie zmień ujednoliconą strukturę danych. Jeśli na przykład korzystasz z macierzy, ustaw liczbę wierszy na ~ 15 milionów x 100. Zapewni to tylko jedno miejsce w pamięci dla tego obiektu, a pozostałe operacje po prostu wstawią dane do macierzy wstępnie określonej wielkości.

Dodaj więcej szczegółów na temat swojego kodu (jak wygląda lista?), A być może będziemy mogli być bardziej pomocni.

+3

Należy również zauważyć, że "skanowanie" jest bardziej odpowiednie niż "read.csv", ponieważ wszystkie dane mogą być przechowywane jako numeryczne. –

+0

A może nawet "readLines' +' writeLines', jeśli OP po prostu chce połączyć pliki w jeden. –

+0

@Jeff - Dzięki za tę szczegółową odpowiedź. Nie sądzę, żebym mógł połączyć wszystkie pliki w jeden duży, ponieważ potrzebuję ich rozdzielić do dalszej analizy. (Każdy plik reprezentuje wykonanie mojego eksperymentu.) Co do wstępnego przydzielania mojej bazy danych, czy jest sposób na uprzednią alokację rozmiaru mojej listy ('' s $ score'')? BTW- Nie widzę, żeby spowolnienie stawało się coraz gorsze, więc myślę, że wydajność jest zdominowana przez dysk IO. – stepthom

0

Jak wspomniał Jeff, jest kilka rzeczy, które mogą zająć dużo czasu. Problemem może być dostęp do plików lub czytanie w plikach lub brak pamięci, gdy masz 15 milionów ramek danych w pamięci RAM.Aby zlikwidować problem, zranienie może się różnić w zależności od specyfikacji urządzenia (np. Powolny dysk twardy spowolni czytanie w plikach, brak pamięci RAM będzie problemem z wysoką liczbą plików). Aby rozwiązać problem, musisz wykonać pewne profilowanie.

Trry czyta tylko około 10000 plików i zaczynając od system.time lub, bardziej ostrożnie, używając rbenchmark, aby zobaczyć, co zajmuje najwięcej czasu.

Następnie spojrzeć na Jøran w linku

Quickly reading very large tables as dataframes in R

i sprawdzić, czy któryś z techniką nie pomaga.

2

Co z tym ogólnym przepływem pracy? Jednak nie testowane.

my.list.of.files <- list.files(pattern = ".txt") # char vector of filenames 
my.data <- sapply(my.list.of.files, FUN = function(x) { 
      # read file using scan, craft the output to two columns 
     }) # result is merged 

#or if you use simplify= FALSE 
my.data <- sapply(my.list.of.files, FUN = function(x) { 
      # read file using scan (or some other method), craft the output to two columns 
     }, simplify = FALSE) #you get a list 
my.data <- do.call("rbind", my.data) 
+0

Wiem, że to tylko szablon, ale zauważ, że gdybyś miał wszystkie 15 milionów plików w jednym katalogu, to może być również inna przyczyna twoich problemów wydajnościowych. –

+1

Zauważ, że 'sapply' jest nieco powolny, ponieważ R musi wykonać dodatkową pracę, zastanawiając się jak uprościć wyjście. Z rodziny '* apply',' lapply' jest najszybsza, stąd może bardziej odpowiednie tutaj. – flodel

+0

@Jeff, to nie jest coś, co możemy wyjaśnić. @flodel, nawet jeśli podasz 'upraszczać = FALSE'? –

Powiązane problemy