.SD는 R에서 data.table의 약자


173

.SD유용 해 보이지만 실제로 무엇을하고 있는지 모르겠습니다. 그것은 무엇을 의미합니까? 왜 앞의 기간이 있습니까? 사용하면 어떻게 되나요?

I는 읽어 .SDdata.table들의 서브셋 함유 x그룹 열 (들)을 제외한 각 군의 데이터. 로 그룹화 할 때,로 그룹화 i할 때 by, 키 by및 _ad hoc_를 사용할 수 있습니다.by

그것은 딸 data.table이 다음 수술을 위해 기억에 유지 된다는 것을 의미합니까 ?


30
?data.table이 질문으로 v1.7.10에서 개선되었습니다. 이제 .SD허용 된 답변에 따라 이름 을 설명합니다 .
매트 Dowle

답변:


205

.SD" Sata.table의 Dubset" 과 같은 것을 의미합니다 . "."사용자 정의 열 이름과의 충돌이 발생할 가능성이 더 낮다는 점을 제외하고 는 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.tablenick-name / handle / symbol을 사용하여 현재 하위를 참조 할 수 있습니다 .SD. 당신이 액세스하고라는 단일 data.table 작업 명령 줄에 앉아있는 것처럼 열에서 작동 할 수로 즉, 매우 편리합니다 .SD여기에 제외 ..., data.table모든 단일, 정에 그 작업을 수행합니다 data.table의해 정의 키 조합을 사용하여 다시 "붙여 넣기"하고 결과를 한 번에 반환합니다 data.table!


12
예, 정확히 보는 또 다른 방법은 .SD입니다 DT[,print(.SD),by=y].
Matt Dowle

6
@ MatthewDowle-당신이 여기있는 동안, 당신을 위해 질문. Doing은의 일부가 아니지만 DT[,print(.SD[,y]),by=y]의 값에 액세스 할 수 있음을 나타냅니다 . 범위가 정해 지는 가치는 어디에서 왔습니까? b / c 현재 값 입니까? y.SDyby
Josh O'Brien

8
@ 조쉬 니스. 예. 는 .SD[,y]정기적 인 data.table이후 있도록 부분 집합 y의 열 아니다 .SD는이 경우입니다 호출 한 환경에서 찾습니다 j(의 환경 DT쿼리) by변수를 사용할 수 있습니다. 거기에서 찾을 수 없으면 부모와 부모 등을 일반적인 R 방식으로 찾습니다. (음료 상속 범위를 통해서도이 예제에서는 is 가 없기 때문에 사용되지 않습니다 ).
Matt Dowle

1
@Josh FAQ 2.8에 더 많은 내용이 있으므로 개선이 필요할 수 있습니다 (제안을 환영합니다).
Matt Dowle

3
@Josh 그룹 변수도 J에서 사용할 수 있으며, 길이 1이기 때문에 by=list(x,y,z)의미 x, y그리고 z사용할 수 있습니다 j. 일반 액세스의 경우에도 마무리됩니다 .BY. FAQ 2.10에 약간의 역사가 있지만, 명확성을 추가 할 수 있습니다 ?data.table. 훌륭한 docu 도움은 매우 환영받을 것입니다. 프로젝트에 참여하고 직접 변경하고 싶다면 더 좋습니다.
Matt Dowle

98

편집하다:

이 답변이 얼마나 잘 수신되었으므로 여기에서 사용할 수있는 패키지 비 네트로 변환했습니다 .


이것이 얼마나 자주 발생 하는지를 감안할 때, 나는 위의 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)]것은 좋지 않으며 열 위치가 변경되면 시간이 지남에 따라 코드가 자동으로 손상 될 수 있습니다. 번호가 지정된 인덱스를 만들 때와 사용할 때의 순서를 현명하게 / 엄격하게 제어하지 않으면 숫자를 암시 적으로 사용하는 것이 위험 할 수 있습니다.

모델의 RHS 제어

다양한 모델 사양은 강력한 통계 분석의 핵심 기능입니다. 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)

W, 다양한 사양에 맞는 OLS 계수

계수는 항상 예상되는 부호를 갖습니다 (더 나은 투수는 더 많은 승을 가지며 더 적은 런을 허용하는 경향이 있습니다).

조건부 조인

data.table구문은 단순성과 견고성으로 아름답습니다. 구문은 x[i]유연 개의 공통 서브 세트가 처리 접근법 - 때 iA는 logical벡터, x[i]의 행만 반환 x곳에 대응 i이다 TRUE; 경우 i이고 다른data.table A는 join(은 USING, 일반 형태로 수행되는 key중들 xi그렇지 않은 경우에는, on =그 열에 일치하는 경우 지정된).

이것은 일반적으로 훌륭하지만 조건부 조인 을 수행하려는 경우에는 부족합니다 . 여기서 테이블 간의 관계의 정확한 특성은 하나 이상의 열에있는 행의 일부 특성에 따라 다릅니다.

이 예는 약간의 생각이지만 아이디어를 보여줍니다. 자세한 내용은 여기 ( 1 , 2 )를 참조하십시오.

목표는 각 팀에서 최고의 투수의 팀의 성과 (순위)를 기록 하는 열 team_performancePitching테이블 에 추가하는 것입니다 (최소한 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]

이 접근법은 물론 각각 .SDcolsdata.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!


5
좋은 설명입니다. 한 가지 의견 : Teams [, .SD [which.max (R)], by = teamID] 대신 Teams [order (teamID, -R), .SD [ 1L], keyby = teamID]보다 빠릅니다.
bartleby

@ bartleby 덕분에 실제로 이것은 정확하지만 일반적인 접근 방식은 여전히 ​​유용합니다-예를 들어 그룹 종속 수량으로 주문 해야하는 경우. 아마 나는 예제를 바꿀 것이다.
MichaelChirico

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.