Rbindlist neden rbind 'den daha iyi?


135

Ben daha iyi olması gerekiyordu data.tableSO üzerinde burada bazı konuşmaları belgelendirme ve de fark ettim .rbindlistrbind

Neden daha rbindlistiyi rbindve hangi senaryoların rbindlistgerçekten üstesinden geldiğini bilmek istiyorum rbind?

Bellek kullanımı açısından herhangi bir avantajı var mı?

Yanıtlar:


155

rbindlist, do.call(rbind, list(...))kullanım sırasında yavaş olduğu bilinen optimize edilmiş bir sürümüdürrbind.data.frame


Gerçekten nerede mükemmel

rbindlistParıltıların nerede olduğunu gösteren bazı sorular

Veri listesinin hızlı vectorized birleştirme. Satır satır

Do.call ve ldply kullanarak uzun data.frames listesini (~ 1 milyon) tek data.frame'e dönüştürme sorunu

Bunların ne kadar hızlı olabileceğini gösteren kriterler var.


rbind.data.frame bir nedenden dolayı yavaş

rbind.data.frameçok fazla kontrol yapar ve isimle eşleşir. (yani rbind.data.frame kolonlar farklı sıralarda olmalı ve ismen maç olabilir gerçeğini hesaba katılmış olur) rbindlistdenetimi bu tür yapmaz ve konumu ile katılacak

Örneğin

do.call(rbind, list(data.frame(a = 1:2, b = 2:3), data.frame(b = 1:2, a = 2:3)))
##    a b
## 1  1 2
## 2  2 3
## 3  2 1
## 4  3 2

rbindlist(list(data.frame(a = 1:5, b = 2:6), data.frame(b = 1:5, a = 2:6)))
##     a b
##  1: 1 2
##  2: 2 3
##  3: 1 2
##  4: 2 3

Rbindlist'in diğer bazı sınırlamaları

O zamandan beri düzeltilen bir hata nedeniyle başa çıkmak için mücadele factorsederdi:

rbindlist iki data.tables biri faktör ve diğeri bir sütun için karakter türü ( Hata # 2650 )

Yinelenen sütun adlarıyla ilgili sorunları var

bkz. Uyarı mesajı: rbindlist (allargs): Zorlama ile getirilen NA'lar: data.table içindeki olası hata? ( Hata # 2384 )


rbind.data.frame rownames sinir bozucu olabilir

rbindlistrownames olmadan bir data.table işleyebilir lists data.framesve data.tablesdöndürür

do.call(rbind, list(...)) bkz. kullanarak rownames bir karışıklık alabilirsiniz

Do.call içinde rbind kullanırken satırların yeniden adlandırılmasını nasıl önleyebilirim?


Bellek verimliliği

Bellek rbindlistaçısından uygulandığı gibi C, bellek de verimlidir, setattrnitelikleri referans olarak ayarlamak için kullanılır

rbind.data.frameuygulanan R, bu atama sürü ve kullanımları yapar attr<-(ve class<-ve rownames<-(dahili) oluşturuldu data.frame kopyalarını yaratacak olan bütün.


1
Bilginize attr<-, class<-ve (bence) rownames<-tüm yerinde değiştirin.
hadley

5
@hadley Emin misin? Deneyin DF = data.frame(a=1:3); .Internal(inspect(DF)); tracemem(DF); attr(DF,"test") <- "hello"; .Internal(inspect(DF)).
Matt Dowle

4
rbind.data.frameözel "kaçırma" mantığı vardır - ilk argümanı bir olduğunda data.table, bunun .rbind.data.tableyerine biraz kontrol yapar ve daha sonra rbindlistdahili olarak arama yapar . Zaten var ise data.tablebağlama nesneleri arasındaki muhtemelen çok az performans farkı var rbindve rbindlist.
Ken Williams

6
mnel, bu yazının belki de rbindlistisimlere ( use.names=TRUE) göre eşleştirme ve eksik sütunları ( fill=TRUE) doldurma yeteneğine sahip olması gerekir . Ben güncelledik bu , bu ve bu yazı. Bunu düzenlemenin bir sakıncası var mı yoksa yaparsam sorun olmaz mı? Her iki şekilde de benim için iyi.
Arun

1
dplyr::rbind_listda oldukça benzer
hadley

48

Tarafından v1.9.2, rbindlistbiraz gelişti, dahil olmak üzere birçok özellik uygulamak:

  • SEXPTYPEBağlama sırasında en yüksek sütun seçimi - FR # 2456 ve Hata # 4981'iv1.9.2 kapatmada uygulanır .
  • Taşıma factorilk uygulanan - düzgün sütunları v1.8.10kapanış Hata # 2650 bağlayıcı ve genişletilmiş sipariş dikkatle içinde faktörleri v1.9.2kapanış, sıra FR # 4856 ve Hata # 5019 .

Buna ek olarak v1.9.2, rbind.data.tableayrıca fill, R'de uygulanan eksik sütunları doldurarak bağlanmasına izin veren bir argüman kazandı .

Şimdi v1.9.3, bu mevcut özelliklerde daha da fazla gelişme var:

  • rbindlistuse.namesvarsayılan olarak FALSEgeriye uyumluluk için olan bir argüman kazanır .
  • rbindlistayrıca fillvarsayılan olarak FALSEgeriye dönük uyumluluk için kullanılan bir argüman kazanır .
  • Bu özelliklerin tümü C dilinde uygulanır ve işlevsellik eklerken hızdan ödün vermemek için dikkatlice yazılır.
  • Yana rbindlistşimdi isimleri ve dolgu eksik sütunlara göre eşleşebilir, rbind.data.tablesadece çağrıları rbindlistşimdi. Tek fark, geriye dönük uyumluluk için use.names=TRUEvarsayılan olarak olmasıdır rbind.data.table.

rbind.data.frameönlenebilecek kopyalar (mnel'in de işaret ettiği) nedeniyle (C'ye geçerek) oldukça yavaşlar. Bence tek sebep bu değil. Sütun adlarını kontrol etme / eşleştirme uygulaması, rbind.data.framedata.frame başına çok sayıda sütun olduğunda ve bağlanmak için bu tür birçok data.fram olduğunda daha yavaş olabilir (aşağıdaki karşılaştırmada gösterildiği gibi).

Ancak, rbindlistbelirli özelliklerin (editör) kontrol edilmesi (faktör seviyelerini kontrol etmek veya isimleri eşleştirmek gibi), ona göre çok daha küçük (veya hiç) ağırlık taşımaktadır rbind.data.frame. Çünkü dikkatlice hız ve bellek için optimize edilmiş C'ye uygulandılar.

İşte rbindlist's use.namesözelliğini kullanarak sütun isimleriyle eşleştirirken etkili ciltlemeyi vurgulayan bir karşılaştırma ölçütü v1.9.3. Veri seti 10000 veriden oluşur. Her biri 10 * 500 boyutunda çerçeveler.

Not: Bu kriter için bir karşılaştırma içerecek şekilde güncellenmiştir dplyrs'bind_rows

library(data.table) # 1.11.5, 2018-06-02 00:09:06 UTC
library(dplyr) # 0.7.5.9000, 2018-06-12 01:41:40 UTC
set.seed(1L)
names = paste0("V", 1:500)
cols = 500L
foo <- function() {
    data = as.data.frame(setDT(lapply(1:cols, function(x) sample(10))))
    setnames(data, sample(names))
}
n = 10e3L
ll = vector("list", n)
for (i in 1:n) {
    .Call("Csetlistelt", ll, i, foo())
}

system.time(ans1 <- rbindlist(ll))
#  user  system elapsed 
# 1.226   0.070   1.296 

system.time(ans2 <- rbindlist(ll, use.names=TRUE))
#  user  system elapsed 
# 2.635   0.129   2.772 

system.time(ans3 <- do.call("rbind", ll))
#   user  system elapsed 
# 36.932   1.628  38.594 

system.time(ans4 <- bind_rows(ll))
#   user  system elapsed 
# 48.754   0.384  49.224 

identical(ans2, setDT(ans3)) 
# [1] TRUE
identical(ans2, setDT(ans4))
# [1] TRUE

Adları kontrol etmeden sütunları bu şekilde bağlamak sadece 1.3 aldı, burada sütun adlarını kontrol etmek ve uygun şekilde ciltlemek sadece 1.5 saniye daha sürdü. Temel çözümle karşılaştırıldığında, bu, dplyrsürümüne göre 14 kat daha hızlı ve 18 kat daha hızlıdır .

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.