2016-09-24 3 views
1

에서 data.table와 스파 스 매트릭스는 내가 data.table 패키지 다음과 같은 질문 해결하기 위해 노력 : Is there a faster way to subset a sparse Matrix than '['?부분적인 R

을하지만 난이 오류를 얻을 : 다음은

Error in Z[, cols] : invalid or not-yet-implemented 'Matrix' subsetting 
10 stop("invalid or not-yet-implemented 'Matrix' subsetting") 
9 Z[, cols] 
8 Z[, cols] 
7 FUN(X[[i]], ...) 
6 lapply(X = ans[index], FUN = FUN, ...) 
5 tapply(.SD, INDEX = "gene_name", FUN = simple_fun, Z = Z, simplify = FALSE) 
4 eval(expr, envir, enclos) 
3 eval(jsub, SDenv, parent.frame()) 
2 `[.data.table`(lkupdt, , tapply(.SD, INDEX = "gene_name", FUN = simple_fun, 
Z = Z, simplify = FALSE), .SDcols = c("snps")) 
1 lkupdt[, tapply(.SD, INDEX = "gene_name", FUN = simple_fun, Z = Z, 
simplify = FALSE), .SDcols = c("snps")] 

을 내 솔루션 :

library(data.table) 
library(Matrix) 

seed(1) 

n_subjects <- 1e3 
n_snps <- 1e5 
sparcity <- 0.05 


n <- floor(n_subjects*n_snps*sparcity) 

# create our simulated data matrix 
Z <- Matrix(0, nrow = n_subjects, ncol = n_snps, sparse = TRUE) 
pos <- sample(1:(n_subjects*n_snps), size = n, replace = FALSE) 
vals <- rnorm(n) 
Z[pos] <- vals 

# create the data frame on how to split 
# real data set the grouping size is between 1 and ~1500 
n_splits <- 500 
sizes <- sample(2:20, size = n_splits, replace = TRUE) 
lkup <- data.frame(gene_name=rep(paste0("g", 1:n_splits), times = sizes), 
        snps = sample(n_snps, size = sum(sizes))) 

# simple function that gets called on the split 
# the real function creates a cols x cols dense upper triangular matrix 
# similar to a covariance matrix 
simple_fun <- function(Z, cols) {sum(Z[ , cols])} 

# split our matrix based look up table 
system.time(
    res <- tapply(lkup[ , "snps"], lkup[ , "gene_name"], FUN=simple_fun, Z=Z, simplify = FALSE) 
) 
lkupdt <- data.table(lkup) 
lkupdt[, tapply(.SD, INDEX = 'gene_name' , FUN = simple_fun, Z = Z, simplify = FALSE), .SDcols = c('snps')] 

위의 함수를 "res"에 저장하려고하는 마지막 줄에 대한 질문입니다. data.table에 문제가 있습니까? 아니면 간단하지 않습니까? 당신의 도움을 주셔서 감사합니다!

답변

1

아니요, 저는 data.table을 사용하여 Matrix 객체에 액세스하는 속도를 높일 수 있다고 생각하지 않습니다. 당신이 ... 행렬 대신 data.table를 사용하고자하는 경우,

ZDT = setDT(summary(Z)) 
system.time(
    resDT <- ZDT[lkupdt, on = c(j = "snps")][, sum(x), by=gene_name] 
) 

# verify correctness 
all.equal(
    unname(unlist(res))[order(as.numeric(substring(names(res), 2, nchar(names(res)))))], 
    resDT$V1 
) 

그것은 물론

 gene_name   V1 
    1:  g1 3.720619 
    2:  g2 35.727923 
    3:  g3 -3.949385 
    4:  g4 -18.253456 
    5:  g5 5.970879 
---      
496:  g496 -20.979669 
497:  g497 63.880925 
498:  g498 16.498587 
499:  g499 -17.417110 
500:  g500 45.169608 

같은 결과를 제공, 당신은에서 데이터를 유지해야 할 수 있습니다 다른 이유 때문에 매트릭스가 희박하지만 컴퓨터에서 훨씬 빠르며 입력과 출력이 더 간단합니다.

0

생각해 보면 sum()은 시간을 예측하기에는 너무 간단하고 더 현실적인 경우 function을 표시 할 때 더 적합한 대답을 얻을 것이라고 생각합니다. 이 function은 (물론,이 방법은 복잡 function 사용할 수없는)이 접근 data.table() 같거나 빠른 보이는 예

(I는 data.table()없이 접근);

sum.func <- function(Z, lkup) { 
    Zsum <- colSums(Z)[lkup$snps] 
    Z2 <- cbind(Zsum, lkup$gene_name) 
    res <- c(tapply(Z2[,1], Z2[,2], sum)) 
    names(res) <- levels(lkup$gene_name) 
    return(c(res)) 
} 

system.time(
    test.res <- sum.func(Z, lkup) 
) 

all.equal(unlist(res), test.res) 

이것은 더 일반적이지만 data.table() 접근보다 분명히 느립니다.

general.fun <- function(Z, lkup) { 
    Z2 <- Z[, lkup$snps] 
    num.gn <- as.numeric(lkup$gene_name) 
    res <- sapply(1:max(num.gn), function(x) sum(Z2[, which(num.gn == x)])) 
    names(res) <- levels(lkup$gene_name) 
    return(res) 
} 

system.time(
    test.res2 <- general.fun(Z, lkup) 
) 

all.equal(unlist(res), test.res2)