Çok büyük tabloları veri çerçeveleri olarak hızlı bir şekilde okuma


503

R.'de bir veri çerçevesi olarak yüklemek istediğim çok büyük tablolar (30 milyon satır) var read.table(), ancak birçok kullanışlı özelliğe sahip, ancak uygulamada işleri yavaşlatan bir sürü mantık var gibi görünüyor. Benim durumumda, önceden sütun türlerini bildiğimi, tabloda herhangi bir sütun başlığı veya satır adı içermediğini ve endişelenmem gereken patolojik karakterlerin olmadığını varsayıyorum.

Bir tablo kullanarak liste olarak okuma scan(), örneğin oldukça hızlı olabileceğini biliyorum:

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

Ancak bunu bir veri çerçevesine dönüştürme girişimlerimin bazıları, yukarıdaki performansı 6 kat azaltıyor gibi görünüyor:

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

Bunu yapmanın daha iyi bir yolu var mı? Veya soruna tamamen farklı bir yaklaşım mı?

Yanıtlar:


425

Birkaç yıl sonra bir güncelleme

Bu cevap eski ve R devam etti. read.tableBiraz daha hızlı koşmak için yapılan ince ayarın değerli küçük bir yararı vardır. Seçenekleriniz:

  1. Csv / sekmeyle ayrılmış dosyalardan doğrudan R vroomtibble'a vroomveri aktarmak için tidyverse paketinden kullanma .

  2. Kullanılması freadhalinde data.tabledoğrudan R. See içine csv / sekme ile sınırlandırılmış dosyalardan veri alma için mnel cevabı .

  3. Kullanılması read_tablehalinde readr(Nisan 2015 den CRAN üzerine). Bu freadyukarıdaki gibi çalışır . Bağlantıdaki benioku , iki işlev arasındaki farkı açıklar ( readrşu anda "1.5-2x daha yavaş" olduğunu iddia etmektedir data.table::fread).

  4. read.csv.rawfrom iotools, CSV dosyalarını hızlı bir şekilde okumak için üçüncü bir seçenek sunar.

  5. Düz dosyalar yerine veritabanlarında olabildiğince fazla veri depolamaya çalışın. (Hem de daha iyi bir kalıcı depolama ortamı olarak, verileri. Daha hızlı olan bir ikili formatta ve Ar geçirilen) read.csv.sqlde sqldfaçıklandığı gibi, paketin JD Long'un cevap geçici SQLite veritabanına, ithalat verilerini ve sonra okur Ayrıca bakınız: RODBCpaket ve tersi DBIpaket sayfasının bölümüne bağlıdır . MonetDB.Rveri çerçevesi gibi davranan, ancak gerçekten altında bir MonetDB olan, performansı artıran bir veri türü sunar. Verileri monetdb.read.csvişleviyle içe aktarın . dplyrçeşitli veritabanı türlerinde saklanan verilerle doğrudan çalışmanıza olanak tanır.

  6. Verilerin ikili biçimlerde depolanması, performansı artırmak için de yararlı olabilir. Kullanım saveRDS/ readRDS(aşağıya bakınız), h5veya rhdf5HDF5 biçimi veya için paketler write_fst/ read_fstdan fstpaketin.


Orijinal cevap

Read.table veya scan komutlarını kullansanız da denemeniz gereken birkaç basit şey vardır.

  1. Set nrows= verilerinizdeki ( nmaxin scan) kayıt sayısı .

  2. comment.char=""Yorumların yorumunu kapattığınızdan emin olun .

  3. Açıkça kullanarak her sütunun sınıfları tanımlar colClassesiçinde read.table.

  4. Ayar multi.line=FALSE, taramadaki performansı da artırabilir.

Bunlardan hiçbiri işe yaramazsa, hangi satırların işleri yavaşlattığını belirlemek için profil oluşturma paketlerinden birini kullanın . Belki de read.tablesonuçlara dayalı bir kesim versiyonu yazabilirsiniz .

Diğer alternatif, verilerinizi R'ye okumadan önce filtrelemektir.

Veya sorun düzenli olarak okumak zorundaysanız, verileri bir kez okumak için bu yöntemleri kullanın, ardından veri çerçevesini bir ikili blob olarak kaydedin. save saveRDS, bir dahaki sefere ile daha hızlı alabilirsiniz load readRDS.


4
İpuçları için teşekkürler Richie. Biraz test yaptım ve okuma için nrow ve colClasses seçeneklerini kullanarak performans kazancı oldukça mütevazı görünüyor. Örneğin, ~ 7M satır tablosunu okumak seçeneksiz 78s ve seçeneklerle 67s alır. (not: tablonun 1 karakter sütunu, 4 tamsayı sütunu vardır ve comment.char = '' ve stringsAsFactors = FALSE kullanarak okudum). Save () ve load () işlevlerini mümkünse kullanmak harika bir ipucu - save () ile birlikte saklandığında, aynı tablonun yüklenmesi sadece 12 saniye sürer.
eytan

2
"Geçiş yumuşatma" paketi, Python'un panda veri çerçeveleriyle iyi oynayan yeni bir ikili biçime sahiptir
rsoren

4
Sanırım paketle ilgili olarak yayınınızı tekrar güncellemeniz gerekebilir feather. Veri okumak featheriçin çok daha hızlı fread. Örneğin az önce yüklediğim bir 4GB veri kümesinden read_featheryaklaşık 4,5 kat daha hızlıydı fread. Veri kaydetmek fwriteiçin hala daha hızlı. blog.dominodatalab.com/the-r-data-io-shootout
Z bozonu

2
Ancak dosya boyutları tüy için RDS'den çok daha büyüktür. Sıkıştırmayı desteklediğini sanmıyorum. RDS dosyası 216 MB ve geçiş yumuşatma dosyası 4GB'dir. Bu yüzden featherokumak için daha hızlıdır, ancak çok daha fazla depolama alanı kullanır.
Z boson

@Zboson Veri çerçevesini hem R hem de Python'dan erişilebilen bir dosyada saklamanız gerekiyorsa, featheriyi bir seçenektir. Yalnızca verilerinizi R dilinde okuyabilmeyi önemsiyorsanız rds, tercih edilir.
Richie Cotton

279

İşte kullanan bir örnek freaddan data.table1.8.7

Örnekler, yardım sayfasından freadWindows XP Core 2 duo E8400'ümdeki zamanlamalarla birlikte geliyor.

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]

standart okuma

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

optimize edilmiş okuma.

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

Özetle:

##    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
Harika bir cevap ve kıyaslama başka bağlamlarda da geçerli. Sadece bir dakikadan kısa bir süre içinde 4GB'lık bir dosyada okuyun fread. Temel R fonksiyonları ile okumayı denemişti ve yaklaşık 15 saat sürdü.
Ari B. Friedman

1
benim ölçütüm data.table içindeki read.csv için daha da yüksek hız avantajları önermektedir. data.table'ın standart R olmadığını, ancak (ne yazık ki) CRAN'daki yaratıcıları tarafından "güzelce" güzelce paylaşıldığını unutmayın. ortak R paket listesini yapmak için yeterince standart kabul edilmez, veri çerçevelerinin yerine daha az yeterlidir. birçok avantajı var, ama aynı zamanda bazı sezgisel yönleri de var. standart R veri çerçevesi dünyasına geri dönmek için paketle birlikte as.data.frame (fread.csv ("test.csv")) kullanmak isteyebilirsiniz.
ivo Welch

3
mnel karşılaştırmalı değerlendirmeyi tekrar çalıştırıp dahil edebilir readrmisiniz?
jangorecki

2
İkinci @jangorecki. Ayrıca, verilen freadbazı gerçek rakipler var, optimize edilmiş freadkullanım için colClasses
belirteçler

1
@jangorecji @ MichaelChirico verilen kod tamamen yeniden üretilebilir, bu yüzden kodu simüle etmek için doğrudan ileri ... benim makinemde geçen zaman çoğu sonuç için daha fazla değilse iki kat daha hızlı olsa da bir ağ üzerinden çalıştırıyorum (ve iyi güncellenmiş sürümleri şimdi olduğu gibi) ... ve readr ile ben 7s ama aynı zamanda ikinci kez (0.66s) çalıştırdığınızda bir saniye altında, ağda bazı önbellekleme veya bazı şişe boyun olduğundan şüpheleniyorum. Burada gösterilen en hızlı çözüm için fread karşılaştırmak için yanımda 2s (bazı nedenlerden dolayı ilk kez 8.69s'de çalışan)
R. Prost

249

Başlangıçta bu soruyu görmedim ve birkaç gün sonra benzer bir soru sordum. Önceki sorumu aşağıya çekeceğim, ama bunu nasıl yaptığımı açıklamak için buraya bir cevap ekleyeceğimi düşündüm sqldf().

Meydana gelmiş tartışma biraz bir R veri çerçevesi içine iyi 2GB almak için yol veya metin verilerinin daha fazlasına kadar. Dün verileri bir hazırlama alanı olarak SQLite içine almak ve daha sonra SQLite'den R'ye emmek için kullanma hakkında bir blog yazısı yazdım sqldf(). Bu benim için gerçekten iyi çalışıyor. <5 dakika içinde 2GB (3 sütun, 40mm sıra) veri alabildim. Buna karşılık, read.csvkomut bütün gece koştu ve asla tamamlanmadı.

İşte test kodum:

Test verilerini ayarlayın:

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

Aşağıdaki alma yordamını çalıştırmadan önce R'yi yeniden başlattım:

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

Aşağıdaki hattın bütün gece çalışmasına izin verdim ama asla tamamlanmadı:

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

1
Selam. Tüm verilerle eşzamanlı olarak kullanılmak üzere tasarlanmış hayvanat bahçesi gibi diğer paketler için bir girdi olarak nasıl kullanırsınız?
skan

@skan son nesne bir veri çerçevesidir. Yani hayvanat bahçesi ile kullanmak için bir hayvanat bahçesi nesnesine dönüştürmek zorunda. Çizimler için hayvanat bahçesi belgelerindeki örneklere bakın.
JD Long

@JD Uzun. Merhaba, sorun, bir hayvanat bahçesi nesnesine dönüştürdüğünüzde belleğe sığdırmaya çalışıyor olmasıdır. Çok büyükse hata üretir. Ve eğer zoo nesnesinin sonucu da (örneğin, iki serinin bir araya getirilmesi) de bir sql veya ff nesnesi de olması gerekir.
skan

Sqldf ile neyin yanlış olduğunu bilmiyorum. Ben disk üzerinde basit bir 1GB dosyası (2 sayısal sütun ile) oluşturdum ve DTSQL <- read.csv.sql ("f2.txt", dbname = tempfile ()) kullandım ve tüm verileri belleğe yüklemeye çalışır. Yarın bunun yerine ff ve revoscaler'ı deneyeceğim.
skan

1
@ m bin, yani mm bin bin veya milyon. Muhtemelen MM olarak büyük harf kullanmalıydım. Ancak, yeterince farklı bir kitleniz varsa, herhangi bir milyon kısaltmanın kafa karıştırıcı olabileceğini görüyorum. Aşırı ayrıntılı olma girişimimde, daha kafa karıştırıcı yaptığım için üzgünüm! muhasebecoach.com/blog/what-does-m-and-mm-stand-for
JD Long

73

Garip bir şekilde, bu önemli bir soru olmasına rağmen, hiç kimse sorunun alt kısmını yıllarca cevaplamadı - data.framesadece doğru özelliklere sahip listelerdir, bu nedenle büyük verileriniz varsa as.data.frame, bir liste için kullanmak istemediğiniz veya benzer bir şey istemezsiniz . Bir listeyi yerinde bir veri çerçevesine "dönüştürmek" çok daha hızlıdır:

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

Bu, verilerin kopyasını almaz, böylece hemen (diğer tüm yöntemlerin aksine). names()Listede buna göre ayarladığınızı varsayar .

[Büyük veri R'ye yüklemek için gelince - kişisel olarak, onları ikili dosyalara sütunla dökümü ve kullanıyorum readBin()- bu en hızlı yöntemdir (mmapping dışında) ve sadece disk hızı ile sınırlıdır. ASCII dosyalarını ayrıştırma, ikili verilere kıyasla doğal olarak yavaştır (C'de bile).]


6
Kullanımı bunu tracmemönerir attr<-ve class<-dahili olarak kopyalar. bit::setattrya data.table::setattrda olmayacak.
mnel

6
Belki de yanlış siparişi kullandınız? Kullanırsanız kopya yoktur df=scan(...); names(df)=...; attr...; class...- bkz. tracemem()(R 2.15.2'de test edilmiştir)
Simon Urbanek

3
Büyük verileri sütuna göre ikili dosyalara nasıl döktüğünüz hakkında ayrıntılı bilgi verebilir misiniz?
dabsingh

32

Bu daha önce R- Help'te sorulmuştu , bu yüzden gözden geçirmeye değer.

Bir öneri kullanmaya vardı readChar()ve daha sonra sonuca dize kullanımı yapmak strsplit()ve substr(). ReadChar'a dahil olan mantığın read.table'dan çok daha az olduğunu görebilirsiniz.

Belleğin burada bir sorun olup olmadığını bilmiyorum, ancak HadoopStreaming paketine de göz atmak isteyebilirsiniz . Bu , büyük veri kümeleriyle başa çıkmak için tasarlanmış bir MapReduce çerçevesi olan Hadoop'u kullanır . Bunun için hsTableReader işlevini kullanırsınız. Bu bir örnektir (ancak Hadoop'u öğrenmek için bir öğrenme eğrisi vardır):

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)

Buradaki temel fikir, veri aktarımını parçalara ayırmaktır. Paralel çerçevelerden birini (ör. Kar) kullanmak ve dosyayı bölümlere ayırarak veri içe aktarmayı paralel olarak çalıştırabilirsiniz, ancak büyük olasılıkla bellek kısıtlamalarına gireceğiniz için yardımcı olmayacak büyük veri kümeleri için, harita azaltmanın daha iyi bir yaklaşım olmasının nedeni budur.


Ben sadece hızlı bir test yaptım ve readChar bazı açıklanamayan bir nedenden dolayı readLines bile çok daha hızlı görünüyor. Bununla birlikte, basit bir C testine kıyasla günah olarak hala yavaştır. 100 mega okuma basit görevinde, R, C'den 5 - 10x daha yavaştır
Jonathan Chang

1
Ne demek istediğini anlamıyorum. Hadoop'un amacı, sorunun ne olduğu ile ilgili çok büyük verileri ele almaktır.
Shane

1
Adına rağmen, hsTableReader'ın Hadoop ile kendi başına bir ilgisi yoktur, büyük verileri parçalar halinde işlemek içindir. Bir seferde bir satır yığını olan con'dan okur ve her parçayı bir data.frame olarak işleme için FUN'a iletir. İgnoreKey = FALSE ile, Harita / Küçült yaklaşımlarıyla ilgili olan bazı ekstra gruplama anahtarları (ilk sütundaki giriş) yapar.
DavidR

Selam. Bu Hadoop verilerini, tüm verilerle eşzamanlı olarak kullanılmak üzere tasarlanmış hayvanat bahçesi gibi diğer paketler için bir girdi olarak nasıl kullanırsınız?
skan

10

Alternatif olarak vroompaketi kullanmaktır . Şimdi CRAN'da. vroomtüm dosyayı yüklemez, her kaydın bulunduğu yeri dizine ekler ve daha sonra kullandığınızda okunur.

Sadece kullandığınız kadar ödeyin.

Bkz . Vroom'a giriş , vroom ve vroom kriterlerini kullanmaya başlama .

Temel genel bakış, büyük bir dosyanın ilk okunmasının çok daha hızlı olacağı ve daha sonra verilerde yapılacak değişikliklerin biraz daha yavaş olabileceğidir. Bu nedenle, kullanımınızın ne olduğuna bağlı olarak, en iyi seçenek olabilir.

Aşağıdaki vroom kriterlerinden basitleştirilmiş bir örneğe bakın, görülecek önemli parçalar süper hızlı okuma süreleridir, ancak toplu vb.

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

Bahsetmeye değer küçük ek noktalar. Çok büyük bir dosyanız varsa, kullanarak satır sayısını (başlık yoksa) ( bedGraphçalışma dizininizdeki dosyanızın adı nerede) kullanarak hesaplayabilirsiniz :

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

Daha sonra ya onu kullanabilirsiniz 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

Çoğu zaman daha büyük veritabanlarını bir veritabanı (örneğin Postgres) içinde tutmanın iyi bir uygulama olduğunu düşünüyorum. Oldukça küçük (nrow * ncol) ncell = 10M'den çok daha büyük bir şey kullanmıyorum; ancak sık sık R'nin birden çok veritabanından sorgu yaparken bellek yoğun grafikler oluşturmasını ve tutmasını istiyorum. 32 GB'lık dizüstü bilgisayarların geleceğinde, bu tür bellek sorunlarının bazıları kaybolacak. Ancak, verileri tutmak için bir veritabanı kullanmanın ve sonuçta ortaya çıkan sorgu sonuçları ve grafikleri için R'nin belleğini kullanmanın cazibesi yine de faydalı olabilir. Bazı avantajlar:

(1) Veriler veritabanınızda yüklü kalır. Dizüstü bilgisayarınızı tekrar açtığınızda pgadmin'de istediğiniz veritabanlarına yeniden bağlanmanız yeterlidir.

(2) R'nin SQL'den çok daha şık istatistik ve grafik işlemleri yapabileceği doğrudur. Ama bence SQL, R'den çok miktarda veriyi sorgulamak için daha iyi tasarlanmış.

# 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

Yeni arrowpaketi kullanarak çok hızlı veri okuyorum . Oldukça erken bir aşamada gibi görünüyor.

Özellikle, parke sütun biçimini kullanıyorum. Bu, data.frameR'de bir a'ya dönüşür , ancak bunu yapmazsanız daha derin hızlanma elde edebilirsiniz. Bu format, Python'dan da kullanılabildiği için uygundur.

Bunun için ana kullanım durumum oldukça kısıtlanmış bir RShiny sunucusunda. Bu nedenlerden dolayı, Uygulamalara bağlı verileri (yani SQL dışında) tutmayı tercih ederim ve bu nedenle hızın yanı sıra küçük dosya boyutu da gerektirir.

Bu bağlantılı makale karşılaştırma ve iyi bir genel bakış sunar. Aşağıda bazı ilginç noktalara değindim.

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

Dosya boyutu

Yani, Parke dosyası gzip edilmiş CSV'nin yarısı kadar büyüktür. Parke dosyasının çok küçük olmasının nedenlerinden biri sözlük kodlamasıdır (“sözlük sıkıştırma” olarak da bilinir). Sözlük sıkıştırması, LZ4 veya ZSTD (FST formatında kullanılan) gibi genel amaçlı bir bayt kompresör kullanmaktan önemli ölçüde daha iyi sıkıştırma sağlayabilir. Parke, hızlı okunabilen çok küçük dosyalar üretmek için tasarlanmıştır.

Okuma Hızı

Çıktı türüne göre kontrol ederken (örn. Tüm R verileri. Çerçeve çıktılarını birbirleriyle karşılaştırırken), Parke, Geçiş Yumuşatma ve FST'nin performanslarının nispeten küçük bir marjda olduğunu görüyoruz. Aynı şey pandas.DataFrame çıkışları için de geçerlidir. data.table :: fread, 1,5 GB dosya boyutu ile etkileyici bir şekilde rekabet edebilir, ancak diğerlerini 2,5 GB CSV'de geride bırakır.


Bağımsız Test

1.000.000 satırlık simüle edilmiş veri kümesinde bağımsız bir karşılaştırma yaptım. Temelde sıkıştırmaya meydan okumak için bir sürü şeyi karıştırdım. Ayrıca rastgele kelimelerin kısa bir metin alanını ve iki simüle edilmiş faktörü ekledim.

Veri

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))
         )

Oku ve yaz

Verileri yazmak kolaydır.

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)

Verileri okumak da kolaydır.

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)

Bu verileri rakip seçeneklerden birkaçına karşı okumayı test ettim ve beklenen makaleye göre biraz farklı sonuçlar elde ettim.

kıyaslama

Bu dosya kıyaslama makalesi kadar büyük değildir, bu yüzden belki de fark budur.

Testler

  • rds: test_data.rds (20.3 MB)
  • parquet2_native: (daha yüksek sıkıştırma ile 14,9 MB ve as_data_frame = FALSE)
  • parke2: test_data2.parquet (daha yüksek sıkıştırma ile 14.9 MB)
  • parke: test_data.parquet (40.7 MB)
  • fst2: test_data2.fst (daha yüksek sıkıştırma ile 27,9 MB)
  • fst: test_data.fst (76,8 MB)
  • fread2: test_data.csv.gz (23.6MB)
  • fread: test_data.csv (98.7MB)
  • feather_arrow: test_data.feather (157.2 MB okuma ile arrow)
  • feather: test_data.feather (157,2 MB okuma ile feather)

Gözlemler

Bu dosya freadiçin aslında çok hızlı. Yüksek sıkıştırılmış parquet2testten küçük dosya boyutunu seviyorum . data.frameGerçekten hızlanmaya ihtiyacım olursa , yerel veri formatıyla çalışmak için zaman harcayabilirim .

Burada fstda harika bir seçim. Ben hız veya dosya boyutu takas gerekiyordu bağlı olarak ben fstya yüksek derecede sıkıştırılmış formatı ya da çok sıkıştırılmış kullanırsınız parquet.


0

Geleneksel read.table yerine kendimi daha hızlı bir işlev hissediyorum. Yalnızca gerekli sütunları seçmek gibi ek öznitelikler belirtmek, karakterleri ve dizeyi faktörler olarak belirtmek dosyayı içe aktarma süresini azaltır.

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

Her şeyi denedim ve [readr] [1] en iyi işi yaptı. Sadece 8GB RAM'im var

20 dosya için döngü, her biri 5 gb, 7 sütun:

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)))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.