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 )..SD
data.table
[
.SD
data.table
:=
Daha basit kullanımı .SD
sütun alt ayarı içindir (yani .SDcols
belirtildiğ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 .SD
iç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 Pitching
veya 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 .SD
olduğ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 fwrite
otomatik olarak okunamaz Date
veya POSIXct
sütunlar oluşturmaz ve character
/ factor
/ arasında ileri geri dönüşümler numeric
yaygındır. Biz kullanabilir .SD
ve .SDcols
bu tür sütunların toplu dönüştürme gruplarına.
Biz Aşağıdaki sütunlar olarak depolanır fark character
içinde Teams
veri 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
sapply
Burada 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
) list
her öğ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).FUN
sapply
lapply
FUN == is.character
logical
sapply
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 fkt
parantez ()
içine almamız gerektiğini unutmayın fkt
.
Esnekliği .SDcols
(ve :=
) bir kabul etmek character
vektörü veya bir integer
de sütun adlarının desen tabanlı dönüşüm için kullanışlı gelebilir sütun pozisyonların vektörü *. Tüm factor
sü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 team
iç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. Pitching
Tabloda 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 ERA
diğer eş değişkenler tarifnamede bağlı olarak değişir dahil edildiği?
İşte gücünü .SD
bu 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)
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.table
sö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 - i
bir logical
vektö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).x
i
TRUE
i
data.table
join
key
x
i
on =
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_performance
iç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 .SD
sağdadır Teams[.SD]
( :=
bu durumda RHS nrow(Pitching[rank_in_team == 1])
değeri değer gerektirdiğinden) .
Gruplandırılmış .SD
işlemler
Genellikle, verilerimiz üzerinde grup düzeyinde bazı işlemler yapmak isteriz . Belirttiğimizde by =
(veya keyby =
), data.table
sü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.table
birçok bileşen alt bölümüne bölünmüş olarak düşünmektir :data.table
by
Bu durumda, .SD
doğal olarak çok sayıda - bu, bu alt her belirtir data.table
, s tek-bir-kez (biraz daha doğru, kapsamı .SD
tek 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]
.SD
Kendisinin a data.table
olduğunu .N
ve 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 ..SD
teamID
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.table
artı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 .SDcols
yalnızca bir kısmı iade için data.table
her 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.table
kitlesel gibi en yaygın gruplandırılmış işlemleri hızlandırmak internals sum
veya 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 ERA
ve W
biz 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*teamID
daha 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')]
Adil miktarda heterojenlik olsa da, gözlemlenen toplam değerin etrafında belirgin bir konsantrasyon vardır
Umarım bu .SD
güzel, verimli kodu kolaylaştırma gücünü açıklamıştır data.table
!
?data.table
bu soru sayesinde v1.7.10'da geliştirildi. Şimdi adı.SD
kabul edilen cevaba göre açıklıyor .