1 data.table
먼저 더 일반적인 하나 질문에 t
의 이상한 구조를 대체 이전 행 perm
은 C 열 (nc + 1 : n)과 PC 열 (nc + n + 1 : n)의 열 번호를 다시 배열하는 데 사용되는 순열 벡터입니다.
nc <- ncol(t) # 3
n <- t[, max(V1, V2)] # 5
Cnames <- paste0("C", 1:n)
PCnames <- paste0("PC", 1:n)
perm <- c(1:nc, rbind(nc + 1:n, nc + n + 1:n))
t[, (Cnames) := as.list(tabulate(c(V1, V2), n)), by = 1:nrow(t)][,
(Cnames):=lapply(.SD, function(x) cumsum(x) - x), .SDcol=Cnames][,
(PCnames):=lapply(.SD, function(x) x/seq(0,len=.N,by=nc-1)), .SDcols=Cnames][,
perm, with = FALSE]
마지막 줄은 제공 :
Date V1 V2 C1 PC1 C2 PC2 C3 PC3 C4 PC4 C5 PC5
1: 2013-05-04 4 2 0 NaN 0 NaN 0 NaN 0 NaN 0 NaN
2: 2013-05-09 2 5 0 0 1 0.5 0 0.0000000 1 0.5000000 0 0.0000000
3: 2013-05-16 3 2 0 0 2 0.5 0 0.0000000 1 0.2500000 1 0.2500000
4: 2013-05-30 1 4 0 0 3 0.5 1 0.1666667 1 0.1666667 1 0.1666667
1a.data.table 대안
만약 그 존재하기 때문에 매우 유용하지 않습니다 첫 데이트의 행 (생략하려면 '확인' 첫 번째 날짜 이전의 날짜가없는 경우) 다음 지루하고 직선적 인 자체 조인을 수행 할 수 있습니다.
t <- data.table(
Date = as.Date(c("2013-5-4", "2013-5-9", "2013-5-16", "2013-5-30")),
V1 = c(4, 2, 3, 1),
V2 = c(2, 5, 2, 4)
)
tt <- t[, one := 1]
setkey(tt, one)
tt[tt,,allow.cartesian=TRUE][Date > Date.1, list(
C1 = sum(.SD == 1), PC1 = mean(.SD == 1),
C2 = sum(.SD == 2), PC2 = mean(.SD == 2),
C3 = sum(.SD == 3), PC3 = mean(.SD == 3),
C4 = sum(.SD == 4), PC4 = mean(.SD == 4),
C5 = sum(.SD == 5), PC5 = mean(.SD == 5)
), by = list(Date, V1, V2), .SDcols = c("V1.1", "V2.1")]
1b. data.table 대안
아니면이 같은보다 콤팩트 1A를 다시 쓸 수있다 (tt
, n
, Cnames
및 PCnames
위에서부터 어디)
tt[tt,,allow.cartesian=TRUE][Date > Date.1, setNames(as.list(rbind(
sapply(1:n, function(i, .SD) sum(.SD==i), .SD=.SD),
sapply(1:n, function(i, .SD) mean(.SD==i), .SD=.SD)
)), c(rbind(Cnames, PCnames))),
by = list(Date, V1, V2), .SDcols = c("V1.1", "V2.1")]
2 sqldf
대안 data.table에이 비슷하고 지루하고 직선적 인 자체 조인으로 SQL을 사용하는 것입니다 :
library(sqldf)
sqldf("select a.Date, a.V1, a.V2,
sum(((b.V1 = 1) + (b.V2 = 1)) * (a.Date > b.Date)) C1,
sum(((b.V1 = 1) + (b.V2 = 1)) * (a.Date > b.Date))/
cast (2 * count(*) - 2 as real) PC1,
sum(((b.V1 = 2) + (b.V2 = 2)) * (a.Date > b.Date)) C2,
sum(((b.V1 = 2) + (b.V2 = 2)) * (a.Date > b.Date))/
cast (2 * count(*) - 2 as real) PC2,
sum(((b.V1 = 3) + (b.V2 = 3)) * (a.Date > b.Date)) C3,
sum(((b.V1 = 3) + (b.V2 = 3)) * (a.Date > b.Date))/
cast (2 * count(*) - 2 as real) PC3,
sum(((b.V1 = 4) + (b.V2 = 4)) * (a.Date > b.Date)) C4,
sum(((b.V1 = 4) + (b.V2 = 4)) * (a.Date > b.Date))/
cast (2 * count(*) - 2 as real) PC4,
sum(((b.V1 = 5) + (b.V2 = 5)) * (a.Date > b.Date)) C5,
sum(((b.V1 = 5) + (b.V2 = 5)) * (a.Date > b.Date))/
cast (2 * count(*) - 2 as real) PC5
from t a, t b where a.Date >= b.Date
group by a.Date")
2a. 대안
sqldf 대안은 다음과 같이 위의 SQL 문자열을 생성하는 문자열 조작을 사용하는 것입니다 :
f <- function(i) {
s <- fn$identity("sum(((b.V1 = $i) + (b.V2 = $i)) * (a.Date > b.Date))")
fn$identity("$s C$i,\n $s /\ncast (2 * count(*) - 2 as real) PC$i")
}
s <- fn$identity("select a.Date, a.V1, a.V2, `toString(sapply(1:5, f))`
from t a, t b where a.Date >= b.Date
group by a.Date")
sqldf(s)
2B. 두 번째 sqldf 대안
첫 번째 날짜에 출력 행을 사용하지 않고 SQL 솔루션을 단순화 할 수 있습니다. 첫 데이트 등이 할 수 감각은 더 이전 날짜가 집계되지합니다 :
sqldf("select a.Date, a.V1, a.V2,
sum((b.V1 = 1) + (b.V2 = 1)) C1,
avg((b.V1 = 1) + (b.V2 = 1)) PC1,
sum((b.V1 = 2) + (b.V2 = 2)) C2,
avg((b.V1 = 2) + (b.V2 = 2)) PC2,
sum((b.V1 = 3) + (b.V2 = 3)) C3,
avg((b.V1 = 3) + (b.V2 = 3)) PC3,
sum((b.V1 = 4) + (b.V2 = 4)) C4,
avg((b.V1 = 4) + (b.V2 = 4)) PC4,
sum((b.V1 = 5) + (b.V2 = 5)) C5,
avg((b.V1 = 5) + (b.V2 = 5)) PC5
from t a, t b where a.Date > b.Date
group by a.Date")
다시는 이전의 솔루션에서와 동일한 방식으로 repitition을 방지하기 위해 SQL 문자열을 만들 수있을 것이다.
UPDATE : 추가 PC 열 및 일부 단순화
업데이트 2 : 내 최초의 솔루션에 사용되는 어떤 용액에 추가 솔루션
새 원본 데이터와 새 분석 데이터를 함께 제공하므로 초기 솔루션을 좋아합니다. 비록 첫 번째 행이 쓰레기 일지라도). 나는 '현재'행과 '이후'('before'가 아님)의 모든 행을 어떻게 고려하는지 이해하기 위해 노력하고 있습니다. 첫 번째 해결 방법은 여러 계층의 과제, 흥미로운 접근 방법을 연습합니다. – eAndy