.SD ne anlama geliyor?


173

.SDyararlı görünüyor ama onunla ne yaptığımı gerçekten bilmiyorum. Ne anlama geliyor? Neden bir önceki dönem var (tam durak). Kullandığımda ne oluyor?

Ben okudum: grup sütun (lar) hariç, her grup için 'veri alt kümesini içeren .SDbir . Gruplama , gruplama , anahtarlama ve _ad hoc_data.tablexibybyby

Bu, kızının bir data.tablesonraki operasyon için hafızada tutulduğu anlamına mı geliyor ?


30
?data.tablebu soru sayesinde v1.7.10'da geliştirildi. Şimdi adı .SDkabul edilen cevaba göre açıklıyor .
Matt Dowle

Yanıtlar:


205

.SD" Sata.table Dubset" gibi bir şey anlamına gelir . İlk harfin önemi yoktur ".", ancak kullanıcı tanımlı sütun adıyla bir çakışma olmasını daha da olası hale getirmez.

Bu sizin verilerinizse. Tablo:

DT = data.table(x=rep(c("a","b","c"),each=2), y=c(1,3), v=1:6)
setkey(DT, y)
DT
#    x y v
# 1: a 1 1
# 2: b 1 3
# 3: c 1 5
# 4: a 3 2
# 5: b 3 4
# 6: c 3 6

Bunu yapmak, ne olduğunu görmenize yardımcı olabilir .SD:

DT[ , .SD[ , paste(x, v, sep="", collapse="_")], by=y]
#    y       V1
# 1: 1 a1_b3_c5
# 2: 3 a2_b4_c6

Temel olarak, by=yifade orijinal verileri kırar. Bu iki altdata.tables

DT[ , print(.SD), by=y]
# <1st sub-data.table, called '.SD' while it's being operated on>
#    x v
# 1: a 1
# 2: b 3
# 3: c 5
# <2nd sub-data.table, ALSO called '.SD' while it's being operated on>
#    x v
# 1: a 2
# 2: b 4
# 3: c 6
# <final output, since print() doesn't return anything>
# Empty data.table (0 rows) of 1 col: y

ve onlar üzerinde çalışır.

Her ikisinde de çalışırken data.table, nick / handle / sembolünü kullanarak geçerli alt öğeye başvurmanızı sağlar .SD. Bu çok kullanışlıdır, çünkü sütunlar üzerinde tıpkı tek bir veri ile çalışan komut satırında oturuyormuş gibi çalışabildiğiniz için .SD... denilen ... burada bunun dışında, data.tablebu işlemleri, data.tabletarafından tanımlanan her bir alt bölümde gerçekleştirecektir . anahtar kombinasyonları, onları geri "yapıştırarak" ve sonuçları tek bir döndürme data.table!


12
Evet kesinlikle. Görmenin bir başka yolu .SDda DT[,print(.SD),by=y].
Matt Dowle

6
@MatthewDowle - Buradayken size bir soru. Yapmak DT[,print(.SD[,y]),by=y], ybir parçası olmasa bile , değerine erişimim olduğunu gösterir .SD. yKapsamlandırılmanın değeri nereden ? Mevcut b / c mevcut değeri bymi?
Josh O'Brien

8
@Josh Nice. Evet. .SD[,y]Düzenli olduğu data.tableberi çok alt küme ybir sütun değil .SDbu durumda olduğunu denir ortamda, bakar j(çevre DTsorgusuna) bydeğişkenleri mevcuttur. Orada bulunmazsa, ebeveyne, ebeveyne ve benzerlerine her zamanki R tarzında bakar. (Peki, bu örneklerde kullanılmadığı için miras alınan kapsamı da birleştirin çünkü yoktur i).
Matt Dowle

1
@Josh FAQ 2.8 bu konuda daha fazlasına sahiptir, iyileştirilmesi gerekebilir (öneriler hoş geldiniz)
Matt Dowle

3
@Josh grup değişkenleri de j mevcuttur ve uzunluğu 1. Çünkü by=list(x,y,z)anlamına geleceğini x, yve zmevcuttur j. Genel erişim için bunlar da paketlenir .BY. SSS 2.10'da biraz geçmiş var, ancak biraz netlik eklenebilir ?data.table. Harika, docu yardım çok hoş olurdu. Projeye katılmak ve doğrudan değiştirmek isterseniz daha da iyi.
Matt Dowle

98

Düzenle:

Bu cevabın ne kadar iyi karşılandığı göz önüne alındığında, şimdi burada bulunan bir paket vinyetine dönüştürdüm


Bunun ne sıklıkta ortaya çıktığı göz önüne alındığında, bu yukarıdaki Josh O'Brien tarafından verilen yararlı cevabın ötesinde, biraz daha fazla açıklama gerektirdiğini düşünüyorum.

Josh tarafından alıntılanan / yaratılan D ata kısaltmasının S ubsetine ek olarak, "S" nin "Kendini" veya "Kendini referans" olarak tanımlamayı da düşünmek yararlı olduğunu düşünüyorum - en temel kisvesi dönüşlü referans için kendisi - biz aşağıdaki örneklerde göreceğimiz gibi, bu arada "sorguları" (ekstraksiyon / alt kümeleri / vs kullanarak zincirleme için özellikle yararlıdır ). Özellikle, bu aynı zamanda kendisi olduğu anlamına gelir (atamaya izin vermediği uyarı ile )..SDdata.table[.SDdata.table:=

Daha basit kullanımı .SDsütun alt ayarı içindir (yani .SDcolsbelirtildiğinde); Bu sürümün anlaşılması çok daha kolay olduğunu düşünüyorum, bu yüzden aşağıda ilkini ele alacağız. Yorumlanması .SD(yani, zaman senaryoları gruplama ikinci kullanımda, by =ya da keyby =belirtilen), kavramsal olarak, biraz daha farklıdır (tüm sonra olmayan bir gruplandırılmış işlemi ile sadece gruplama bir kenarı durumda olduğu için özünde bu aynı olsa bir grup).


İşte kendim sık sık uyguladığım bazı açıklayıcı örnekler ve diğer kullanım örnekleri:

Lahman Verilerini Yükleme

Buna veri oluşturmak yerine daha gerçek bir his vermek için beyzbol hakkında bazı veri setleri yükleyelim Lahman:

library(data.table) 
library(magrittr) # some piping can be beautiful
library(Lahman)
Teams = as.data.table(Teams)
# *I'm selectively suppressing the printed output of tables here*
Teams
Pitching = as.data.table(Pitching)
# subset for conciseness
Pitching = Pitching[ , .(playerID, yearID, teamID, W, L, G, ERA)]
Pitching

Çıplak .SD

Dönüşlü doğası hakkında ne demek istediğimi göstermek .SDiçin en banal kullanımını düşünün:

Pitching[ , .SD]
#         playerID yearID teamID  W  L  G   ERA
#     1: bechtge01   1871    PH1  1  2  3  7.96
#     2: brainas01   1871    WS3 12 15 30  4.50
#     3: fergubo01   1871    NY2  0  0  1 27.00
#     4: fishech01   1871    RC1  4 16 24  4.35
#     5: fleetfr01   1871    NY2  0  1  1 10.00
#    ---                                       
# 44959: zastrro01   2016    CHN  1  0  8  1.13
# 44960: zieglbr01   2016    ARI  2  3 36  2.82
# 44961: zieglbr01   2016    BOS  2  4 33  1.52
# 44962: zimmejo02   2016    DET  9  7 19  4.87
# 44963:  zychto01   2016    SEA  1  0 12  3.29

Yani, az önce geri döndük Pitching, yani, bu aşırı ayrıntılı bir yazma yoluydu Pitchingveya Pitching[]:

identical(Pitching, Pitching[ , .SD])
# [1] TRUE

Alt kümeleme açısından .SD, hala verilerin bir alt kümesidir, sadece önemsiz bir kümedir (kümenin kendisi).

Sütun Alt Ayarı: .SDcols

Ne .SDolduğunu etkilemenin ilk yolu , argümanı kullanırken içerilen sütunları şu şekilde sınırlamaktır :.SD.SDcols[

Pitching[ , .SD, .SDcols = c('W', 'L', 'G')]
#         W  L  G
#     1:  1  2  3
#     2: 12 15 30
#     3:  0  0  1
#     4:  4 16 24
#     5:  0  1  1
# ---         
# 44959:  1  0  8
# 44960:  2  3 36
# 44961:  2  4 33
# 44962:  9  7 19
# 44963:  1  0 12

Bu sadece gösterim amaçlıdır ve oldukça sıkıcıydı. Ancak bu basit kullanım bile, çok çeşitli çok faydalı / her yerde veri işleme işlemlerine katkıda bulunur:

Sütun Türü Dönüştürme

Sütun türü dönüşümü, veri yazma için bir hayat gerçeğidir - bu yazıdan itibaren fwriteotomatik olarak okunamaz Dateveya POSIXctsütunlar oluşturmaz ve character/ factor/ arasında ileri geri dönüşümler numericyaygındır. Biz kullanabilir .SDve .SDcolsbu tür sütunların toplu dönüştürme gruplarına.

Biz Aşağıdaki sütunlar olarak depolanır fark characteriçinde Teamsveri seti:

# see ?Teams for explanation; these are various IDs
#   used to identify the multitude of teams from
#   across the long history of baseball
fkt = c('teamIDBR', 'teamIDlahman45', 'teamIDretro')
# confirm that they're stored as `character`
Teams[ , sapply(.SD, is.character), .SDcols = fkt]
# teamIDBR teamIDlahman45    teamIDretro 
#     TRUE           TRUE           TRUE 

sapplyBurada kullanımınız konusunda kafanız karıştıysa, bunun R tabanı ile aynı olduğuna dikkat edin data.frames:

setDF(Teams) # convert to data.frame for illustration
sapply(Teams[ , fkt], is.character)
# teamIDBR teamIDlahman45    teamIDretro 
#     TRUE           TRUE           TRUE 
setDT(Teams) # convert back to data.table

Bu sözdizimini anlamanın anahtarı, a'nın data.table(a'nın yanı sıra data.frame) listher öğenin bir sütun olduğu bir yer olarak kabul edilebileceğini hatırlamaktır - bu nedenle, sapply/ her sütunalapply uygulanır ve sonucu / genellikle olduğu gibi döndürür (burada, uzunluk 1, yani bir vektör döndürür).FUNsapplylapplyFUN == is.characterlogicalsapply

Bu sütunları dönüştürmek için sözdizimi factorçok benzer - yalnızca :=atama işlecini ekleyin

Teams[ , (fkt) := lapply(.SD, factor), .SDcols = fkt]

RHS'yi adı RHS'ye atamaya çalışmak yerine R'yi sütun adları olarak yorumlamaya zorlamak için fktparantez ()içine almamız gerektiğini unutmayın fkt.

Esnekliği .SDcols(ve :=) bir kabul etmek charactervektörü veya bir integerde sütun adlarının desen tabanlı dönüşüm için kullanışlı gelebilir sütun pozisyonların vektörü *. Tüm factorsütunları şuna dönüştürebiliriz character:

fkt_idx = which(sapply(Teams, is.factor))
Teams[ , (fkt_idx) := lapply(.SD, as.character), .SDcols = fkt_idx]

Sonra içeren tüm sütunları dönüştürmek teamiçin geri factor:

team_idx = grep('team', names(Teams), value = TRUE)
Teams[ , (team_idx) := lapply(.SD, factor), .SDcols = team_idx]

** Açıkça sütun numaralarını (gibi DT[ , (1) := rnorm(.N)]) kullanmak kötü bir uygulamadır ve sütun konumları değiştiğinde zaman içinde sessizce bozuk kodlara yol açabilir. Numaralı dizini ne zaman oluşturduğumuz ve ne zaman kullandığımızın sırası üzerinde akıllı / katı kontrol sahibi olmamanız durumunda, örtük olarak sayıları kullanmak tehlikeli olabilir.

Bir Modelin RHS'sini Kontrol Etme

Değişen model özellikleri, sağlam istatistiksel analizin temel bir özelliğidir. PitchingTabloda bulunan küçük eş değişkenler setini kullanarak bir sürahinin ERA'sını (bir performans ölçüsü olan Kazanılmış Koşular Ortamı) tahmin edelim . Ne arasında (lineer) bir ilişki vermez W(kazanç) ve ERAdiğer eş değişkenler tarifnamede bağlı olarak değişir dahil edildiği?

İşte gücünü .SDbu soruyu araştıran kısa bir senaryo :

# this generates a list of the 2^k possible extra variables
#   for models of the form ERA ~ G + (...)
extra_var = c('yearID', 'teamID', 'G', 'L')
models =
  lapply(0L:length(extra_var), combn, x = extra_var, simplify = FALSE) %>%
  unlist(recursive = FALSE)

# here are 16 visually distinct colors, taken from the list of 20 here:
#   https://sashat.me/2017/01/11/list-of-20-simple-distinct-colors/
col16 = c('#e6194b', '#3cb44b', '#ffe119', '#0082c8', '#f58231', '#911eb4',
          '#46f0f0', '#f032e6', '#d2f53c', '#fabebe', '#008080', '#e6beff',
          '#aa6e28', '#fffac8', '#800000', '#aaffc3')

par(oma = c(2, 0, 0, 0))
sapply(models, function(rhs) {
  # using ERA ~ . and data = .SD, then varying which
  #   columns are included in .SD allows us to perform this
  #   iteration over 16 models succinctly.
  #   coef(.)['W'] extracts the W coefficient from each model fit
  Pitching[ , coef(lm(ERA ~ ., data = .SD))['W'], .SDcols = c('W', rhs)]
}) %>% barplot(names.arg = sapply(models, paste, collapse = '/'),
               main = 'Wins Coefficient with Various Covariates',
               col = col16, las = 2L, cex.names = .8)

W üzerinde OLS katsayısına uygun, çeşitli özellikler

Katsayı her zaman beklenen işarete sahiptir (daha iyi sürahi daha fazla galibiyet ve daha az koşuya izin verilir), ancak büyüklük, başka ne kontrol ettiğimize bağlı olarak önemli ölçüde değişebilir.

Koşullu Birleşimler

data.tablesözdizimi sadeliği ve sağlamlığı için güzeldir. Sözdizimi x[i], alt kümeye iki yaygın yaklaşımı esnek bir şekilde ele alır - ibir logicalvektör olduğunda , nerede olduğuna karşılık gelen x[i]satırları döndürür ; zaman olan başka bir (kullanarak, düz şeklinde gerçekleştirilmektedir lerini ve , aksi halde, ne zaman, bu sütunların sonuç kullanılarak, belirtilen).xiTRUEidata.tablejoinkeyxion =

Bu genel olarak harika, ancak koşullu bir birleştirme gerçekleştirmek istediğimizde yetersiz kalır , burada tablolar arasındaki ilişkinin kesin doğası bir veya daha fazla sütundaki satırların bazı özelliklerine bağlıdır.

Bu örnek biraz çelişkilidir, ancak fikri gösterir; daha fazla bilgi için buraya ( 1 , 2 ) bakınız .

Amaç bir sütun eklemektir team_performanceiçin Pitching(gibi en az 6 kaydedilen oyunları ile sürahi arasında, en düşük ERA ile ölçülen) her takımın en iyi sürahi Takımın performansını (sıralama) kaydeder masaya.

# to exclude pitchers with exceptional performance in a few games,
#   subset first; then define rank of pitchers within their team each year
#   (in general, we should put more care into the 'ties.method'
Pitching[G > 5, rank_in_team := frank(ERA), by = .(teamID, yearID)]
Pitching[rank_in_team == 1, team_performance := 
           # this should work without needing copy(); 
           #   that it doesn't appears to be a bug: 
           #   https://github.com/Rdatatable/data.table/issues/1926
           Teams[copy(.SD), Rank, .(teamID, yearID)]]

x[y]Sözdiziminin nrow(y)değerleri döndürdüğünü unutmayın , bu nedenle .SDsağdadır Teams[.SD]( :=bu durumda RHS nrow(Pitching[rank_in_team == 1])değeri değer gerektirdiğinden) .

Gruplandırılmış .SDişlemler

Genellikle, verilerimiz üzerinde grup düzeyinde bazı işlemler yapmak isteriz . Belirttiğimizde by =(veya keyby =), data.tablesüreçler olduğunda ne olacağına ilişkin zihinsel model j, sizi her biri değişkenlerinizin tek bir değerine karşılık gelen data.tablebirçok bileşen alt bölümüne bölünmüş olarak düşünmektir :data.tableby

resimli gruplama

Bu durumda, .SDdoğal olarak çok sayıda - bu, bu alt her belirtir data.table, s tek-bir-kez (biraz daha doğru, kapsamı .SDtek alt olan data.table). Bu , yeniden toplanan sonuç bize geri dönmeden önce her bir alt bölümdedata.table gerçekleştirmek istediğimiz bir işlemi kısaca ifade etmemizi sağlar.

Bu, en yaygın olanları burada sunulan çeşitli ayarlarda yararlıdır:

Grup Altkümesi

Lahman verilerindeki her takım için en son veri sezonunu alalım. Bu oldukça basit bir şekilde yapılabilir:

# the data is already sorted by year; if it weren't
#   we could do Teams[order(yearID), .SD[.N], by = teamID]
Teams[ , .SD[.N], by = teamID]

.SDKendisinin a data.tableolduğunu .Nve bir gruptaki toplam satır sayısını ( nrow(.SD)her grup içinde eşittir ) ifade ettiğini hatırlayın , bu nedenle her biriyle ilişkili son satırın tamamını.SD[.N] döndürür ..SDteamID

Bunun bir başka yaygın versiyonu, her grup için ilk gözlemi .SD[1L]almak için kullanmaktır .

Grup Optima

Her takım için en iyi yılı, toplam atılan koşu sayısına göre ölçmek istediğimizi varsayalım ( R; tabii ki bunu diğer metriklere başvuracak şekilde kolayca ayarlayabiliriz). Her bir alt öğeden sabit bir öğe almak yerine, data.tableartık istenen dizini dinamik olarak şu şekilde tanımlarız :

Teams[ , .SD[which.max(R)], by = teamID]

Bu yaklaşım, elbette ile kombine edilebileceği Not .SDcolsyalnızca bir kısmı iade için data.tableher biri için .SD(uyarı ile .SDcolsçeşitli alt boyunca sabit olmalıdır)

NB : .SD[1L]Şu anda optimize edildi GForce( ayrıca bkz ,) data.tablekitlesel gibi en yaygın gruplandırılmış işlemleri hızlandırmak internals sumveya mean- bkz ?GForce: Daha fazla bilgi için ve bu cephede güncellemeler için özellik geliştirmesi istekleri için açık / sesli desteği göz kulak 1 , 2 , 3 , 4 , 5 , 6

Gruplandırılmış Regresyon

Arasındaki ilişkiyle ilgili yukarıdaki soruşturma dönersek ERAve Wbiz bu ilişkinin ekibi tarafından fark bekliyoruz varsayalım (yani her takım için farklı bir eğim vardır). Bu ilişkideki heterojenliği aşağıdaki gibi keşfetmek için bu regresyonu kolayca tekrar yürütebiliriz (bu yaklaşımdaki standart hataların genellikle yanlış olduğunu belirterek - spesifikasyon ERA ~ W*teamIDdaha iyi olacaktır - bu yaklaşımın okunması daha kolaydır ve katsayılar iyidir ) :

# use the .N > 20 filter to exclude teams with few observations
Pitching[ , if (.N > 20) .(w_coef = coef(lm(ERA ~ W))['W']), by = teamID
          ][ , hist(w_coef, 20, xlab = 'Fitted Coefficient on W',
                    ylab = 'Number of Teams', col = 'darkgreen',
                    main = 'Distribution of Team-Level Win Coefficients on ERA')]

uygun katsayıların dağılımı

Adil miktarda heterojenlik olsa da, gözlemlenen toplam değerin etrafında belirgin bir konsantrasyon vardır

Umarım bu .SDgüzel, verimli kodu kolaylaştırma gücünü açıklamıştır data.table!


5
İyi açıklama. Sadece bir yorum: Takımlar [, .SD [which.max (R)] yerine = teamID] yerine, hızlı data.table sipariş fonksiyonundan yararlanabilirsiniz: Teams [order (teamID, -R), .SD [ 1L], keyby = teamID], bu daha hızlı olmalıdır.
bartleby

@bartleby teşekkürler, gerçekten bu doğrudur, ancak genel yaklaşımı bilmek hala yararlıdır - örneğin, gruba bağlı bir miktarla sipariş vermemiz gerekiyorsa. belki örneği değiştireceğim.
MichaelChirico

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.