You are loosing a lot of time by repeatedly calculating character indices with paste() in every iteration. Two options:

-- 1) calculate these once outside the loop and then refer to them by index

idx.names <- vector(mode="character", length=nind)
for (i in (0:(nind-1))) {idx[i+1] <-    # need the offset
       c(paste("G_hat_0_",i,sep=""),
        paste("G_hat_1_",i,sep=""),
        paste("G_hat_2_",i,sep=""),
        paste("G_",i,sep="") ) }

Then the inner loop would be:
for (i in (0:(nind-1))) {
      Gmax = which.max(c(data[[ idx.names[1] ]][row],
                         data[[ idx.names[2] ]][row],
                         data[[ idx.names[3] ]][row] ))

        Gtru = data[[ idx.names[4] ]][row] + 1  # add 1 to match Gmax range
                       }

And as has been said many times before,...
require(fortunes)
fortune("dog")

-- 2) probably even faster to pre-calculate (or just construct by inspection) those column indices as a numeric vector and use then access with data[row, numidxs[i] ]

The for-loop is generally going to be faster than an lapply solution. The fastest solution would be a fully indexed strategy, which might become more apparent (it's not yet so to me) after you implement the second option above.

--
David.

On Oct 8, 2010, at 11:35 AM, epowell wrote:


My data looks like this:

data
name G_hat_0_0 G_hat_1_0 G_hat_2_0 G_0 G_hat_0_1 G_hat_1_1 G_hat_2_1 G_1 1 rs0 0.488000 0.448625 0.063375 1 0.480875 0.454500 0.064625 1 2 rs1 0.002375 0.955375 0.042250 1 0.000000 0.062875 0.937125 2 3 rs2 0.050375 0.835875 0.113750 1 0.877250 0.115875 0.006875 0 4 rs3 0.000000 0.074750 0.925250 2 0.897750 0.102000 0.000250 0 5 rs4 0.000125 0.052375 0.947500 2 0.261500 0.724125 0.014375 1 6 rs5 0.003750 0.092125 0.904125 2 0.023000 0.738125 0.238875 1

And my task is:
For each individual (X) on each row, to find the index corresponding to the max of G_hat_X_0, G_hat_X_1, G_hat_X_2 and then increment the cell of the confusion matrix with the row corresponding to that index and the column
corresponding to G_X.

For example, in the first row and the first individual, the index with the
max value (0.488000) is 0 and the G_0 value is 1, so I would increment
matrix index of the first row and second column. (Note that the ranges
between rows and columns are one off. That is accounted for in the code.)

In reality the data will be much bigger, containing 10000 rows and a
variable number of columns (inds) between 10 and 500.

The correct result is:

cmat
       tru_rr tru_rv tru_vv
call_rr      2      2      0
call_rv      0      4      0
call_vv      0      0      4

I am not sure what the best way to do this is. I implemented it once using two for loops. Then I tried to use lapply and came up with a nested lapply solution, but it was slower than the simple loops. I still think that there is a better way and I was hoping for some advice. Perhaps something with
pmax....

#### DATA PREP ##########

data = data.frame(name=c("rs0","rs1","rs2","rs3","rs4","rs5"),
        G_hat_0_0=c(0.488,0.002375,0.050375,0,0.000125,0.00375),
        G_hat_1_0=c(0.448625,0.955375,0.835875,0.07475,0.052375,0.092125),
        G_hat_2_0=c(0.063375,0.04225,0.11375,0.92525,0.9475,0.904125),
        G_0=c(1,1,1,2,2,2),
        G_hat_0_1=c(0.480875,0,0.87725,0.89775,0.2615,0.023),
        G_hat_1_1=c(0.4545,0.062875,0.115875,0.102,0.724125,0.738125),
        G_hat_2_1=c(0.064625,0.937125,0.006875,0.00025,0.014375,0.238875),
        G_1=c(1,2,0,0,1,1))     

# get list of inds in file (e.g. G_0,G_1,...,G_100)
inds = grep("G_[0-9]+",names(data),perl=T,value=T)

# get total number of inds
nind = length(inds)

# create an empty "confusion" table
cmat = matrix(rep(0,9), nrow=3, ncol=3)
colnames(cmat) = c("tru_rr", "tru_rv", "tru_vv")
rownames(cmat) = c("call_rr","call_rv","call_vv")

## APPROACH 1: Nested For Loop ####

# Nested Loop Approach
for (row in (1:nrow(data))) {
for (i in (0:(nind-1))) {

        Gmax = which.max(c( data[[paste("G_hat_0_",i,sep="")]][row],
                                  data[[paste("G_hat_1_",i,sep="")]][row],
                                  data[[paste("G_hat_2_",i,sep="")]][row] ))

Gtru = data[[paste("G_",i,sep="")]][row] + 1 # add 1 to match Gmax range

        cmat[Gmax,Gtru] = cmat[Gmax,Gtru] + 1
}
}


## APPROACH 2: Nested lapply ####

# This routine finds the geno w/ highest prob from the erg.avgs.
# and compares it to the true geno. Result is tallied by                
# incrementing the appropriate index of the confusion matrix    

add2cmat <- function(ind,locus) {

        Gmax = which.max(c( data[[paste("G_hat_0_",ind,sep="")]][locus],
                                  data[[paste("G_hat_1_",ind,sep="")]][locus],
                                  data[[paste("G_hat_2_",ind,sep="")]][locus] ))

Gtru = data[[paste("G_",ind,sep="")]][locus] + 1 # add 1 to match Gmax
range

cmat[Gmax,Gtru] <<- cmat[Gmax,Gtru] + 1 # use double arrow to modify
global env.

}

# Run add2cmat for all individuals on a given locus

add_locus2cmat <- function(locus) {
        lapply(0:(nind-1),add2cmat,locus)
}

junk = lapply((1:nrow(data)),add_locus2cmat) # don't need return value



--
View this message in context: 
http://r.789695.n4.nabble.com/Efficiency-Question-Nested-lapply-or-nested-for-loop-tp2968553p2968553.html
Sent from the R help mailing list archive at Nabble.com.

______________________________________________
R-help@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.

David Winsemius, MD
West Hartford, CT

______________________________________________
R-help@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.

Reply via email to