Szybki odczyt bardzo dużych tabel jako ramek danych


502

Mam bardzo duże tabele (30 milionów wierszy), które chciałbym załadować, ponieważ ramki danych w R. read.table()mają wiele wygodnych funkcji, ale wygląda na to, że w implementacji jest dużo logiki, która spowolniłaby wszystko. W moim przypadku zakładam, że znam typy kolumn z wyprzedzeniem, tabela nie zawiera żadnych nagłówków kolumn ani nazw wierszy i nie ma żadnych znaków patologicznych, o które muszę się martwić.

Wiem, że czytanie w tabeli przy użyciu listy scan()może być dość szybkie, np .:

datalist <- scan('myfile',sep='\t',list(url='',popularity=0,mintime=0,maxtime=0)))

Ale niektóre z moich prób przekształcenia tego w ramkę danych wydają się zmniejszać wydajność powyższego współczynnika 6:

df <- as.data.frame(scan('myfile',sep='\t',list(url='',popularity=0,mintime=0,maxtime=0))))

Czy jest na to lepszy sposób? A może całkiem inne podejście do problemu?

Odpowiedzi:


425

Aktualizacja, kilka lat później

Ta odpowiedź jest stara i R ruszył dalej. Ulepszenie, read.tableaby uruchomić trochę szybciej, ma cenną niewielką zaletę. Twoje opcje to:

  1. Używanie vroomz pakietu tidyverse vroomdo importowania danych z plików rozdzielanych znakami csv / tab bezpośrednio do tibble R.

  2. Używanie freadw data.tablecelu importowania danych z plików rozdzielanych csv / tabulatorami bezpośrednio do R. Zobacz odpowiedź mnel .

  3. Korzystanie read_tablez readr(w CRAN od kwietnia 2015 r.). To działa podobnie jak freadpowyżej. Plik Readme w linku wyjaśnia różnicę między dwiema funkcjami ( readrobecnie twierdzi, że jest „1,5-2x wolniejszy” data.table::fread).

  4. read.csv.rawfrom iotoolszapewnia trzecią opcję szybkiego odczytu plików CSV.

  5. Próbuje przechowywać jak najwięcej danych w bazach danych, a nie w płaskich plikach. (Oprócz tego, że jest lepszym trwałym nośnikiem pamięci, dane są przekazywane do iz R w formacie binarnym, co jest szybsze.) read.csv.sqlW sqldfpakiecie, jak opisano w odpowiedzi JD Long , importuje dane do tymczasowej bazy danych SQLite, a następnie odczytuje je do R. Zobacz także: RODBCpakiet, a odwrotna strona zależy od sekcji strony DBIpakietu . MonetDB.Rdaje typ danych, który udaje ramkę danych, ale pod spodem jest MonetDB, co zwiększa wydajność. Importuj dane ze swoją monetdb.read.csvfunkcją. dplyrpozwala pracować bezpośrednio z danymi przechowywanymi w kilku typach baz danych.

  6. Przechowywanie danych w formatach binarnych może być również przydatne w celu poprawy wydajności. Użyj saveRDS/ readRDS(patrz poniżej), h5lub rhdf5pakietów dla formatu HDF5 lub write_fst/ read_fstz fstpakietu.


Oryginalna odpowiedź

Jest kilka prostych rzeczy do wypróbowania, niezależnie od tego, czy korzystasz z read.table, czy skanujesz.

  1. Set nrows= liczba rekordów w twoich danych ( nmaxw scan).

  2. Upewnij się, że comment.char=""chcesz wyłączyć interpretację komentarzy.

  3. Jawnie zdefiniuj klasy każdej kolumny, używając colClassesin read.table.

  4. Ustawienie multi.line=FALSEmoże również poprawić wydajność skanowania.

Jeśli żadna z tych rzeczy nie działa, użyj jednego z pakietów profilujących, aby ustalić, które linie spowalniają działanie. Być może możesz napisać zmniejszoną wersję read.tableopartą na wynikach.

Inną alternatywą jest filtrowanie danych przed odczytaniem ich w R.

Lub, jeśli problem polega na tym, że musisz go regularnie czytać, użyj tych metod, aby odczytać dane za jednym razem, a następnie zapisz ramkę danych jako binarny obiekt blob z save saveRDS, a następnym razem będziesz mógł go szybciej odzyskać load readRDS.


4
Dzięki za porady Richie. Zrobiłem trochę testów i wydaje się, że wzrost wydajności przy użyciu opcji nrow i colClasses dla read.table jest dość skromny. Na przykład odczytanie tabeli wierszy ~ 7M zajmuje 78 sekund bez opcji i 67 sekund z opcjami. (uwaga: tabela ma 1 kolumnę znaków, 4 kolumny liczb całkowitych, i czytam za pomocą comment.char = '' i stringsAsFactors = FALSE). Używanie save () i load (), gdy jest to możliwe, jest świetną wskazówką - po zapisaniu z save () ta sama tabela zajmuje tylko 12 sekund.
eytan

2
Pakiet „pióro” ma nowy format binarny, który ładnie się gra z ramkami danych pand Pythona
rsoren

4
Myślę, że może musisz ponownie zaktualizować swój post w odniesieniu do pakietu feather. Do odczytu danych featherjest znacznie szybszy niż fread. Na przykład w właśnie załadowanym zestawie danych 4 GB read_featherbyło około 4,5 razy szybsze niż fread. Zapisywanie danych fwritejest jeszcze szybsze. blog.dominodatalab.com/the-r-data-io-shootout
Z boson Z

2
Ale rozmiary plików są znacznie większe dla piór niż w RDS. Nie sądzę, że obsługuje kompresję. Plik RDS ma 216 MB, a plik wtapiania ma 4 GB. featherJest więc szybszy do czytania, ale zajmuje dużo więcej miejsca do przechowywania.
Z bozonem

@Zboson Jeśli chcesz przechowywać ramkę danych w pliku, do którego można uzyskać dostęp zarówno z R, jak i Pythona, featherto dobra opcja. Jeśli zależy ci tylko na możliwości odczytu danych w języku R, rdslepiej jest.
Richie Cotton,

279

Oto przykład, który korzysta freadz data.table1.8.7

Przykłady pochodzą ze strony pomocy do fread, wraz z czasami na moim Windows XP Core 2 duet E8400.

library(data.table)
# Demo speedup
n=1e6
DT = data.table( a=sample(1:1000,n,replace=TRUE),
                 b=sample(1:1000,n,replace=TRUE),
                 c=rnorm(n),
                 d=sample(c("foo","bar","baz","qux","quux"),n,replace=TRUE),
                 e=rnorm(n),
                 f=sample(1:1000,n,replace=TRUE) )
DT[2,b:=NA_integer_]
DT[4,c:=NA_real_]
DT[3,d:=NA_character_]
DT[5,d:=""]
DT[2,e:=+Inf]
DT[3,e:=-Inf]

standardowy stół do odczytu

write.table(DT,"test.csv",sep=",",row.names=FALSE,quote=FALSE)
cat("File size (MB):",round(file.info("test.csv")$size/1024^2),"\n")    
## File size (MB): 51 

system.time(DF1 <- read.csv("test.csv",stringsAsFactors=FALSE))        
##    user  system elapsed 
##   24.71    0.15   25.42
# second run will be faster
system.time(DF1 <- read.csv("test.csv",stringsAsFactors=FALSE))        
##    user  system elapsed 
##   17.85    0.07   17.98

zoptymalizowany stół do odczytu

system.time(DF2 <- read.table("test.csv",header=TRUE,sep=",",quote="",  
                          stringsAsFactors=FALSE,comment.char="",nrows=n,                   
                          colClasses=c("integer","integer","numeric",                        
                                       "character","numeric","integer")))


##    user  system elapsed 
##   10.20    0.03   10.32

fread

require(data.table)
system.time(DT <- fread("test.csv"))                                  
 ##    user  system elapsed 
##    3.12    0.01    3.22

sqldf

require(sqldf)

system.time(SQLDF <- read.csv.sql("test.csv",dbname=NULL))             

##    user  system elapsed 
##   12.49    0.09   12.69

# sqldf as on SO

f <- file("test.csv")
system.time(SQLf <- sqldf("select * from f", dbname = tempfile(), file.format = list(header = T, row.names = F)))

##    user  system elapsed 
##   10.21    0.47   10.73

ff / ffdf

 require(ff)

 system.time(FFDF <- read.csv.ffdf(file="test.csv",nrows=n))   
 ##    user  system elapsed 
 ##   10.85    0.10   10.99

W podsumowaniu:

##    user  system elapsed  Method
##   24.71    0.15   25.42  read.csv (first time)
##   17.85    0.07   17.98  read.csv (second time)
##   10.20    0.03   10.32  Optimized read.table
##    3.12    0.01    3.22  fread
##   12.49    0.09   12.69  sqldf
##   10.21    0.47   10.73  sqldf on SO
##   10.85    0.10   10.99  ffdf

43
Świetna odpowiedź, a testy porównawcze dotyczą innych kontekstów. Wystarczy przeczytać plik 4 GB w niecałą minutę z fread. Próbowałem go odczytać za pomocą podstawowych funkcji R. Zajęło to około 15 godzin.
Ari B. Friedman

1
mój test porównawczy sugeruje jeszcze większe korzyści prędkości dla read.csv w data.table. zauważ, że data.table nie jest standardowym R, ale (niestety) „po prostu” ładnie udostępnionym przez jego twórców w CRAN. nie jest nawet uważane za wystarczająco standardowe, aby wspólna lista pakietów R, a tym bardziej kwalifikować się jako zamiennik ramek danych. ma wiele zalet, ale ma także bardzo sprzeczne z intuicją aspekty. możesz użyć as.data.frame (fread.csv („test.csv”)) z pakietem, aby wrócić do standardowego świata ramek danych R.
ivo Welch,

3
@mnel. Czy możesz ponownie uruchomić test porównawczy i dołączyć readr?
jangorecki

2
Drugi @jangorecki. Ponadto, biorąc pod uwagę, że freadma teraz prawdziwych konkurentów, może być przydatne dodanie punktów odniesienia dla zoptymalizowanego freadużycia - określanie colClassesitp.
MichaelChirico

1
@jangorecji @ MichaelChirico podany kod jest w pełni odtwarzalny, więc można go łatwo symulować readr ... ponowne uruchomienie kodu, na moim komputerze czas upłynął dwa razy szybciej, jeśli nie więcej, dla większości wyników, mimo że działam przez sieć (i dobrze zaktualizowane wersje, ponieważ jest już jakiś czas) ... a przy czytniku mam 7 sekund, ale także poniżej sekundy, gdy uruchamiam drugi raz (0,66 s), podejrzewam, że w sieci jest trochę buforowania lub szyjki butelki. fread najszybszego pokazanego tutaj rozwiązania jest o 2 s po mojej stronie dla porównania (pierwszy raz o 8,69 s) z jakiegoś powodu wolniej)
R. Prost

249

Początkowo nie widziałem tego pytania i kilka dni później zadałem podobne pytanie. Mam zamiar usunąć moje poprzednie pytanie, ale pomyślałem, że dodam tutaj odpowiedź, aby wyjaśnić, jak to wykorzystałemsqldf() .

Trwa dyskusja na temat najlepszego sposobu zaimportowania 2 GB lub więcej danych tekstowych do ramki danych R. Wczoraj napisałem wpis na blogu o sqldf()zaimportowaniu danych do SQLite jako obszaru przejściowego, a następnie wyssaniu go z SQLite do R. To działa bardzo dobrze dla mnie. Udało mi się pobrać 2 GB danych (3 kolumny, rzędy 40 mm) w <5 minut. Natomiastread.csv polecenie działało całą noc i nigdy się nie zakończyło.

Oto mój kod testowy:

Skonfiguruj dane testowe:

bigdf <- data.frame(dim=sample(letters, replace=T, 4e7), fact1=rnorm(4e7), fact2=rnorm(4e7, 20, 50))
write.csv(bigdf, 'bigdf.csv', quote = F)

Zrestartowałem R przed uruchomieniem następującej procedury importowania:

library(sqldf)
f <- file("bigdf.csv")
system.time(bigdf <- sqldf("select * from f", dbname = tempfile(), file.format = list(header = T, row.names = F)))

Pozwoliłem, aby następująca linia działała całą noc, ale nigdy się nie zakończyła:

system.time(big.df <- read.csv('bigdf.csv'))

1
Cześć. W jaki sposób użyjesz go jako danych wejściowych dla innych pakietów, takich jak zoo, zaprojektowanych do jednoczesnego korzystania ze wszystkich danych?
skan

@skan obiektem końcowym jest ramka danych. Musisz więc przekonwertować go na obiekt zoo, aby móc go używać z zoo. Zobacz przykłady w dokumentach zoo.
JD Long

@JD Long. Cześć, problem polega na tym, że po przekonwertowaniu go na obiekt zoo próbuje dopasować go do pamięci. Jeśli jest za duży, powoduje błąd. A jeśli wynik obiektu zoo (na przykład agregacja dwóch serii) jest również zbyt, musiałby to być również obiekt sql lub ff.
skan

Nie wiem, co jest nie tak z sqldf. Utworzyłem prosty plik 1 GB na dysku (z 2 kolumnami numerycznymi) i użyłem DTSQL <- read.csv.sql („f2.txt”, dbname = tempfile ()) i próbuje załadować całe dane do pamięci. Jutro zamiast tego spróbuję ff i rewoskalera.
skan

1
@ co m jest tysiącem, więc mm to tysiąc tysięcy lub milion. Prawdopodobnie powinienem napisać wielką literą jako MM. Uważam jednak, że każdy milion skrótów może być dla kogoś mylący, jeśli masz wystarczająco zróżnicowaną grupę odbiorców. Przepraszam, że starałem się być zbyt gadatliwy! Accountcoach.com/blog/what-does-m-and-mm-stand-for
JD Long

73

O dziwo, nikt przez lata nie udzielał odpowiedzi na dolną część pytania, mimo że jest to ważna - data.framesą to po prostu listy z odpowiednimi atrybutami, więc jeśli masz duże dane, których nie chcesz używać as.data.framelub podobne do listy. Znacznie szybciej jest po prostu „przekształcić” listę w ramkę danych w miejscu:

attr(df, "row.names") <- .set_row_names(length(df[[1]]))
class(df) <- "data.frame"

Nie powoduje to kopiowania danych, więc jest natychmiastowe (w przeciwieństwie do wszystkich innych metod). Zakłada się, że odpowiednio ustawiłeś już names()na liście.

[Jeśli chodzi o ładowanie dużych danych do R - osobiście, zrzucam je kolumnami do plików binarnych i używam readBin()- jest to zdecydowanie najszybsza metoda (inna niż mapowanie) i jest ograniczona tylko prędkością dysku. Analiza plików ASCII jest z natury powolna (nawet w C) w porównaniu do danych binarnych.]


6
Korzystanie tracmemsugeruje attr<-i class<-rób kopie wewnętrznie. bit::setattralbo data.table::setattrnie będzie.
mnel

6
Może użyłeś niewłaściwej kolejności? Nie ma kopii, jeśli używasz df=scan(...); names(df)=...; attr...; class...- patrz tracemem()(testowane w R 2.15.2)
Simon Urbanek

3
Czy możesz wyjaśnić, w jaki sposób zrzucasz duże dane według kolumn do plików binarnych?
dabsingh

32

To było wcześniej zadawane w R-Help , więc warto to sprawdzić.

Jedną z sugestii było użycie, readChar()a następnie manipulowanie ciągiem wyników za pomocą strsplit()i substr(). Widać, że logika związana z readChar jest znacznie mniejsza niż read.table.

Nie wiem, czy pamięć jest tutaj problemem, ale możesz również rzucić okiem na pakiet HadoopStreaming . Ten wykorzystuje Hadoop , który stanowi ramy MapReduce przeznaczone do czynienia z dużymi zbiorami danych. W tym celu użyłbyś funkcji hsTableReader. To jest przykład (ale ma krzywą uczenia się do nauki Hadoop):

str <- "key1\t3.9\nkey1\t8.9\nkey1\t1.2\nkey1\t3.9\nkey1\t8.9\nkey1\t1.2\nkey2\t9.9\nkey2\"
cat(str)
cols = list(key='',val=0)
con <- textConnection(str, open = "r")
hsTableReader(con,cols,chunkSize=6,FUN=print,ignoreKey=TRUE)
close(con)

Podstawową ideą jest podzielenie importu danych na części. Możesz nawet posunąć się do tego, aby użyć jednej z równoległych struktur (np. Śniegu) i równolegle uruchomić import danych, dzieląc plik, ale najprawdopodobniej w przypadku dużych zestawów danych, które nie pomogą, ponieważ napotkasz ograniczenia pamięci, dlatego redukcja mapy jest lepszym podejściem.


Właśnie zrobiłem szybki test i readChar wydaje się być znacznie szybszy niż nawet readLines z jakiegoś niewytłumaczalnego powodu. Jednak nadal jest powolny jak grzech w porównaniu do prostego testu C. Przy prostym zadaniu odczytu 100 megabajtów R jest około 5-10 razy wolniejszy niż C
Jonathan Chang

1
Nie rozumiem o co ci chodzi. Celem Hadoop jest obsługa bardzo dużych danych, o to właśnie chodziło.
Shane

1
Mimo nazwy, hsTableReader nie ma nic wspólnego z Hadoop, lecz do przetwarzania dużych danych w kawałkach. Odczytuje z con, fragment wierszy na raz, i przekazuje każdy fragment jako data.frame do FUN w celu przetworzenia. Przy ignoreKey = FALSE dokonuje dodatkowego grupowania według klucza (wpis w pierwszej kolumnie), co jest istotne dla podejść Mapuj / Zmniejsz.
DavidR

Cześć. Jak wykorzystałbyś te dane Hadoop jako dane wejściowe dla innych pakietów, takich jak zoo, zaprojektowanych do jednoczesnego używania ze wszystkimi danymi?
skan

10

Alternatywą jest użycie vroompakietu. Teraz w CRAN. vroomnie ładuje całego pliku, indeksuje lokalizację każdego rekordu i jest czytany później, gdy go użyjesz.

Płać tylko za to, czego używasz.

Zobacz Wprowadzenie do vroom , Rozpocznij z vroom i testy porównawcze vroom .

Podstawowy przegląd jest taki, że początkowy odczyt dużego pliku będzie znacznie szybszy, a kolejne modyfikacje danych mogą być nieco wolniejsze. W zależności od tego, jakie jest twoje zastosowanie, może to być najlepsza opcja.

Zobacz uproszczony przykład z testów porównawczych vroom poniżej, najważniejsze elementy to super szybki czas odczytu, ale operacje nieco rozsiewające, takie jak agregacja itp.

package                 read    print   sample   filter  aggregate   total
read.delim              1m      21.5s   1ms      315ms   764ms       1m 22.6s
readr                   33.1s   90ms    2ms      202ms   825ms       34.2s
data.table              15.7s   13ms    1ms      129ms   394ms       16.3s
vroom (altrep) dplyr    1.7s    89ms    1.7s     1.3s    1.9s        6.7s

5

Drobne dodatkowe punkty, o których warto wspomnieć. Jeśli masz bardzo duży plik, możesz w locie obliczyć liczbę wierszy (jeśli nie ma nagłówka), używając (gdzie bedGraphjest nazwa pliku w katalogu roboczym):

>numRow=as.integer(system(paste("wc -l", bedGraph, "| sed 's/[^0-9.]*\\([0-9.]*\\).*/\\1/'"), intern=T))

Następnie można użyć, że albo w read.csv, read.table...

>system.time((BG=read.table(bedGraph, nrows=numRow, col.names=c('chr', 'start', 'end', 'score'),colClasses=c('character', rep('integer',3)))))
   user  system elapsed 
 25.877   0.887  26.752 
>object.size(BG)
203949432 bytes

4

Często myślę, że dobrą praktyką jest przechowywanie większych baz danych w bazie danych (np. Postgres). Nie używam niczego większego niż (nrow * ncol) ncell = 10M, co jest dość małe; ale często stwierdzam, że chcę, aby R tworzył i przechowywał wykresy wymagające dużej ilości pamięci tylko podczas zapytania z wielu baz danych. W przyszłości laptopy o pojemności 32 GB znikną niektóre z tych problemów z pamięcią. Ale urok użycia bazy danych do przechowywania danych, a następnie użycia pamięci R do wynikowych wyników zapytań i wykresów nadal może być przydatny. Niektóre zalety to:

(1) Dane pozostają ładowane do bazy danych. Po prostu ponownie pgadmin łączy się z bazami danych, które chcesz po ponownym włączeniu laptopa.

(2) Prawdą jest, że R może wykonać znacznie więcej sprytnych operacji statystycznych i graficznych niż SQL. Ale myślę, że SQL jest lepiej zaprojektowany do wyszukiwania dużych ilości danych niż R.

# Looking at Voter/Registrant Age by Decade

library(RPostgreSQL);library(lattice)

con <- dbConnect(PostgreSQL(), user= "postgres", password="password",
                 port="2345", host="localhost", dbname="WC2014_08_01_2014")

Decade_BD_1980_42 <- dbGetQuery(con,"Select PrecinctID,Count(PrecinctID),extract(DECADE from Birthdate) from voterdb where extract(DECADE from Birthdate)::numeric > 198 and PrecinctID in (Select * from LD42) Group By PrecinctID,date_part Order by Count DESC;")

Decade_RD_1980_42 <- dbGetQuery(con,"Select PrecinctID,Count(PrecinctID),extract(DECADE from RegistrationDate) from voterdb where extract(DECADE from RegistrationDate)::numeric > 198 and PrecinctID in (Select * from LD42) Group By PrecinctID,date_part Order by Count DESC;")

with(Decade_BD_1980_42,(barchart(~count | as.factor(precinctid))));
mtext("42LD Birthdays later than 1980 by Precinct",side=1,line=0)

with(Decade_RD_1980_42,(barchart(~count | as.factor(precinctid))));
mtext("42LD Registration Dates later than 1980 by Precinct",side=1,line=0)

3

Bardzo szybko czytam dane, używając nowego arrow pakietu. Wydaje się, że jest na dość wczesnym etapie.

W szczególności używam parkietowego formatu kolumnowego. To konwertuje z powrotem nadata.frame R, ale możesz uzyskać jeszcze głębsze przyspieszenia, jeśli tego nie zrobisz. Ten format jest wygodny, ponieważ można go również używać z języka Python.

Mój główny przypadek użycia tego jest na dość ograniczonym serwerze RShiny. Z tych powodów wolę trzymać dane dołączone do aplikacji (tj. Poza SQL), a zatem wymagają małego rozmiaru pliku i szybkości.

Ten powiązany artykuł zawiera analizę porównawczą i dobry przegląd. Poniżej zacytowałem kilka interesujących punktów.

https://ursalabs.org/blog/2019-10-columnar-perf/

Rozmiar pliku

Oznacza to, że plik Parquet jest o połowę mniejszy niż nawet skompresowany plik CSV. Jednym z powodów, dla których plik Parquet jest tak mały, jest kodowanie słownikowe (zwane również „kompresją słownikową”). Kompresja słownikowa może zapewnić znacznie lepszą kompresję niż przy użyciu kompresora bajtów ogólnego przeznaczenia, takiego jak LZ4 lub ZSTD (które są używane w formacie FST). Parkiet został zaprojektowany do produkcji bardzo małych plików, które można szybko odczytać.

Czytaj prędkość

Kiedy kontrolujemy według rodzaju wyjścia (np. Porównując ze sobą wszystkie dane wyjściowe R data.frame), widzimy, że wydajność Parquet, Feather i FST mieści się w granicach stosunkowo niewielkiego marginesu. To samo dotyczy wyników pandas.DataFrame. data.table :: fread jest imponująco konkurencyjny w stosunku do rozmiaru pliku 1,5 GB, ale opóźnia się w stosunku do 2,5 GB CSV.


Niezależny test

Przeprowadziłem niezależne testy porównawcze na symulowanym zbiorze danych obejmującym 1 000 000 wierszy. Zasadniczo przetasowałem kilka rzeczy, aby spróbować zakwestionować kompresję. Dodałem również krótkie pole tekstowe z losowymi słowami i dwoma symulowanymi czynnikami.

Dane

library(dplyr)
library(tibble)
library(OpenRepGrid)

n <- 1000000

set.seed(1234)
some_levels1 <- sapply(1:10, function(x) paste(LETTERS[sample(1:26, size = sample(3:8, 1), replace = TRUE)], collapse = ""))
some_levels2 <- sapply(1:65, function(x) paste(LETTERS[sample(1:26, size = sample(5:16, 1), replace = TRUE)], collapse = ""))


test_data <- mtcars %>%
  rownames_to_column() %>%
  sample_n(n, replace = TRUE) %>%
  mutate_all(~ sample(., length(.))) %>%
  mutate(factor1 = sample(some_levels1, n, replace = TRUE),
         factor2 = sample(some_levels2, n, replace = TRUE),
         text = randomSentences(n, sample(3:8, n, replace = TRUE))
         )

Czytaj i pisz

Zapisywanie danych jest łatwe.

library(arrow)

write_parquet(test_data , "test_data.parquet")

# you can also mess with the compression
write_parquet(test_data, "test_data2.parquet", compress = "gzip", compression_level = 9)

Odczytywanie danych jest również łatwe.

read_parquet("test_data.parquet")

# this option will result in lightning fast reads, but in a different format.
read_parquet("test_data2.parquet", as_data_frame = FALSE)

Przetestowałem czytanie tych danych w stosunku do kilku konkurencyjnych opcji i uzyskałem nieco inne wyniki niż w powyższym artykule, który jest oczekiwany.

analiza porównawcza

Ten plik nie jest tak duży jak artykuł porównawczy, więc może to jest różnica.

Testy

  • rds: test_data.rds (20,3 MB)
  • parquet2_native: (14,9 MB z wyższą kompresją i as_data_frame = FALSE)
  • parquet2: test_data2.parquet (14,9 MB z wyższą kompresją)
  • parkiet: test_data.parquet (40,7 MB)
  • fst2: test_data2.fst (27,9 MB z wyższą kompresją)
  • fst: test_data.fst (76,8 MB)
  • fread2: test_data.csv.gz (23,6 MB)
  • fread: test_data.csv (98,7 MB)
  • pióro_arrow: test_data.feather (157,2 MB czytane z arrow)
  • pióro: test_data.feather (157,2 MB czytane za pomocą feather)

Spostrzeżenia

W przypadku tego konkretnego pliku freadjest on naprawdę bardzo szybki. Podoba mi się mały rozmiar pliku z wysoce skompresowanego parquet2testu. Mogę poświęcić czas na pracę z rodzimym formatem danych, a nie zdata.frame jeśli naprawdę potrzebuję przyspieszenia.

Tutaj fstjest również doskonałym wyborem. Używałbym mocno skompresowanego fstformatu lub wysoce skompresowanego, w parquetzależności od tego, czy potrzebuję kompromisu prędkości lub rozmiaru pliku.


0

Zamiast konwencjonalnej tabeli read.tab czuję, że fread jest szybszą funkcją. Określenie dodatkowych atrybutów, takich jak wybranie tylko wymaganych kolumn, określenie klas i łańcucha, ponieważ czynniki skracają czas importowania pliku.

data_frame <- fread("filename.csv",sep=",",header=FALSE,stringsAsFactors=FALSE,select=c(1,4,5,6,7),colClasses=c("as.numeric","as.character","as.numeric","as.Date","as.Factor"))

0

Próbowałem już wszystkiego i [readr] [1] wykonał najlepszą robotę. Mam tylko 8 GB pamięci RAM

Pętla na 20 plików, każdy 5 GB, 7 kolumn:

read_fwf(arquivos[i],col_types = "ccccccc",fwf_cols(cnpj = c(4,17), nome = c(19,168), cpf = c(169,183), fantasia = c(169,223), sit.cadastral = c(224,225), dt.sitcadastral = c(226,233), cnae = c(376,382)))
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.