2014-02-10 5 views
0

나는 열이 정확히 같은 34 개의 열이있는 두 개의 데이터 테이블을 가지고 있습니다.Data.table 루프 효율성

Month SpId1 SpId2 ... SpId33 

편집 : 여기에서 SPID는 종 식별자 Reproducible Example

AltSuitSp1 <- data.table(structure(list(Month = structure(c(2L, 2L, 2L, 2L, 2L, 2L, 2L,12L, 12L, 12L), .Label = c("1", "10", "11", "12", "2", "3", "4","5", "6", "7", "8", "9"), class = "factor"), SpdSpSuit = c(0,0, 0, 0, 0, 0, 0, 0, 0, 0), SpdIncSuit = c(0, 0, 0,0, 0, 0, 0, 0, 0, 0), SpdGrowSuit = c(0.4625, 0.4625, 0.4625, 0.4625, 0.4625, 0.4625, 0.4625,0.4625, 0.4625, 0.4625), RzbSpSuit = c(0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333,0.283333333, 0.283333333, 0.283333333, 0.283333333), RzbIncSuit = c(0.34,0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34), RzbGrowSuit = c(0.283333333,0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333), FMSSpSuit = c(0.34,0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34), FMSIncSuit = c(0.425, 0.425, 0.425, 0.425, 0.425, 0.425, 0.425, 0.425, 0.425, 0.425), FMSGrowSuit = c(0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333), BhsSpSuit = c(0.283333333,0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.233333333, 0.233333333, 0.233333333), BhsIncSuit = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), BhsGrowSuit = c(0.283333333,0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.283333333, 0.233333333, 0.233333333, 0.233333333), BrtSpSuit = c(0.866666667,0.866666667, 0.866666667, 0.866666667, 0.866666667, 0.866666667,0.866666667, 0.54, 0.54, 0.54), BrtIncSuit = c(0.8, 0.8, 0.8, 0.8, 0.8,0.8, 0.8, 0.43, 0.43, 0.43), BrtGrSuit = c(0.8, 0.8, 0.8, 0.8, 0.8, 0.8,0.8, 0.86, 0.86, 0.86), CcfSpSuit = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), CcfIncSuit = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0),CcfGrSuit = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), GsfSpSuit = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), GsfIncSuit = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), GsfGrSuit = c(0, 0, 0, 0, 0,0, 0, 0, 0, 0), RbtSpSuit = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), RbtIncSuit = c(0, 0, 0, 0, 0, 0, 0, 0, 0,0), RbtGrSuit = c(0.95, 0.95, 0.95, 0.95, 0.95, 0.95, 0.95, 0.925, 0.925, 0.925), SmbSpSuit = c(0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.675, 0.675,0.675), SmbIncSuit = c(0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.766666667,0.766666667, 0.766666667), SmbGrSuit = c(0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.0875, 0.0875, 0.0875), StbSpSuit = c(0.425, 0.425, 0.425, 0.425, 0.425, 0.425, 0.425, 0.425, 0.425, 0.425), StbIncSuit = c(0, 0,0, 0, 0, 0, 0, 0, 0, 0), StbGrSuit = c(0, 0, 0, 0, 0,0, 0, 0, 0, 0), HbcSpSuit = c(0, 0, 0, 0, 0, 0, 0,0, 0, 0), HbcIncSuit = c(0, 0, 0, 0, 0, 0, 0, 0, 0,0), HbcGrSuit = c(0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.425, 0.425, 0.425)), .Names = c("Month", "SpdSpSuit", "SpdIncSuit", "SpdGrowSuit","RzbSpSuit", "RzbIncSuit", "RzbGrowSuit", "FMSSpSuit", "FMSIncSuit","FMSGrowSuit", "BhsSpSuit", "BhsIncSuit", "BhsGrowSuit", "BrtSpSuit","BrtIncSuit", "BrtGrSuit", "CcfSpSuit", "CcfIncSuit", "CcfGrSuit","GsfSpSuit", "GsfIncSuit", "GsfGrSuit", "RbtSpSuit", "RbtIncSuit","RbtGrSuit", "SmbSpSuit", "SmbIncSuit", "SmbGrSuit", "StbSpSuit","StbIncSuit", "StbGrSuit", "HbcSpSuit", "HbcIncSuit", "HbcGrSuit"), class = c("data.table", "data.frame"), row.names = c(NA, -10L))) 

AltSuitDates <- data.table(structure(list(Month = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 10L, 11L,12L), SpdSpT = c(NA, NA, NA, NA, NA, 1L, 1L, NA, NA, NA), SpdIncT = c(NA,NA, NA, NA, NA, 1L, 1L, NA, NA, NA), SpdGrT = c(1L, 1L, 1L, 1L,1L, 1L, 1L, 1L, 1L, 1L), RzbSpT = c(NA, NA, NA, 1L, 1L, 1L, NA,NA, NA, NA), RzbIncT = c(NA, NA, NA, 1L, 1L, 1L, NA, NA, NA,NA), RzbGrT = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), FmsSpT = c(NA,NA, 1L, 1L, NA, NA, NA, NA, NA, NA), FmsIncT = c(NA, NA, 1L,1L, 1L, NA, NA, NA, NA, NA), FMSGrT = c(1L, 1L, 1L, 1L, 1L, 1L,1L, 1L, 1L, 1L), BhsSpT = c(NA, NA, NA, 1L, 1L, 1L, NA, NA, NA,NA), BhsIncT = c(NA, NA, NA, 1L, 1L, 1L, NA, NA, NA, NA), BhsGrT = c(1L,1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), BRTsp = c(1L, 1L, 1L, NA,NA, NA, NA, 1L, 1L, 1L), BRTinc = c(1L, 1L, 1L, 1L, NA, NA, NA,1L, 1L, 1L), BRTgr = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), CCFsp = c(NA, NA, NA, NA, 1L, 1L, 1L, NA, NA, NA), CCFinc = c(NA,NA, NA, NA, 1L, 1L, 1L, NA, NA, NA), CCFgr = c(1L, 1L, 1L, 1L,1L, 1L, 1L, 1L, 1L, 1L), GSFsp = c(NA, NA, NA, NA, 1L, 1L, 1L,NA, NA, NA), GSFinc = c(NA, NA, NA, NA, 1L, 1L, 1L, NA, NA, NA), GSFgr = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), RBTsp = c(1L,1L, 1L, 1L, 1L, 1L, 1L, NA, NA, NA), RBTinc = c(1L, 1L, 1L, 1L,1L, 1L, 1L, NA, NA, NA), RBTgr = c(1L, 1L, 1L, 1L, 1L, 1L, 1L,1L, 1L, 1L), SMBsp = c(NA, NA, NA, 1L, 1L, 1L, 1L, NA, NA, NA), SMBinc = c(NA, NA, NA, 1L, 1L, 1L, 1L, NA, NA, NA), SMBgr = c(1L,1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), STBsp = c(NA, NA, NA, NA,NA, 1L, 1L, NA, NA, NA), STBinc = c(NA, NA, NA, NA, NA, 1L, 1L,NA, NA, NA), STBgr = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), HBCsp = c(NA, NA, NA, 1L, 1L, 1L, NA, NA, NA, NA), HBCinc = c(NA,NA, NA, 1L, 1L, 1L, NA, NA, NA, NA), HBCgr = c(1L, 1L, 1L, 1L,1L, 1L, 1L, 1L, 1L, 1L)), .Names = c("Month", "SpdSpT", "SpdIncT","SpdGrT", "RzbSpT", "RzbIncT", "RzbGrT", "FmsSpT", "FmsIncT","FMSGrT", "BhsSpT", "BhsIncT", "BhsGrT", "BRTsp", "BRTinc", "BRTgr","CCFsp", "CCFinc", "CCFgr", "GSFsp", "GSFinc", "GSFgr", "RBTsp","RBTinc", "RBTgr", "SMBsp", "SMBinc", "SMBgr", "STBsp", "STBinc","STBgr", "HBCsp", "HBCinc", "HBCgr"), class = c("data.table","data.frame"), row.names = c(NA, -10L))) 

에서 재현 기능을 이용하여 샘플 데이터이다. 하나의 DT는 5 백만 행 (AltSuitSp1)이고 다른 DT는 12 (AltSuitDates)입니다. 큰 DT를 업데이트하기 위해 12 행 (12 개월에 해당) 인 DT를 사용하고 있습니다. for 루프의 구조는 상태를 확인하고 더 큰 DT 기반으로 작은 DT를 업데이트 할 경우 현재 내가 다른, 경우 중첩을 사용하고

h <- 1 
n <- length(AltSuitSp1[,Month]) 
stm <- AltSuitSp1[,Month] # AltSuitSp1 is the 5+ million row DT 

cond1 <- which(stm == 1) # list of all rows of AltSuitSp1 where the Month is = 1 
cond2 <- which(stm == 2) # list of all rows of AltSuitSp1 where the Month is = 2 
... 
cond12 <- which(stm == 12) 

for (h in seq(n)){ 
    if (any(cond1 == h)){ 
     set(AltSuitSp1,h,2:34,(AltSuitSp1[h,2:34,with=F] * AltSuitDates[1,2:34,with=F])) 
    }else if (any(cond2 == h)){ 
     set(AltSuitSp1,h,2:34,(AltSuitSp1[h,2:34,with=F] * AltSuitDates[2,2:34,with=F])) 
    }else if ... 
    }else if (any(cond12)){ 
     set(AltSuitSp1,h,2:34,(AltSuitSp1[h,2:34,with=F] * AltSuitDates[12,2:34,with=F])) 
    }else 
     break 
} 

는 지금, 나는 1이 코드를 실행 한 (아래 코드 참조) 그리고 얼마나 멀리 나아 갔는지 확인했습니다. 현재 저는 약 29-30 개의 루프를 보았고 h는 약 1800 개의 반복으로 나아갔습니다. 그러나 초당 30 회 루프 (다소 느림 : Using Set in DT) 일지라도이 코드는 완료하는 데 약 2 일이 소요됩니다. 그러나 아래 출력이 보여 주듯이, 내가 원하는/기대하는대로하고 있습니다.

AltSuitSp1Results <- data.table(structure(list(Month = structure(c(2L, 2L, 2L, 2L, 2L, 2L, 2L,12L, 12L, 12L), .Label = c("1", "10", "11", "12", "2", "3", "4","5", "6", "7", "8", "9"), class = "factor"), SpdSpSuit = c(NA,NA, NA, NA, NA, NA, NA, 0, 0, 0), SpdIncSuit = c(NA, NA, NA,NA, NA, NA, NA, 0, 0, 0), SpdGrowSuit = c(0, 0, 0, 0, 0, 0, 0,0.4625, 0.4625, 0.4625), RzbSpSuit = c(NA, NA, NA, NA, NA, NA,NA, 0.283333333, 0.283333333, 0.283333333), RzbIncSuit = c(NA,NA, NA, NA, NA, NA, NA, 0.34, 0.34, 0.34), RzbGrowSuit = c(0,0, 0, 0, 0, 0, 0, 0.283333333, 0.283333333, 0.283333333), FMSSpSuit = c(NA,NA, NA, NA, NA, NA, NA, 0.34, 0.34, 0.34), FMSIncSuit = c(NA,NA, NA, NA, NA, NA, NA, 0.425, 0.425, 0.425), FMSGrowSuit = c(0,0, 0, 0, 0, 0, 0, 0.283333333, 0.283333333, 0.283333333), BhsSpSuit = c(NA,NA, NA, NA, NA, NA, NA, 0.233333333, 0.233333333, 0.233333333), BhsIncSuit = c(NA, NA, NA, NA, NA, NA, NA, 0, 0, 0), BhsGrowSuit = c(0,0, 0, 0, 0, 0, 0, 0.233333333, 0.233333333, 0.233333333), BrtSpSuit = c(0.866666667,0.866666667, 0.866666667, 0.866666667, 0.866666667, 0.866666667,0.866666667, 0, 0, 0), BrtIncSuit = c(0.8, 0.8, 0.8, 0.8, 0.8,0.8, 0.8, 0.43, 0.43, 0.43), BrtGrSuit = c(0, 0, 0, 0, 0, 0,0, 0.86, 0.86, 0.86), CcfSpSuit = c(NA, NA, NA, NA, NA, NA, NA,0, 0, 0), CcfIncSuit = c(NA, NA, NA, NA, NA, NA, NA, 0, 0, 0),CcfGrSuit = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), GsfSpSuit = c(NA,NA, NA, NA, NA, NA, NA, 0, 0, 0), GsfIncSuit = c(NA, NA,NA, NA, NA, NA, NA, 0, 0, 0), GsfGrSuit = c(0, 0, 0, 0, 0,0, 0, 0, 0, 0), RbtSpSuit = c(NA, NA, NA, NA, NA, NA, NA,0, 0, 0), RbtIncSuit = c(NA, NA, NA, NA, NA, NA, NA, 0, 0,0), RbtGrSuit = c(0, 0, 0, 0, 0, 0, 0, 0.925, 0.925, 0.925), SmbSpSuit = c(NA, NA, NA, NA, NA, NA, NA, 0.675, 0.675,0.675), SmbIncSuit = c(NA, NA, NA, NA, NA, NA, NA, 0.766666667,0.766666667, 0.766666667), SmbGrSuit = c(0, 0, 0, 0, 0, 0,0, 0.0875, 0.0875, 0.0875), StbSpSuit = c(NA, NA, NA, NA,NA, NA, NA, 0.425, 0.425, 0.425), StbIncSuit = c(NA, NA,NA, NA, NA, NA, NA, 0, 0, 0), StbGrSuit = c(0, 0, 0, 0, 0,0, 0, 0, 0, 0), HbcSpSuit = c(NA, NA, NA, NA, NA, NA, NA,0, 0, 0), HbcIncSuit = c(NA, NA, NA, NA, NA, NA, NA, 0, 0,0), HbcGrSuit = c(0, 0, 0, 0, 0, 0, 0, 0.425, 0.425, 0.425)), .Names = c("Month", "SpdSpSuit", "SpdIncSuit", "SpdGrowSuit","RzbSpSuit", "RzbIncSuit", "RzbGrowSuit", "FMSSpSuit", "FMSIncSuit","FMSGrowSuit", "BhsSpSuit", "BhsIncSuit", "BhsGrowSuit", "BrtSpSuit","BrtIncSuit", "BrtGrSuit", "CcfSpSuit", "CcfIncSuit", "CcfGrSuit","GsfSpSuit", "GsfIncSuit", "GsfGrSuit", "RbtSpSuit", "RbtIncSuit","RbtGrSuit", "SmbSpSuit", "SmbIncSuit", "SmbGrSuit", "StbSpSuit","StbIncSuit", "StbGrSuit", "HbcSpSuit", "HbcIncSuit", "HbcGrSuit"), class = c("data.table", "data.frame"), row.names = c(NA, -10L))) 

분명히 나는 ​​효율적인 방법으로이 문제를 해결하지 못하고 일부 실수 프로그래밍을하고 있습니다. 그러나 나는 코드를 정확히 최적화 할 수있는 곳을 찾기 위해 고심하고있다. 내장 된 DT 기능을 재발 명하려고합니까 DT? 서클 중 하나에 있습니다. 내가 vectorize 할 수있는 곳을 놓쳤는가 : R Inferno?

기본적으로 AltSuitDate DT를 기준으로 AltSuitSp1 DT의 열 2:34를 업데이트해야합니다. AltSuitDates DT에서 AltSuitSp1을 업데이트 할 때 사용할 행을 아는 조건으로 월 열을 사용합니다. 어떤 도움을 주셔서 감사합니다.

+2

2 개의 데이터 테이블을 1로 병합하면 루프 할 필요가 없습니다. 예제 데이터가 없으면 그 이상은 말할 수 없습니다. –

+0

@DeanMacGregor, 예제 데이터를 포함하지 않으면 나를 9 번째 서클에 넣습니다! 예제 데이터를 포함시켜 주셔서 감사합니다. – duHaas

+0

@duHaas, dput을하기 전에 데이터를 as.data.frame 할 수 있습니까? 데이터 테이블'dputing '에 문제가 있다고 생각합니다. Altenatively 전에 코드를 시도하고 그것이 당신이 원하는 것을 확인하거나 그것이 왜 설명하지 않습니다. – BrodieG

답변

1

EDIT, 게시 된 데이터로 실행되도록 업데이트되었습니다.

이 작동합니다 :

AltSuitSp1$Month <- as.integer(levels(AltSuitSp1$Month))[AltSuitSp1$Month] 
setkey(AltSuitDates, Month) 
d.cols <- ncol(AltSuitDates) - 1L 
AltSuitDates[AltSuitSp1, ][, 
    c(list(Month=Month), 
    mapply(
    `*`, 
    .SD[, 2:(d.cols + 1), with=F], 
    .SD[, (d.cols + 2):(2 * d.cols + 1), with=F], 
    SIMPLIFY=FALSE 
)) ] 

기본적으로, 당신은, 당신은 데이터 테이블 자신을 참조 특수 객체가, 인, .SD를 사용 Month (세 번째 줄)에 의해 두 개의 테이블을 조인하여 시작 AltSuitSp1의 첫 번째 행 집합과 AltSuitDates의 두 번째 집합 (이제는 모두 동일한 테이블에 있음)을 mapply으로 전달하여 함께 곱할 수 있습니다. 저는 여기에 사용되는 데이터이다

library(data.table) 
set.seed(1) 
AltSuitSp1 <- do.call(rbind, replicate(3, data.table(Month=1:12, a=runif(12), b=runif(12), c=runif(12)), s=F)) 
AltSuitDates <- data.table(Month=1:12, a=runif(12, 5, 10), b=runif(12, 5, 10), c=runif(12, 5, 10)) 
0

@ BrodieG의 의견에 본사를 둔이, 이것은 SP2에서 34 열을 수용하기 위해 재 작업되었습니다. 크기 (5e6 행, 34 열)의 데이터 세트에서 약 4 분 만에 실행됩니다.

기본 접근 방식은 한 번에 하나씩 SP1에 참조 열 (여기서는 Dates)을 추가하는 것입니다. 그런 다음 SP1의 해당 열을 업데이트 한 후 다음 열을 반복합니다. 이것은 메모리 측면에서 매우 효율적이며 (임의의 추가 열 1 개만) data.table의 참조 별 설정을 여전히 사용합니다.

library(data.table) 
set.seed(1) 
ncol <- 34 
nrow <- 5e6 
m <- matrix(sample(10000:99999,nrow*ncol,replace=T),ncol=ncol) 
SP1 <- data.table(Month=sample(1:12,nrow(m),replace=T),m) 
m <- matrix(sample(1:12,12*ncol,replace=T),ncol=ncol) 
SP2 <- data.table(Month=sample(1:12,12),m) 
cols <- paste0("SpId",(1:ncol(m))) 
setnames(SP1,2:(ncol(m)+1),cols) 
setnames(SP2,2:(ncol(m)+1),cols) 

system.time({ 
    setkey(SP1,"Month") 
    setkey(SP2,"Month") 
    lapply(1:ncol,function(i){ 
    setnames(SP2,cols[i],"Dates") # don't want colname collision in merge 
    SP1[SP2[,c("Month","Dates"),with=F],Dates:=Dates] 
    SP1[,cols[i]:=.SD[,cols[i],with=F]*Dates,with=F] 
    setnames(SP2,"Dates",cols[i]) # set it back so next iteration works 
    }) 
}) 
# user system elapsed 
# 219.54 22.45 242.59 
+0

이 질문에 대한 나의 해석에는 34 개의 데이터 열이있는 두 테이블이 있었으며, 쌍으로 일치해야합니다 (예 : SP1의 첫 번째 SP1과 첫 번째 SP2 등). 내가 제대로 이해한다면 네가하지 않는다. 내 생각에 추가적인 복잡성의 대부분은이를 다루고 있으며 다른 수의 열로도 작동하는 구조를 가지고 있다고 생각합니다. – BrodieG

+0

무슨 뜻인지 알 겠어. 이 문제를 해결하기 위해 답변을 변경했습니다. 당연히 이제는 ~ 34 * 5 초가 걸립니다. – jlhoward

0

시도해보십시오. 나는 그것이 BrodieG 's와 유사하다고 생각하지만 BrodieG의 대답을 복사 할 때 그것은 나에게 효과가 없었고 내가 잘못한 것을 알아 내기 위해 mapply 부분을 읽는 법을 모른다. ....

comb<-merge(AltSuitSp1,AltSuitDates,by="Month") 
sp<-colnames(AltSuitSp1)[2:NCOL(AltSuitSp1)] 
dat<-colnames(AltSuitDates)[2:NCOL(AltSuitDates)] 
comb[,eval(parse(text=paste0("list(Month,",paste0(sp,"=",sp,"*",dat,collapse=","),")")))] 

내가 팔자 'eval(parse(text=은 일반적으로 좋은 연습으로 간주되지 않습니다 알고 있지만 당신이 모두는 나사가 나무에 갈 수 망치는 경우.