답변:
.SD
" S
ata.table의 D
ubset" 과 같은 것을 의미합니다 . "."
사용자 정의 열 이름과의 충돌이 발생할 가능성이 더 낮다는 점을 제외하고 는 initial에 대한 의미는 없습니다 .
이것이 data.table 인 경우 :
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
이렇게하면 다음 내용이 무엇인지 알 수 있습니다 .SD
.
DT[ , .SD[ , paste(x, v, sep="", collapse="_")], by=y]
# y V1
# 1: 1 a1_b3_c5
# 2: 3 a2_b4_c6
기본적 by=y
으로이 명령문은 원래 데이터를 표로 구분합니다.data.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
차례로 작동합니다.
둘 중 하나에서 작동하는 동안 data.table
nick-name / handle / symbol을 사용하여 현재 하위를 참조 할 수 있습니다 .SD
. 당신이 액세스하고라는 단일 data.table 작업 명령 줄에 앉아있는 것처럼 열에서 작동 할 수로 즉, 매우 편리합니다 .SD
여기에 제외 ..., data.table
모든 단일, 정에 그 작업을 수행합니다 data.table
의해 정의 키 조합을 사용하여 다시 "붙여 넣기"하고 결과를 한 번에 반환합니다 data.table
!
.SD
입니다 DT[,print(.SD),by=y]
.
DT[,print(.SD[,y]),by=y]
의 값에 액세스 할 수 있음을 나타냅니다 . 범위가 정해 지는 가치는 어디에서 왔습니까? b / c 현재 값 입니까? y
.SD
y
by
.SD[,y]
정기적 인 data.table
이후 있도록 부분 집합 y
의 열 아니다 .SD
는이 경우입니다 호출 한 환경에서 찾습니다 j
(의 환경 DT
쿼리) by
변수를 사용할 수 있습니다. 거기에서 찾을 수 없으면 부모와 부모 등을 일반적인 R 방식으로 찾습니다. (음료 상속 범위를 통해서도이 예제에서는 i
s 가 없기 때문에 사용되지 않습니다 ).
by=list(x,y,z)
의미 x
, y
그리고 z
사용할 수 있습니다 j
. 일반 액세스의 경우에도 마무리됩니다 .BY
. FAQ 2.10에 약간의 역사가 있지만, 명확성을 추가 할 수 있습니다 ?data.table
. 훌륭한 docu 도움은 매우 환영받을 것입니다. 프로젝트에 참여하고 직접 변경하고 싶다면 더 좋습니다.
이 답변이 얼마나 잘 수신되었으므로 여기에서 사용할 수있는 패키지 비 네트로 변환했습니다 .
이것이 얼마나 자주 발생 하는지를 감안할 때, 나는 위의 Josh O'Brien이 제공 한 유용한 답변을 넘어서서 조금 더 설명 할 필요가 있다고 생각합니다.
받는 사람 또한 S의 의 ubset D 일반적으로 인용 약어 ATA / 조쉬 만든, 나는 그것이 "바로 그"또는 "자기 참조"를 스탠드에 "S"를 고려하는 것도 도움이 생각 - .SD
가장 기본적인 모습 A의입니다 재귀 참조 받는 사람 data.table
자체 - 우리는 아래의 예에서 살펴 보 겠지만,이 함께 "쿼리"(추출 / 집합 / 등 사용하여 체인에 특히 도움이된다 [
). 특히,이 또한 수단이 .SD
있다 자체data.table
(이와 할당을 허용하지 않는다는 경고와 함께 :=
)를.
보다 간단한 사용법은 .SD
열 하위 설정에 사용됩니다 (예 : .SDcols
지정된 경우). 이 버전은 이해하기가 훨씬 간단하다고 생각하므로 먼저 아래에서 다루겠습니다. .SD
두 번째 사용법, 그룹화 시나리오 ( by =
또는 keyby =
지정시) 에 대한 해석은 개념적으로 약간 다릅니다 (핵심에서는 동일하지만 그룹화되지 않은 작업은 단지 한 그룹).
다음은 제가 자주 구현하는 예시적인 예와 사용법의 다른 예입니다.
데이터를 구성하지 않고보다 실제적인 느낌을주기 위해 다음에서 야구에 관한 데이터 세트를로드 해 보겠습니다 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
.SD
의 반사 특성에 대한 의미를 설명하기 .SD
위해 가장 기본적인 사용법을 고려하십시오.
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
즉 우리는 단지 반환 한 인 Pitching
즉,이 글을 쓰는 지나치게 자세한 방법이었다, Pitching
또는 Pitching[]
:
identical(Pitching, Pitching[ , .SD])
# [1] TRUE
서브 세트의 관점에서, .SD
그것은 단지 사소한 일 (설정 자체)이다, 여전히 데이터의 하위 집합입니다.
.SDcols
영향을 미치는 첫 번째 방법 은 인수 사용에 포함 된 열.SD
을 다음으로 제한하는 것입니다 ..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
이것은 단지 설명을위한 것이며 지루했습니다. 그러나 이러한 단순한 사용조차도 매우 유익하고 유비쿼터스 한 다양한 데이터 조작 작업에 적합합니다.
열 형식 변환은 munging 데이터의 삶의 사실입니다 -이 글을 쓰는 등, fwrite
자동으로 읽을 수 없습니다 Date
또는 POSIXct
열 및 전환 앞뒤로 사이에 character
/ factor
/ numeric
일반적이다. 우리는 사용할 수 .SD
와 .SDcols
같은 열 일괄 변환 그룹.
데이터 세트 character
에서와 같이 다음 열이 저장 Teams
되어 있습니다.
# 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
여기를 사용하여 혼란 스러우면 기본 R과 동일하다는 점에 유의하십시오 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
이 구문을 이해하기위한 열쇠는 리콜이다 data.table
(뿐만 아니라 바와 같이 data.frame
)가 고려 될 수있는 list
각각의 요소는 열이다 - 즉, sapply
/ lapply
적용되는 FUN
각 열 및 복귀 결과 sapply
/ lapply
보통 여기 (것이다 FUN == is.character
반환 logical
길이가 1이므로 sapply
벡터를 반환합니다).
이 열을 변환하는 구문 factor
은 매우 유사합니다. 간단히 :=
할당 연산자 를 추가하십시오.
Teams[ , (fkt) := lapply(.SD, factor), .SDcols = fkt]
RHS에 이름 을 할당하는 대신 R이이를 열 이름으로 해석하도록 하려면 fkt
괄호 ()
로 묶어야 합니다 fkt
.
의 유연성 .SDcols
(과 :=
)를 수용하는 character
벡터 또는integer
또한 열 이름의 패턴 기반의 변환에 유용하게 사용할 수있는 열 위치의 벡터를 *. 모든 factor
열을 character
다음으로 변환 할 수 있습니다 .
fkt_idx = which(sapply(Teams, is.factor))
Teams[ , (fkt_idx) := lapply(.SD, as.character), .SDcols = fkt_idx]
그리고 포함 된 모든 열 변환 team
가기 factor
:
team_idx = grep('team', names(Teams), value = TRUE)
Teams[ , (team_idx) := lapply(.SD, factor), .SDcols = team_idx]
** 와 같이 열 번호를 명시 적으로 사용하는 DT[ , (1) := rnorm(.N)]
것은 좋지 않으며 열 위치가 변경되면 시간이 지남에 따라 코드가 자동으로 손상 될 수 있습니다. 번호가 지정된 인덱스를 만들 때와 사용할 때의 순서를 현명하게 / 엄격하게 제어하지 않으면 숫자를 암시 적으로 사용하는 것이 위험 할 수 있습니다.
다양한 모델 사양은 강력한 통계 분석의 핵심 기능입니다. Pitching
표 에서 사용할 수있는 작은 공변량 세트를 사용하여 투수의 방어율 (실적 측정치, 성과 측정치)을 예측해 봅시다 . W
(승리) 의 (선형) 관계 ERA
는 사양에 포함 된 다른 공변량에 따라 어떻게 달라 집니까?
다음은 .SD
이 질문을 탐구 하는 힘을 활용하는 간단한 스크립트입니다 .
# 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)
계수는 항상 예상되는 부호를 갖습니다 (더 나은 투수는 더 많은 승을 가지며 더 적은 런을 허용하는 경향이 있습니다).
data.table
구문은 단순성과 견고성으로 아름답습니다. 구문은 x[i]
유연 개의 공통 서브 세트가 처리 접근법 - 때 i
A는 logical
벡터, x[i]
의 행만 반환 x
곳에 대응 i
이다 TRUE
; 경우 i
이고 다른data.table
A는 join
(은 USING, 일반 형태로 수행되는 key
중들 x
과 i
그렇지 않은 경우에는, on =
그 열에 일치하는 경우 지정된).
이것은 일반적으로 훌륭하지만 조건부 조인 을 수행하려는 경우에는 부족합니다 . 여기서 테이블 간의 관계의 정확한 특성은 하나 이상의 열에있는 행의 일부 특성에 따라 다릅니다.
이 예는 약간의 생각이지만 아이디어를 보여줍니다. 자세한 내용은 여기 ( 1 , 2 )를 참조하십시오.
목표는 각 팀에서 최고의 투수의 팀의 성과 (순위)를 기록 하는 열 team_performance
을 Pitching
테이블 에 추가하는 것입니다 (최소한 ERA로 측정 된, 6 개 이상의 기록 된 게임 중 투수 중).
# 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]
구문은 반환 nrow(y)
이유입니다, 값 .SD
의 오른쪽에 Teams[.SD]
의 RHS 때문에 ( :=
이 경우 필요한 nrow(Pitching[rank_in_team == 1])
값을.
.SD
작업종종 그룹 수준에서 데이터 에 대한 작업을 수행하려고 합니다 . 우리가 by =
(또는 keyby =
) 명시 할 때 , data.table
프로세스 j
가 수행 될 때 일어나는 일에 대한 정신적 모델 은 당신 data.table
이 많은 컴포넌트 서브로 나뉘어져 있다고 생각하는 것입니다 data.table
. 각각은 by
변수 의 단일 값에 해당합니다 :
이 경우, .SD
자연 배수 - 서브 이들 각각 의미 data.table
, S 한번에 하나씩 (좀더 정확하게의 범위는 .SD
단일 서브이다 data.table
). 이것은 우리가 재 조립 된 결과가 우리에게 반환되기 전에 각 하위data.table
에서 수행하고자하는 작업을 간결하게 표현할 수있게합니다 .
이것은 다양한 설정에 유용하며 가장 일반적인 설정은 다음과 같습니다.
Lahman 데이터에서 각 팀에 대한 최신 데이터 시즌을 가져옵니다. 이것은 다음과 같이 간단하게 수행 할 수 있습니다.
# 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
자체이며 data.table
, 그것은 .N
그룹 (이 동등하게 행의 총 수를 의미 nrow(.SD)
하므로, 각 그룹 내에서) .SD[.N]
수익 의 전체가.SD
각각과 관련된 최종 행을 teamID
.
이것의 또 다른 일반적인 버전은 .SD[1L]
대신 각 그룹에 대한 첫 번째 관찰 을 얻기 위해 사용하는 것 입니다.
총 득점 횟수로 측정 한 각 팀 의 최고 연도 를 반환하려고한다고 가정 해 봅시다 ( R
물론 다른 지표를 참조하도록이를 쉽게 조정할 수 있음). 각 sub-에서 고정 요소를 가져 오는 대신 data.table
원하는 인덱스 를 다음과 같이 동적으로 정의합니다 .
Teams[ , .SD[which.max(R)], by = teamID]
이 접근법은 물론 각각 .SDcols
에 data.table
대한 부분만을 반환하기 위해 결합 될 수 있습니다 .SD
( .SDcols
다양한 부분 집합에 걸쳐 고정되어야 하는 경고와 함께 )
NB는 : .SD[1L]
현재에 의해 최적화되어 있습니다 GForce
( 참조 ) data.table
대규모 같은 가장 일반적인 분류 작업 속도 내부 sum
또는 mean
- 참조 ?GForce
: 자세한 내용은이 전면에 업데이트 기능 개선 요청에 / 음성 지원을 주시 1 , 2 , 3 , 4 , 5 , 6
사이의 관계에 관한 위의 질문에 반환 ERA
하고 W
, 우리는이 관계가 팀에 의해 다른 것으로 기대 가정 (즉, 각 팀에 대해 서로 다른 기울기있다). 이 회귀 분석을 쉽게 다시 실행하여 다음과 같이이 관계의 이질성을 탐색 할 수 있습니다 (이 접근 방식의 표준 오류가 일반적으로 올바르지 않음-사양 ERA ~ W*teamID
이 더 우수함-이 접근 방식이 읽기 쉽고 계수 가 정상 임) :
# 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')]
상당한 양의 이질성이 있지만 관찰 된 전체 값 주위에 뚜렷한 농도가 있습니다.
잘만되면 이것은 .SD
아름답고 효율적인 코드를 용이하게 하는 힘을 설명 했습니다 data.table
!
.SD에 대해 Matt Dowle과 이야기 한 후 이것에 대한 비디오를 만들었습니다 .YouTube에서 볼 수 있습니다 : https://www.youtube.com/watch?v=DwEzQuYfMsI
?data.table
이 질문으로 v1.7.10에서 개선되었습니다. 이제.SD
허용 된 답변에 따라 이름 을 설명합니다 .