[R] how to use 'which' inside of 'apply'?

William Dunlap wdunlap at tibco.com
Mon Oct 17 20:00:00 CEST 2011


Try vectorizing it a bit by looping over the columns.
E.g.,

  f1 <- function (df)
  {
      # loop (backwards) over all columns in df whose
      # names start with "D" to find the earliest one
      # that is bigger than column "thold".  I tested with
      # df being a data.frame but a matrix should work too.
      i <- rep(NA_character_, nrow(df))
      colNames <- grep(value = TRUE, "^D", colnames(df))
      for (colName in rev(colNames)) {
          i[df[, colName] > df[, "thold"]] <- colName
      }
      # convert column name "D<number>" to <number>.
      doy <- as.numeric(sub("^D", "", i))
      doy
  }
  > f1(a)
  [1] 129 145 129 177 177 177

You could also try looping over rows with something like
findInterval.  If there are far fewer columns than rows
then looping over columns is generally faster.

Your sample data.frame I called 'a' and in copy-and-pastable
form (from dput()) is
a <- structure(list(pt = c(39177L, 39178L, 39164L, 39143L, 39144L,
39146L), D1 = c(0L, 0L, 0L, 0L, 0L, 0L), D17 = c(0L, 0L, 0L,
0L, 0L, 0L), D33 = c(0L, 0L, 0L, 0L, 0L, 0L), D49 = c(0L, 0L,
0L, 0L, 0L, 0L), D65 = c(0L, 0L, 0L, 0L, 0L, 0L), D81 = c(0L,
0L, 0L, 0L, 0L, 0L), D97 = c(0L, 0L, 0L, 0L, 0L, 0L), D113 = c(0L,
0L, 0L, 0L, 0L, 0L), D129 = c(0.4336, 0.342, 0.483, 0.3088, 0.339,
0.4232), D145 = c(0.4754, 0.4543, 0.4943, 0.3753, 0.4152, 0.4442
), D161 = c(0.5340667, 0.5397666, 0.5740333, 0.4466, 0.5147,
0.5084), D177 = c(0.5927334, 0.6252333, 0.6537667, 0.5179, 0.6142,
0.5726), D193 = c(0.6514, 0.7107, 0.7335, 0.5892, 0.7137, 0.6368
), D209 = c(0.6966, 0.7123, 0.6255, 0.6468, 0.6914, 0.5896),
    D225 = c(0.59, 0.5591, 0.6228, 0.4794, 0.6381, 0.4703), D241 = c(0.5583,
    0.4617, 0.5255, 0.4411, 0.5704, 0.4936), D257 = c(0.5676,
    0.4206, 0.5436, 0.4307, 0.5619, 0.5353), D273 = c(0.4682,
    0.3867, 0.5541, 0.3632, 0.5347, 0.4067), D289 = c(0.35115,
    0.2578, 0.46195, 0.34355, 0.4976, 0.39685), D305 = c(0.2341,
    0.1289, 0.3698, 0.3239, 0.4605, 0.387), D321 = c(0.11705,
    0, 0.1849, 0, 0, 0), D337 = c(0L, 0L, 0L, 0L, 0L, 0L), D353 = c(0L,
    0L, 0L, 0L, 0L, 0L), thold = c(0.406825, 0.4206, 0.4592,
    0.4778, 0.52635, 0.5119), doy = c(0L, 0L, 0L, 0L, 0L, 0L)), .Names = c("pt",
"D1", "D17", "D33", "D49", "D65", "D81", "D97", "D113", "D129",
"D145", "D161", "D177", "D193", "D209", "D225", "D241", "D257",
"D273", "D289", "D305", "D321", "D337", "D353", "thold", "doy"
), class = "data.frame", row.names = c("1", "2", "3", "4", "5",
"6"))


Bill Dunlap
Spotfire, TIBCO Software
wdunlap tibco.com 

> -----Original Message-----
> From: r-help-bounces at r-project.org [mailto:r-help-bounces at r-project.org] On Behalf Of R. Michael
> Weylandt
> Sent: Monday, October 17, 2011 10:32 AM
> To: Nathan Piekielek
> Cc: r-help at r-project.org
> Subject: Re: [R] how to use 'which' inside of 'apply'?
> 
> I think something like this should do it at a huge speed up, though
> I'd advise you check it to make sure it does exactly what you want:
> there's also nothing to guarantee that something beats the threshold,
> so that might make the whole thing fall apart (though I don't think it
> will)
> 
> # Sample data
> df = data.frame(x = sample(5, 15,T),
> 			y = sample(5, 15, T),
> 			z = sample(5, 15,T),
> 			w = (1:5)/2 + 0.5,
> 			th = (1:5)/2,
> 			doy = rep(0,15))
> 
> wd <- which(df[,1:4] > df[,5], arr.ind = TRUE)
> # identify all elements that beat the threshold value by their indices
> 
> wd <- wd[!duplicated(wd[,1]),]
> # select only the first appearance of each "row" value in wd -- this
> keeps the earliest column beating the threshold
> 
> wd <- wd[order(wd[,"row"]),]
> # sort them by row
> 
> df$doy = (wd[,"col"]-1)*16 + 1
> # The column transform you used.
> 
> Hope this helps,
> 
> Michael
> 
> 
> On Mon, Oct 17, 2011 at 1:03 PM, Nathan Piekielek <npiekielek at gmail.com> wrote:
> > Hello R-community,
> >
> > I am trying to populate a column (doy) in a large dataset with the first
> > column number that exceeds the value in another column (thold) using the
> > 'apply' function.
> >
> > Sample data:
> >     pt D1 D17 D33 D49 D65 D81 D97 D113   D129   D145      D161      D177
> > D193   D209   D225   D241   D257
> > 1 39177  0   0   0   0   0   0   0    0 0.4336 0.4754 0.5340667 0.5927334
> > 0.6514 0.6966 0.5900 0.5583 0.5676
> > 2 39178  0   0   0   0   0   0   0    0 0.3420 0.4543 0.5397666 0.6252333
> > 0.7107 0.7123 0.5591 0.4617 0.4206
> > 3 39164  0   0   0   0   0   0   0    0 0.4830 0.4943 0.5740333 0.6537667
> > 0.7335 0.6255 0.6228 0.5255 0.5436
> > 4 39143  0   0   0   0   0   0   0    0 0.3088 0.3753 0.4466000 0.5179000
> > 0.5892 0.6468 0.4794 0.4411 0.4307
> > 5 39144  0   0   0   0   0   0   0    0 0.3390 0.4152 0.5147000 0.6142000
> > 0.7137 0.6914 0.6381 0.5704 0.5619
> > 6 39146  0   0   0   0   0   0   0    0 0.4232 0.4442 0.5084000 0.5726000
> > 0.6368 0.5896 0.4703 0.4936 0.5353
> >    D273    D289   D305    D321 D337 D353    thold doy
> > 1 0.4682 0.35115 0.2341 0.11705    0    0 0.406825   0
> > 2 0.3867 0.25780 0.1289 0.00000    0    0 0.420600   0
> > 3 0.5541 0.46195 0.3698 0.18490    0    0 0.459200   0
> > 4 0.3632 0.34355 0.3239 0.00000    0    0 0.477800   0
> > 5 0.5347 0.49760 0.4605 0.00000    0    0 0.526350   0
> > 6 0.4067 0.39685 0.3870 0.00000    0    0 0.511900   0
> >
> > For the first record in above example I would expect doy = 129.
> >
> > I can achieve this with the following loop, but it takes several days to run
> > and there must be a more efficient solution:
> >
> > for (i in (1:152000)) {
> > t=which(data[i,2:24]>data[i,25])
> > r=min(t)
> > data[i,26]=(r-1)*16+1
> > }
> >
> > How do I write this using 'apply' or another function that will be more
> > efficient?
> >
> > I have tried the following:
> > data$doy=apply(which(data[,2:24]>data[,25]),1,min)
> >
> > Which returns the following error message:
> > "Error in apply(which(new[, 2:24] > new[, 25]), 1, min) :
> >  dim(X) must have a positive length"
> >
> > Any help would be much appreciated.
> >
> > Nathan
> >
> > ______________________________________________
> > R-help at 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.
> >
> 
> ______________________________________________
> R-help at 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.



More information about the R-help mailing list