Reputation: 17678
This should be simple but I just can't get the apply
to communicate with my vectorised function.
Test data is: df <- data.frame(a = 1:3, b1 = c(4:5, NA), b2 = c(5,6,5))
Looks like this:
a b1 b2
1 1 4 5
2 2 5 6
3 3 NA 5
Custom function checks returns a vector to indicate whether values fall in a given interval.
validScore <- function(x, a, b) {
is.na(x) == FALSE &
x%%1 == 0 &
findInterval(x, c(a,b), rightmost.closed = TRUE) == 1
}
Test of custom function: validScore(c(3, 3.5, 6, NA), 1, 5)
returns the logical vector TRUE FALSE FALSE FALSE
as expected.
I want to run the custom function on the row defined by the columns b1 and b2. This would return TRUE FALSE FALSE (that is T on (b1=4,b2=5), F on (b1=5,b2=6) and F on (b1=NA,b2=5)).
The answer Call apply-like function on each row of dataframe with multiple arguments from each row for selecting the columns, and how to apply a function to every row of a matrix (or a data frame) in R together suggest the following:
library(dplyr)
apply(select(df, b1:b2), 1, function(x) validScore(x, 1, 5))
but that doesn't actually send the row to the function, instead assessing each value individually, so output is:
[,1] [,2] [,3]
b1 TRUE TRUE FALSE
b2 TRUE FALSE TRUE
Sticking a rowwise() into the middle like select(df, b1:b2) %>% rowwise() %>% apply(1, function(x) validScore(x, 1, 5))
makes no difference.
I thought it might by something to do with the form that the dplyr select returned, but apply(df[, c("b1", "b2")], 1, function(x) validScore(x, 1, 5))
also generates the same result.
Upvotes: 2
Views: 1902
Reputation: 60462
You don't need dplyr
or plyr
. You can just use base R.
The first thing to do is to make validScore
return only a single TRUE
or FALSE
. This can be done using the all
function
validScore <- function(x, a, b) {
test = is.na(x) == FALSE &
x %% 1 == 0 &
findInterval(x, c(a,b), rightmost.closed = TRUE) == 1
all(test)
}
After that just use the standard apply
## Select columns 2 & 3
apply(df[, 2:3], 1, validScore, a=1, b=8)
Upvotes: 2