JOFC on CxP data ======================================================== ### YP, MT, JV, CEP, ... `r date()` Goal ---- The long term goal is to discover structure that is meaningful in terms of treatment outcomes. Data ----- 1. **C**-data ([time_series_cc200_20130402](./Data/time_series_cc200_20130402)): **C** is for *connectome*, which just refers, in this case, to the fMRI data. The 197 regions are obtained from the 'all voxel' data via parsing voxels into regions. We already know the function relating the 197 to the all voxels case, because we wrote it. It is in the form of $(region=197)\times (time=194)\times (subj=42)$. Unfortunately, the time-series across subjects are *not* aligned relative to one another. 2. **P**-data ([NEO2012.csv](./Data/NEO2012.csv)): **P** is short for *phenotype*, in this case, it is the 5 factor model ($(subj=42)\times (factor=5)$), which are the 5 factors: ENOAC (sometimes ordered differently and called OCEAN). Supplements ----------- 1. [NEO2012.csv](./Data/NEO2012.csv) has 42 subjects and the following columns: ParticipantID,Sex,Age,E,N,O,A,C the last 5 are the "5 factors" 2. [NEO2012_linkage.csv](./Data/NEO2012_linkage.csv) has 42 subjects and 2 columns: the first is the ParticipantID, which is listed in the other file, the second is the file name. so it maps participant id to file, which we need. 3. _ScaledScales.xls_: this is the file that had the original data that i extracted *NEO2012.csv* from. you shouldn't need it, but it is the raw data, so i didn't want to discard it. ```{r,echo=FALSE,eval=TRUE,warning=FALSE,message=FALSE} #utils::globalVariables(c("scales", "obj2")) suppressMessages(require(knitr,quietly=TRUE)) suppressMessages(require(mclust,quietly=TRUE)) suppressMessages(require(jhusmacof,quietly=TRUE)) suppressMessages(require(Matrix,quietly=TRUE)) suppressMessages(require(parallel,quietly=TRUE)) suppressMessages(require(foreach,quietly=TRUE)) suppressMessages(require(doMC,quietly=TRUE)) suppressMessages(require(ggplot2,quietly=TRUE)) suppressMessages(require(reshape2,quietly=TRUE)) registerDoMC(cores=detectCores()-1) #library(IM,silent=TRUE) source("cgputils.r") source("~/RFolder/fastoos.R") source("~/RFolder/oosIM.R") opts_chunk$set(cache=TRUE,echo=FALSE,warning=FALSE,message=FALSE,comment="#",tidy=FALSE, fig.width=6,fig.height=6,fig.path='Figure/cgp-',dpi=72) hook_output <- knit_hooks$get('output') knit_hooks$set(output = function(x, options) { # this hook is used only when the linewidth option is not NULL if (!is.null(n <- options$linewidth)) { x = knitr:::split_lines(x) # any lines wider than n should be wrapped if (any(nchar(x) > n)) x = strwrap(x, width = n) x = paste(x, collapse = '\n') } hook_output(x, options) }) ``` ## *C* Data ```{r cdata, echo=TRUE, eval=FALSE} dname <- "http://www.cis.jhu.edu/~parky/CGP/Data/time_series_cc200_20130402/" urlfiles <- readHTMLTable(dname,skip.rows=1:2)[[1]]$V2 urlfiles <- urlfiles[!is.na(urlfiles)] files <- paste0(dname,urlfiles) (n <- length(files)) # 42 require(flexmix) coh <- ts <- spect <- spect_norm <- NULL for (i in 1:length(files)) { ts[[i]] <- readMat(files[i])[[1]] # 194 x 197 spect[[i]] <- spectrum(t(ts[[i]]))$spec[6:40,] # 100 (freq) x 194 => (bandpass) 35 x 194 spect_norm[[i]] <- scale(spect[[i]],center=FALSE,scale=colSums(spect[[i]])) # normalization coh[[i]] <- KLdiv(spect_norm[[i]]) # Delta: 194 x 194 } ``` ```{r dissmatata,echo=FALSE} load("outC.Rbin") attach(outC) plotmat(ts[[1]],"region","time","ts") ``` ### run spectrum (FFT) on ts for each region ```{r} spec <- spectrum(t(ts[[1]]))$spec plotmat(spec,"frequency","region","spec") ``` ### bandpass and normalize it ```{r} plotmat(spect[[1]],"frequency","region","bandpass(spec)") plotmat(spect_norm[[1]],"frequency","region","spect_norm") ``` ### calc KLdiv among regions ```{r} #dim(coh[[1]]) plotmat(coh[[1]],"region","region","KLdiv") ``` ### calc normalized Hellinger distance among subjects ```{r,echo=TRUE,eval=FALSE} dissmat <- matrix(0,n,n) for (i in 1:(n-1)) { for (j in (i+1):n) { dissmat[i,j] <- helldist(coh[[i]],coh[[j]]) # hellinger distance } } dissmat <- dissmat + t(dissmat) diag(dissmat) <- 0 distC <- normalize(dissmat) ``` ```{r plotC,echo=FALSE} distC <- normalize(dissmat) dim(distC) plotmat(distC,"subject","subject","Hellinger") hist(distC) ``` ### embed and cluster it ```{r,echo=TRUE,eval=TRUE} n <- nrow(distC) mdsC <- cmdscale(distC,n-1) elbowC <- getElbows(mdsC,3) mcC <- Mclust(mdsC[,1:elbowC[2]]) plot(mcC,"BIC") ``` ## *P* Data ```{r pdata,echo=TRUE,eval=FALSE} require(gdata) fname <- "http://www.cis.jhu.edu/~parky/CGP/Data/NEO2012.csv" neo <- read.csv(fname) pdat <- neo[,4:8] distP <- as.matrix(dist(pdat)) plotmat(as.matrix(pdat),"subject","factor") distP <- normalize(distP) dim(distP) plotmat(distP,"subject","subject") hist(distP) mdsP <- cmdscale(distP,n-1) elbowP <- getElbows(mdsP,3) mcP <- Mclust(mdsP[,1:elbowP[3]]) plot(mcP,"BIC") ``` ```{r distPdata,echo=FALSE} #outP <- doPdata() load("outP.Rbin") attach(outP) plotmat(as.matrix(pdat),"subject","factor","pdat") distP <- dmat distP <- normalize(distP) #dim(distP) ``` ```{r plotP,echo=FALSE} stopifnot(n==nrow(distP)) plotmat(distP,"subject","subject","dist(pdat)") hist(distP) mdsP <- cmdscale(distP,n-1) elbowP <- getElbows(mdsP,3) mcP <- Mclust(mdsP[,1:elbowP[3]]) plot(mcP,"BIC") ``` ## JOFC ```{r JOFC, echo=TRUE} #distC <- distP #set.seed(123) #distC <- jitter(distP,17000) #plotmat(distC,main="distC = jitter(distP,100)") #plotmat(distP,main="distP") #plotmat(abs(distC-distP),main="abs(distC-distP)") ## form omnibus matrix meanD <- (distC+distP)/2 omni <- rbind(cbind(distC,meanD),cbind(t(meanD),distP)) dim(omni) ## embed n2 <- n*2 mds <- cmdscale(omni,n2-1) ``` ```{r JOFC-omni-w, echo=FALSE} plotmat(omni,"column","row","omni") ``` ```{r JOFC-mds, echo=TRUE} elbow <- getElbows(mds,3) knee <- elbow[1] dat <- mds[,1:knee] ``` ```{r JOFC-scatter, echo=FALSE} lab <- factor(rep(c("C","P"),each=n)) #for (i in 1:4) { # for (j in (i+1):5) { for (i in 1:1) { for (j in (i+1):2) { plot(dat[,i],dat[,j],col=as.numeric(lab),pch=as.numeric(lab),main=paste("dim ",i, " vs dim ", j)) legend("bottomleft", c("C","P"),col=1:2,pch=1:2) segments(dat[1:n,i],dat[1:n,j],dat[(n+1):n2,i],dat[(n+1):n2,j],col="orange") } } pairs(dat[,1:5],col=as.numeric(lab),pch=as.numeric(lab)) ``` ## Validation the null (ie, truly matched subjects) and alternative holdout pdf estimates of the oos distances! 1. loop through the data, embedding but holding out two matched pairs. call these two matched pairs (i1,i2) and (j1,j2). * oos embed (i1,i2) under the null -- that is, assuming they are a matched pair -- and record d(i1,i2) in the embedded space. * oos embed (j1,j2) under the null -- that is, assuming they are a matched pair -- and record d(j1,j2) in the embedded space. * oos embed (i1,j2) under the null -- that is, assuming they are a matched pair -- and record d(i1,j2) in the embedded space. * oos embed (j1,i2) under the null -- that is, assuming they are a matched pair -- and record d(j1,i2) in the embedded space. 2. calc null pdf estimates of the first two oos distances. calc alternative pdf estimates of the last two oos distances. 3. plot these two kernel estimates together on the same plot -- null in blue, alt in red. ```{r oos, echo=TRUE, eval=FALSE} set.seed(12345) nmc <- 1000 out <- foreach(mc=1:nmc, .combine="rbind") %dopar% { ij1 <- sample(1:n,2,replace=FALSE) # i1, j1 ij2 <- ij1+n # i2, j2 ij <- c(ij1,ij2) ## "joint" oos Y <- fast.oos2(omni[-ij,-ij], knee, omni[ij,-ij]) DY <- as.matrix(dist(Y$X.oos)) D0 <- c(DY[1,3],DY[2,4]) # d(i1,i2), d(j1,j2) DA <- c(DY[1,4],DY[2,3]) # d(i1,j2), d(j1,i2) c(D0,DA) } ``` ```{r loadpwr, echo=FALSE, eval=TRUE} load("mcout-power-mc1000.Rbin") ``` ```{r plotpdf, echo=FALSE, eval=TRUE} adj <- 2 plot(density(out[,1],adjust=adj),type="l",lwd=2,col="blue",main="pdf of H0(blue) and HA(red)",xlim=c(0,max(out))) # (i1, i2) lines(density(out[,2],adjust=adj),type="l",lwd=2,lty=2,col="blue") # (j1, j2) lines(density(out[,3],adjust=adj),type="l",lwd=2,lty=1,col="red") # (i1, j2) lines(density(out[,4],adjust=adj),type="l",lwd=2,lty=2,col="red") # (j1, i2) leg <- c("d(i1,i2)","d(j1,j2)","d(i1,j2)","d(j1,i2)") legend("topright",leg,col=c(4,4,2,2),lty=c(1,2,1,2)) ``` ```{r plotpwr, echo=FALSE, eval=TRUE} size <- seq(0,1,0.01) p1 <- get_power2(out[,1], out[,3], size) # (i1,*) p2 <- get_power2(out[,2], out[,4], size) # (j1,*) plot(size,p1,type="l",xlab="alpha",ylab="power") lines(size,p2,lty=2) lines(size,(p1+p2)/2,lty=3,col="blue") abline(a=0,b=1,col=2) ``` ```{r W2, echo=FALSE, eval=TRUE} meanD <- matrix(1,n,n) - diag(1,n,n) O2 <- rbind(cbind(distC,meanD), cbind(t(meanD),distP)) w <- 1 Wdiag <- matrix(w, n, n) Woff <- matrix(0, n, n) diag(Woff) <- 1 Wb <- rbind(cbind(Wdiag, Woff), cbind(t(Woff), Wdiag)) # 84 x 84 ``` ## Predicting P from C ```{r W1, echo=TRUE, eval=TRUE} n2 <- n*2 ## omni meanD <- (distC + distP)/2 O1 <- rbind(cbind(distC, meanD), cbind(t(meanD), distP)) ``` ```{r plotO2, echo=FALSE, eval=TRUE} plotmat(O1,main=expression(O[1])) plotmat(O2,main=expression(O[2])) ``` ```{r O1, echo=TRUE, eval=TRUE} ## smacof W w <- 0.01 Wdiag <- matrix(w, n, n) Woff <- matrix(0, n, n) diag(Woff) <- 1 - w W1 <- rbind(cbind(Wdiag, Woff), cbind(t(Woff), Wdiag)) ``` ```{r plotW2, echo=FALSE, eval=TRUE} plotmat(W1,main=expression(W[1])) plotmat(Wb,main=expression(W[2])) ``` ```{r perf, echo=TRUE, eval=TRUE} ## smacof embedding of all 2*n points knee <- 2 set.seed(12345) smacof <- smacofSym(O1, knee, weightmat = W1)$conf lab <- factor(rep(c("C","P"),each=n)) plot(smacof[,1],smacof[,2],col=as.numeric(lab),pch=as.numeric(lab),main="C vs P via smacof embedding") segments(smacof[1:n,1],smacof[1:n,2],smacof[(n+1):n2,1],smacof[(n+1):n2,2],col="orange") legend("topright", c("C","P"),col=1:2,pch=1:2) ``` ### Estimating P for a C for which we have no P for each left-out (_C_,_P_) in turn 1. we choose _Phat[C]_ = weighted avg of _P_'s associated with _C_'s nearby to embedded _C_. 2. we look at _d( P[C], Phat[C] )_. 3. we decide what type of person you are, based on your connectome. ```{r ex1, echo=TRUE, eval=FALSE} K <- 1 # 1-NN Pjhat <- matrix(0,n,knee) for(i in 1:n) { j <- i+n # matching P ij <- c(i,j) ## (Ci,Pj) pair ## in sample without (Ci,Pj) pair Dij <- O1[-ij,-ij] Wij <- W1[-ij,-ij] Ci <- smacof[i,] Xij <- smacof[-ij,] X <- smacofSym(Dij, knee, weightmat = Wij, init=Xij)$conf # 82 x 5 Chat <- X[1:(n-1),] Phat <- X[-c(1:(n-1)),] ## oos Ci only Di <- O1[-j,-j] Wi <- matrix(0, nrow(O1), ncol = ncol(O1)) Wi[i,1:n] <- 1 Wi[1:n,i] <- 1 Wi <- Wi[-j,-j] within <- rep(1,n2) within[ij] <- 0 Cihat[i,] <- oosIM(Di, X, W=Wi, init=Ci, isWithin=within[-j]) ## estimate Pj dChat <- outer(rowSums(Cihat^2),rowSums(Chat^2),"+") - (2*Cihat %*% t(Chat)) dChat <- sqrt((dChat+abs(dChat))/2) ind <- order(dChat) # index of k-NN from Cihat to Chat Pjhat[i,] <- colMeans(Phat[ind[1:K],,drop=FALSE]) } ``` ```{r load1, echo=FALSE, eval=TRUE} load("smacof-oos-outP-new.Rbin") xrng <- range(c(smacof[,1],Cihat[,1])) yrng <- range(c(smacof[,2],Cihat[,2])) plot(smacof[1:n,],xlim=xrng,ylim=yrng, main="i = 42") # C points(smacof[n,1],smacof[n,2],pch=19,col=1,cex=2) # Ci points(Cihat[,1],Cihat[,2],pch=8,col=1,cex=2) # Cihat points(Chat,col=1,pch=21,bg="grey") # Chat points(Chat[ind[1],1],Chat[ind[1],2],col=1,pch=21,bg=3) # 1NN Chat points(smacof[-c(1:n),1],smacof[-c(1:n),2],col=2,pch=2) # P points(smacof[n2,1],smacof[n2,2],pch=17,col=2,cex=2) # Pj points(Phat,col=2,pch=24,bg="pink") # Pjhat points(Pjhat[n,1],Pjhat[n,2],col=2,pch=8,cex=2) # Phat segments(Pjhat[n,1],Pjhat[n,2],smacof[n2,1],smacof[n2,2],col="blue",lwd=2) segments(Cihat[,1],Cihat[,2],smacof[n,1],smacof[n,2],col="blue",lwd=2) legend("bottomright", c("C","Ci","Chat","Cihat","P","Pj","Phat","Pjhat"), col=c(1,1,1,1,2,2,2,2),pch=c(1,19,21,8,2,17,24,8), ncol=2, pt.bg=c("white","white","grey","white","white","white","pink","white")) plot(smacof[-c(1:n),],pch=2,col=2, main="P vs Pjhat")#,xlim=c(-1,1),ylim=c(-1,1)) points(Pjhat,col=2,pch=8) segments(smacof[-c(1:n),1],smacof[-c(1:n),2],Pjhat[1:n,1],Pjhat[1:n,2],col="orange") legend("topright", c("P","Pjhat"),col=2,pch=c(2,8)) diffP <- abs(Pjhat - smacof[-c(1:n),]) plot(density(diffP),main="d(P,Pjhat)") ``` ### Performance With $d_1 = d(\hat{P}_j, P_j)$ and $d_2 = d(P_j, mean(\hat{P}))$, where $P_j \in joint embedding(C,P)$ and $\hat{P}_j$ is obtained by either "no loo" or "with loo" based on $C_j$, we can define $Perf = \sum I(d_1 < d_2)$. Omni | Weight | no loo | with loo -----|-----|--------|--------- $O_1$ | $W_1$ | 41 | 34 $O_1$ | $W_2$ | 19 | 19 $O_2$ | $W_1$ | 42 | 25 $O_2$ | $W_2$ | 15 | 16 ------------------------------ Let $dP$ be the distance in the *original* $P$-space.
Let $dC$ be the distance in the *original* $C$-space.
Let $dJOFC$ be the distance in the *original* $JOFC$-space.
Consider the $j^{th}$ subject, then we care about $dP(\hat{P}_j,P_j)$ as our figure of merit. We observe $C_j$, as well as all the other $(C,P)$ pairs. 1. we estimate $P_j$ via the $P$'s associated with the $C$'s which are $dC$-close to $C_j$. 2. we estimate $P_j$ via the $P$'s associated with the $C$'s which are $JOFC$-close to $C_j$.
Both approaches are trying to approximate
3. we estimate $P_j$ via the $P$'s which are $dP$-close to $P_j$. Let's look at which $P$'s are close, in all three cases, that is, for each $j$, 1. $dist_0 = dP(P_j, \hat{P})$, where $\hat{P} = P_{\arg\min_{k \neq j} dP(C_j,C_k)}$ 2. $dist_1 = dP(P_j, \hat{P}_{dC})$, where $\hat{P}_{dC} = P_{\arg\min_{k \neq j} dC(C_j,C_k)}$ 3. $dist_2 = dP(P_j, \hat{P}_{dJOFC})$, where $\hat{P}_{dJOFC} = P_{\arg\min_{k \neq j} dJOFC(C_j,C_k)}$ If $dist_2$ looks more like $dist_0$ than $dist_1$ looks like $dist_0$, then JOFC wins! ```{r pval0, echo=FALSE, eval=TRUE} require(smacof) N <- nrow(distC) N2 <- N*2 knee <- 2 K <- 1 dP <- distP dC <- distC mds <- smacofSym(O1, knee, weightmat = W1)$conf dmat <- as.matrix(dist(mds))[1:N,1:N] # for C ## (1) we estimate P_j via the P's associated with the C's which are dC-close to C_j. ## (2) we estimate P_j via the P's associated with the C's which are jofc-close to C_j. ## both approaches are trying to approximate ## (0) we estimate P_j via the P's which are dP-close to P_j. order0 <- order1 <- order2 <- matrix(0,N,N) for (j in 1:N) { tmp <- order(dP[j,]) order0[j,] <- tmp tmp <- order(dC[j,]) order1[j,] <- tmp tmp <- order(dmat[j,]) order2[j,] <- tmp } whichj <- matrix(0,N,2) for (j in 1:N) { # print(rbind(order0[j,1:10],order1[j,1:10],order2[j,1:10])) whichj[j,1] <- which(order0[j,2] == order1[j,]) whichj[j,2] <- which(order0[j,2] == order2[j,]) } ## dP(Pj,Phat_jofcnn(Cj)) - dP(Pj,Phat_dCnn(Cj)) diffD <- rep(0,N) for (j in 1:N) { diffD[j] <- dP[j,order2[j,2]] - dP[j,order1[j,2]] # diffD[j] <- dP[j,whichj[j,2]] - dP[j,whichj[j,1]] } ## sign test # pval <- 1-pbinom(sum(diffD<0)-1,sum(diffD!=0),.5) # main=expression(dP(P[j],hat(P)[jofcnn](C[j])) - dP(P[j],hat(P)[dCnn](C[j]))) # plot(density(diffD),main=main,xlab=paste("p-value = ",round(pval,2), "using alpha = 0.5")) # abline(v=0,lty=2) # alp <- seq(0,0.5,0.01) # pvec <- rep(0,length(alp)) # ind <- 1 # for (i in alp) { # pvec[ind] <- 1-pbinom(sum(diffD<0)-1,sum(diffD!=0),alp[ind]) # ind <- ind+1 # } # plot(x=alp,y=pvec,type="l",xlab=expression(alpha),ylab="p-value") diffD <- dist0 <- dist1 <- dist2 <- rep(0,N) for (j in 1:N) { # diffD[j] <- dP[j,whichj[j,2]] - dP[j,whichj[j,1]] dist0[j] <- dP[j,order0[j,K+1]] dist1[j] <- dP[j,order1[j,K+1]] dist2[j] <- dP[j,order2[j,K+1]] diffD[j] <- dist2[j] - dist1[j] } dist3 <- data.frame(dP=dist0,dC=dist1,dJOFC=dist2) dist3.df <- melt(dist3) diff.df <- melt(diffD) p <- ggplot(dist3.df, aes(value, fill = variable)) p <- p + geom_density(alpha = 0.2) # p <- p + geom_bar(alpha = 0.5) p <- p + scale_fill_discrete(name="method",labels=c("dist0","dist1","dist2")) p <- p + theme(legend.position=c(0.9,0.5)) p <- p + scale_x_continuous(name="phenotype prediction distance") p <- p + scale_y_continuous(name="kernel density estimate") p + ggtitle("Nearest Neighbor Phenotype Prediction based on Connectome") p <- ggplot(diff.df,aes(x=value)) + geom_density(fill="cyan",alpha=0.2) # p <- p + geom_vline(xintercept = mean(diffD),color="red",linetype="dashed") p <- p + scale_x_continuous(name="dist2 - dist1") #, red vline: mean(d_JOFC-d_C)") p <- p + scale_y_continuous(name="kernel density estimate") p <- p + ggtitle("Nearest Neighbor Phenotype Prediction based on Connectome") p <- p + geom_point(x = mean(diffD), y = 0, color="red",size=5) p + annotate("text", x = mean(diffD), y = 0.1, label = "mean", color="red") ``` Now, let's do sign tests for $dP(P_j,\hat{P}_{jofcnn}(C_j)) - dP(P_j,\hat{P}_{dCnn}(C_j))$ by varying $w$ in $W_1$. Note that $w=0.5$ yields $W_1=W_2$. ```{r pval, echo=FALSE, eval=TRUE} dat <- dget("alpha-pval.RData") plot(x=dat[1,], y=dat[2,], type="l", xlab="w in W1, w=0.5 => W2", ylab="p-value") abline(h=0.05,lty=2,col=2) ``` **Prediction of Phenotype based on Connectome is better via jofc than via raw!**