[R] applying a function to data frame columns

Tim Hesterberg timh at insightful.com
Fri Feb 22 19:31:32 CET 2008


You can do:

	lapply2(u, v, function(u,v) u[inRange(u, range(v))])

using two functions 'lapply2' and 'inRange' defined at bottom.
This basically does:

	lapply(seq(along=u),
               function(i, U, V){
                 u <- U[[i]]
                 v <- V[[i]]
                 u[u >= range(v)[1] & u <= range(v)[2]]
               },
               U = u, V = v)

Tim Hesterberg

>I want to apply this function to the columns of a data frame:
>
>u[u >= range(v)[1] & u <= range(v)[2]]
>
>where u is the n column data frame under consideration and v is a data frame
>of values with the same number of columns as u.  For example,
>v1 <- c(1,2,3)
>v2 <- c(3,4,5)
>v3 <- c(2,3,4)
>v <- as.data.frame(cbind(v1,v2,v3))
>
>uk1 <- seq(min(v1) - .5, max(v1) + .5, .5)
>uk2 <- seq(min(v2) - .5, max(v2) + .5, .5)
>uk3 <- seq(min(v3) - .5, max(v3) + .5, .5)
>
>u <- do.call("expand.grid", list(uk1,uk2,uk3))
>
>Here, there are 3 columns; instead of hard-coding this, can the function
>given above, which will restrict the u data frame to values within the
>ranges of each variable, be done with the apply function?  Thanks in
>advance.
>
>dxc13

# inRange requires ifelse1, part of the "splus2R" package.

inRange <- function(x, a, b, strict = FALSE) {
  # Return TRUE where x is within the range of a to b.
  # If a is length 2 and b is missing, assume that a gives the range.
  # if(strict==FALSE), then allow equality, otherwise require a < x < b.
  # strict may be a vector of length 2, governing the two ends.
  if(length(a)==2) {
    b <- a[2]
    a <- a[1]
  }
  else if(length(a) * length(b) != 1)
    stop("a and b must both have length 1, or a may have length 2")
  strict <- rep(strict, length=2)
  ifelse1(strict[1], x>a, x>=a) & ifelse1(strict[2], x<b, x<=b)
}

lapply2 <- function(X1, X2, FUN, ...){
  # Like lapply, but for two inputs.
  # FUN should take two inputs, one from X1 and one from X2.

  n1 <- length(X1)
  if(n1 != length(X2))
    stop("X1 and X2 have different lengths")

  if(is.character(FUN))
    FUN <- getFunction(FUN)
  else if(!is.function(FUN)) {
    farg <- substitute(FUN)
    if(is.name(farg))
      FUN <- getFunction(farg)
    else
      stop("'", deparseText(farg), "' is not a function")
  }

  FUNi <- function(i, X1, X2, FUN2, ...)
    FUN2(X1[[i]], X2[[i]], ...)

  # Create sequence vector.
  # If objects have same names, use them.
  i <- seq(length = n1)
  names1 <- names(X1)
  if(length(names1) && identical(names1, names(X2)))
    names(i) <- names1

  # Final result; loop over the sequence vector
  lapply(i, FUNi, X1 = X1, X2 = X2, FUN2 = FUN, ...)
}



More information about the R-help mailing list