lrclark
lrclark

Reputation: 91

Passing multiple arguments within apply function

I am trying to pass 2 arguments for a user-defined function within the FUN argument of an apply function, as in the below example:

mat <- matrix(NA, nrow =10, ncol=3)
mat[,1] <- runif(10, 0, 1)
mat[,2] <- runif(10, 0, 1)
mat[,3] <- runif(10, 0, 1)


roundFn <- function(indata, p){
  for (i in ncol(indata)){
    if(is.numeric(indata[,i])){
      indata[,i] <- round(indata[,i], digits = p)
    }
  } 
}

outdata <- apply(mat, 2, roundFn, indata = mat, p = 3)

But when I run the above code I get an error message that says:

Error in FUN(newX[, i], ...) : unused argument (newX[, i])

Any tips on how to properly use the apply function in this context would be much appreciated.

Upvotes: 0

Views: 57

Answers (1)

Ricardo Semi&#227;o
Ricardo Semi&#227;o

Reputation: 4456

Your roundFn function loops through every column of indata, so applying it to every column with apply is redundant. You can either (1) apply roundFn directly to mat, or (2) redefine roundFn to act on a column of mat, and then apply it to every column with apply.

mat = replicate(3, runif(10)) #a smarter way to create a random matrix

First method:

roundFn <- function(indata, p){
  for (i in 1:ncol(indata)){ #here you missed the "1:" before "ncol(indata)"
    if(is.numeric(indata[,i])){
      indata[,i] <- round(indata[,i], digits = p)
    }
  }
  return(indata) #you forgot to say what your function should return
}

outdata <- roundFn(mat, 3)

Second method:

roundFn <- function(indata.col, p){ #now, it receives a column
  if(is.numeric(indata.col)){
    return(round(indata.col, digits = p))
  }
}

outdata <- apply(mat, 2, roundFn, p = 3)

As @Allan Cameron and @M-- pointed out in the comments, roundFn is really similar to round, the only difference is that it only applies to numeric columns. Thus, you can get the same output from:

Using base R:

apply(mat[,apply(mat, 2, is.numeric)], 2, round, digits = 3)

Using dplyr/tidyverse:

library(tidyverse)
mutate(as_tibble(mat), across(where(is.numeric), round, digits = 3))

Upvotes: 3

Related Questions