Data.table'da bir anahtar ayarlamanın amacı nedir?


113

Data.table kullanıyorum ve bir anahtar ayarlamamı gerektiren birçok işlev var (örneğin X[Y]). Bu nedenle, veri tablolarımdaki anahtarları doğru şekilde ayarlamak için bir anahtarın ne yaptığını anlamak isterim.


Okuduğum kaynaklardan biri ?setkey.

setkey()a'yı sıralar data.tableve sıralı olarak işaretler. Sıralanan sütunlar anahtardır. Anahtar, herhangi bir sıradaki herhangi bir sütun olabilir. Sütunlar her zaman artan sırada sıralanır. Tablo referans olarak değiştirilir. Bir sütun büyüklüğündeki geçici çalışma belleği dışında hiçbir şekilde kopyalama yapılmaz.

Buradaki çıkarım, bir anahtarın data.table'ı "sıralaması" ve sonuçta çok benzer bir etki yaratmasıdır order(). Ancak, bir anahtara sahip olmanın amacını açıklamıyor.


Data.table SSS 3.2 ve 3.3 şunları açıklar:

3.2 Büyük bir masada anahtarım yok, ancak gruplama hala çok hızlı. Neden?

data.table, radix sıralama kullanır. Bu, diğer sıralama algoritmalarından önemli ölçüde daha hızlıdır. Radix yalnızca tamsayılar içindir, bkz ?base::sort.list(x,method="radix"). Bu aynı zamanda setkey()hızlı olmasının bir nedenidir . Anahtar ayarlanmadığında veya anahtardan farklı bir sırada grupladığımızda, buna ad hoc diyoruz.

3.3 Neden anahtardaki sütunlara göre gruplama geçici bir yöntemden daha hızlıdır?

Her grup RAM'de bitişik olduğundan, böylece sayfa getirmeleri en aza indirilir ve bellek memcpyC'de döngü yapmak yerine toplu olarak ( C olarak) kopyalanabilir .

Buradan, bir anahtar ayarlamanın bir şekilde R'nin diğer algoritmalara göre "taban sıralaması" kullanmasına izin verdiğini ve bu yüzden daha hızlı olduğunu tahmin ediyorum.


10 dakikalık hızlı başlangıç ​​kılavuzu ayrıca tuşlarla ilgili bir kılavuza da sahiptir.

  1. Anahtarlar

Data.frame, özel olarak satır adları (veya İngilizce satır adlarını) düşünerek başlayalım. Yani, tek bir satıra ait birden çok isim. Tek satıra ait birden fazla isim? Data.frame'de alıştığımız şey bu değil. Her satırın en fazla bir adı olduğunu biliyoruz. Bir kişinin en az iki adı vardır, ilk adı ve ikinci adı. Bu, örneğin soyadına ve ardından ilk ada göre sıralanmış bir telefon rehberi düzenlemek için kullanışlıdır. Ancak, data.frame'deki her satırın yalnızca bir adı olabilir.

Bir anahtar, yalnızca karakterden değil, tam sayı, faktör, karakter veya başka bir sınıf olabilen bir veya daha fazla satır adı sütunundan oluşur. Ayrıca, satırlar anahtara göre sıralanır. Bu nedenle, bir data.table birden fazla şekilde sıralanamayacağı için en fazla bir anahtara sahip olabilir.

Benzersizlik zorunlu kılınmaz, yani yinelenen anahtar değerlerine izin verilir. Satırlar anahtara göre sıralandığından, anahtardaki kopyalar art arda görünecektir

Telefon rehberi, bir anahtarın ne olduğunu anlamada yardımcı oldu, ancak bir anahtarın bir faktör sütununa sahip olmaktan farklı olmadığı görülüyor. Ayrıca, neden bir anahtarın gerekli olduğunu (özellikle belirli işlevleri kullanmak için) ve anahtar olarak ayarlanacak sütunun nasıl seçileceğini açıklamaz. Ayrıca, bir sütun olarak zaman içeren bir data.table'da, başka herhangi bir sütunu anahtar olarak ayarlamak muhtemelen zaman sütununu da bozacak gibi görünüyor, bu da başka bir sütunu olarak ayarlamama izin verilip verilmediğini bilmediğim için daha da kafa karıştırıcı hale getiriyor. tuşuna basın. Biri beni aydınlatabilir mi lütfen?


"Sanırım bir anahtar ayarlamak R'nin diğer algoritmalara göre" taban sıralaması "kullanmasına izin veriyor" - Bunu yardımdan hiç anlamıyorum. Benim okuduğum, bir anahtar ayarlamanın bir anahtarla sıralanmasıdır. Anahtardan başka sütunlara göre "geçici" sıralama yapabilirsiniz ve hızlıdır, ancak önceden sıraladığınız kadar hızlı değildir.
Ari B. Friedman

Satırları seçerken ikili aramanın vektör taramasından daha hızlı olduğunu düşünüyorum. Bilgisayar bilimcisi değilim, bu yüzden bunun gerçekte ne anlama geldiğini bilmiyorum. SSS yanı sıra, bkz tanıtım .
Frank

Yanıtlar:


125

Küçük güncelleme: Lütfen yeni HTML vinyetlerine de bakın. Bu sayı , planladığımız diğer vinyetlerin altını çiziyor.


Geçici birleştirmelere de on=izin veren yeni özellik ışığında bu yanıtı tekrar güncelledim (Şubat 2016) . Daha önceki (eski) cevaplar için geçmişe bakın.

Tam olarak ne yapar setkey(DT, a, b)?

İki şey yapar:

  1. data.table'ın satırlarını , her zaman artan sırada , referans olarakDT sağlanan ( a , b ) sütun (lar) a göre yeniden sıralar .
  2. işaretleri olarak bu sütunları anahtar adlı bir öznitelik ayarlayarak sütunlar sortediçin DT.

Yeniden sıralama hem hızlıdır ( data.table'ın dahili taban sıralaması nedeniyle ) hem de bellek verimlidir ( double türünde yalnızca bir ekstra sütun ayrılır).

Ne zaman setkey()gereklidir?

Gruplama işlemleri setkey()için hiçbir zaman mutlak bir gereklilik olmadı. Yani, bir soğuk ya da plansız gerçekleştirebiliriz .

## "cold" by
require(data.table)
DT <- data.table(x=rep(1:5, each=2), y=1:10)
DT[, mean(y), by=x] # no key is set, order of groups preserved in result

Ancak öncesinde v1.9.6, formun birleştiği x[i]gerekli keyayarlanacak x. V1.9.6 + 'dan gelen yeni on=argüman ile bu artık doğru değil ve bu nedenle anahtarları ayarlamak burada da mutlak bir gereklilik değil .

## joins using < v1.9.6 
setkey(X, a) # absolutely required
setkey(Y, a) # not absolutely required as long as 'a' is the first column
X[Y]

## joins using v1.9.6+
X[Y, on="a"]
# or if the column names are x_a and y_a respectively
X[Y, on=c("x_a" = "y_a")]

Bağımsız on=değişkenin keyedbirleşimler için bile açıkça belirtilebileceğini unutmayın .

keyMutlak olarak ayarlanması gereken tek işlem foverlaps () işlevidir. Ancak, yapıldığında bu gereksinimi ortadan kaldıracak bazı daha fazla özellik üzerinde çalışıyoruz.

  • Öyleyse on=argümanı uygulamanın nedeni nedir?

    Pek çok neden var.

    1. İşlemi iki veri içeren bir işlem olarak net bir şekilde ayırt etmeyi sağlar . Tablo . X[Y]Değişkenleri uygun bir şekilde adlandırarak netleşse de, sadece yapmak bunu da ayırt etmez.

    2. Ayrıca , bu kod satırına bakarak (ve karşılık gelen satıra geri dönmek zorunda kalmadan) birleştirme / alt kümenin hemen gerçekleştirildiği sütunları anlamaya da olanak tanır setkey().

    3. Sütunlar eklenir veya güncellenir operasyonlarda referans olarak , on=bu güncelleştirme kolon (lar) / tüm data.table sadece eklemek için, yeniden düzenlenmesi gerekmez olarak operasyonlar çok daha fazla ölçülebilir vardır. Örneğin,

      ## compare 
      setkey(X, a, b) # why physically reorder X to just add/update a column?
      X[Y, col := i.val]
      
      ## to
      X[Y, col := i.val, on=c("a", "b")]

      İkinci durumda, yeniden sipariş vermek zorunda kalmadık. Zaman alıcı olan sırayı hesaplamak değil, verileri RAM'de fiziksel olarak yeniden sıralamak ve bundan kaçınarak orijinal sırayı koruyoruz ve aynı zamanda performans gösteriyor.

    4. Aksi takdirde bile, birleştirme işlemlerini tekrar tekrar gerçekleştirmediğiniz sürece, anahtarlı ve anlık birleştirmeler arasında gözle görülür bir performans farkı olmamalıdır .

Bu, bir data.table'ı anahtarlamanın artık ne gibi bir avantajı var?

  • Bir data.table'ı anahtarlamanın bir avantajı var mı?

    Bir data.table'ı anahtarlamak, onu RAM'deki bu sütunlara göre fiziksel olarak yeniden sıralar. Siparişi hesaplamak genellikle zaman alan bir iş değildir, daha ziyade yeniden sıralamanın kendisidir. Bununla birlikte, verileri RAM'de sıraladığımızda, aynı gruba ait satırların tümü RAM'de bitişiktir ve bu nedenle önbellek açısından çok verimlidir. Anahtarlı veri tablolarındaki işlemleri hızlandıran sıralılıktır.

    Bu nedenle, tüm data.table'ı yeniden düzenlemek için harcanan zamanın, önbellek açısından verimli bir birleştirme / toplama yapmak için harcanan zamana değip değmeyeceğini anlamak önemlidir. Genellikle, aynı anahtarlanmış data.table üzerinde gerçekleştirilen tekrarlayan gruplama / birleştirme işlemleri olmadığı sürece, gözle görülür bir fark olmamalıdır.

Bu nedenle çoğu durumda, artık anahtarları ayarlamaya gerek kalmamalıdır. on=Anahtar ayarlamadan yararlanmak istediğiniz performans açısından önemli bir gelişme olmadıkça, mümkün olan her yerde kullanmanızı öneririz .

Soru: Bir karşılaştırıldığında gibi performans olurdu ne düşünüyorsunuz Anahtarlı kullanırsanız, katılmak setorder()yeniden sıralamak data.table ve kullanım on=? Şimdiye kadar takip ettiyseniz, bunu çözebilmelisiniz :-).


3
Harika, teşekkürler! Şimdiye kadar, "ikili arama" nın gerçekte ne anlama geldiğini düşünmemiştim ve hash yerine neden kullanıldığını gerçekten anlamamıştım.
Frank

@Arun, DT[J(1e4:1e5)]gerçekten eşdeğer DF[DF$x > 1e4 & DF$x < 1e5, ]mi? Bana ne Janlama geldiğini gösterebilir misin ? Ayrıca, sample(1e4, 1e7, TRUE)1e4'ün üzerindeki sayıları içermediğinden bu arama herhangi bir satır döndürmez.
fishtank

@fishtank, bu durumda, düzeltilmeli >=ve <=düzeltilmelidir. J(ve .) takma adlardır list(yani eşdeğerdirler). Dahili iolarak bir liste olduğunda , satır indekslerini hesaplamak için ikili aramanın kullanıldığı bir data.table'a dönüştürülür. Karışıklığı önlemek 1e4için sabitlendi 1e5. Gördüğün için teşekkürler. on=Şimdi, anahtarı ayarlamak yerine ikili alt kümeleri gerçekleştirmek için doğrudan argümanı kullanabileceğimizi unutmayın . Yeni HTML vinyetlerinden daha fazlasını okuyun . Ve birleştirmeler için vinyetler için o sayfaya bir göz atın.
Arun

belki bu daha kapsamlı bir güncelleme için gidebilir? "gerektiğinde" bölümü geçerliliğini yitirmiş görünüyor, örneğin
MichaelChirico

Hangi işlev size kullanılan anahtarı söyler?
skan

20

Anahtar, temelde çok hızlı ve verimli sıralama, filtreleme ve birleştirme işlemlerine olanak tanıyan bir veri kümesine dizindir. Bunlar muhtemelen veri çerçeveleri yerine veri tablolarını kullanmanın en iyi nedenleridir (veri tablolarını kullanmak için sözdizimi de çok daha kullanıcı dostudur, ancak bunun anahtarlarla hiçbir ilgisi yoktur).

Dizinleri anlamıyorsanız, şunu göz önünde bulundurun: bir telefon rehberi isme göre "endekslenir". Yani birinin telefon numarasına bakmak istersem, oldukça basittir. Ancak, telefon numarasına göre aramak istediğimi varsayalım (örneğin, kimin belirli bir telefon numarasına sahip olduğuna bakın)? Telefon rehberini telefon numarasına göre "yeniden endeksleyemediğim" sürece, çok uzun zaman alacaktır.

Şu örneği düşünün: ABD'deki tüm posta kodlarının (> 33.000) yanı sıra ilişkili bilgilerle (şehir, eyalet, nüfus, medyan gelir vb.) Bir tablonun, ZIP'iniz olduğunu varsayalım. Belirli bir posta kodu için bilgi aramak istersem, arama (filtre) setkey(ZIP,zipcode)ilk önce 1000 kat daha hızlıdır .

Diğer bir avantaj da birleştirme ile ilgilidir. Bir veri tablosunda bir kişi listesi ve posta kodları olduğunu varsayalım (buna "PPL" deyin) ve ZIP tablosundaki bilgileri (örneğin şehir, eyalet, vb.) Eklemek istiyorum. Aşağıdaki kod bunu yapacak:

setkey(ZIP,zipcode)
setkey(PPL,zipcode)
full.info <- PPL[ZIP, nomatch=F]

Bu, ortak bir alana (posta kodu) dayalı olarak 2 tablodaki bilgileri birleştirmem anlamında bir "birleştirme" dir. Çok büyük tablolardaki bu gibi birleşimler veri çerçevelerinde son derece yavaş ve veri tablolarında son derece hızlıdır. Gerçek hayattan bir örnekte, tam bir posta kodları tablosunda bunun gibi 20.000'den fazla birleştirme yapmak zorunda kaldım. Veri tablolarıyla betik yaklaşık 20 dakika sürdü. koşmak. Veri çerçeveleriyle bile denemedim çünkü 2 haftadan fazla sürecekti.

IMHO sadece okumak ama olmamalı çalışma SSS ve giriş malzemesini. Bunu uygulayacak gerçek bir sorununuz varsa anlamak daha kolay.

[@ Frank'in yorumuna yanıt]

Re: sıralama ve indeksleme - Bu sorunun cevabına göre setkey(...), aslında tablodaki sütunları yeniden düzenlediği (örneğin, fiziksel bir sıralama) ve veritabanı anlamında bir indeks oluşturmadığı görülmektedir. Bunun bazı pratik sonuçları vardır: setkey(...)Öncelikle bir tablodaki anahtarı ile ayarlar ve sonra anahtar sütunundaki değerlerden herhangi birini değiştirirseniz, data.table yalnızca tablonun artık sıralanmayacağını bildirir ( sortedözniteliği kapatarak ); öyle değil (bir veritabanında olur gibi) uygun sıralama düzeni sürdürmek için yeniden indeksi dinamik. Ayrıca kullanarak "tuşuna çıkarmadan" setky(DT,NULL)yok değil 's orijinal tasnifsiz düzene tabloyu geri yükleyin.

Re: filtreleme ve birleştirme - pratik fark, filtrelemenin tek bir veri kümesinden bir alt kümeyi çıkarması, oysa birleştirme ortak bir alana dayalı olarak iki veri kümesindeki verileri birleştirmesidir. Birçok farklı birleştirme türü vardır (iç, dış, sol). Yukarıdaki örnek bir iç birleşimdir (yalnızca her iki tabloda ortak anahtarlara sahip kayıtlar döndürülür) ve bu, filtrelemeye birçok benzerliğe sahiptir.


1
+1. İlk cümlenize gelince ... zaten sıralandı değil mi? Ve birleştirme, özel bir filtre durumu (veya filtrelemeyi ilk adımı olarak alan bir işlem) değil mi? Görünüşe göre "daha iyi filtreleme" tüm faydayı özetliyor.
Frank

1
Veya sanırım daha iyi tarama.
Wet Feet

1
@jlhoward Teşekkürler. Önceki inancım, sıralamanın anahtarı belirlemenin faydaları arasında olmadığı (çünkü sıralamak istiyorsanız, sadece sıralamanız gerekir) ve ayrıca bu setkeyaslında satırları geri döndürülemez bir şekilde yeniden düzenlemekti. Yalnızca görüntüleme amaçlı ise, ilk on satırı "true" sıralamasına göre (setkey'den önce görmüş olacağım) nasıl yazdırırım? Bunu setkey(DT,NULL)yapmayacağından oldukça eminim ... (devam)
Frank

... (devam) Ayrıca, paketin koduna bakmadım, ancak katılmak X[Y,...]için anahtarı kullanarak X'in satırlarını "filtrelemeniz" gerekiyor. Kabul edilirse, bundan sonra başka şeyler olur (Y'nin sütunları kullanılabilir hale getirilir ve örtük bir by-without-by-by-by-by-olmadan), ama yine de bunu kavramsal olarak farklı bir fayda olarak görmüyorum. Sanırım cevabınız, ayrımın yardımcı olabileceği operasyonlar açısından soruluyor.
Frank

1
@Frank - Yani setkey(DT,NULL)anahtarı kaldırır, ancak sıralama düzenini etkilemez. Bu konuda bir soru yöneltilen burada . Bakalım.
jlhoward
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.