Mel36
Mel36

Reputation: 27

Using apply functions to do pair comparisons

Would anyone be able to advise on what I might be doing wrong with apply function I have tried below to do paired comparisons. I have created a newfunction and was able to compare the 1st case with the 1st control using [1]. But now I need to use an apply function to compare all 9 possible pairs. I tried using sapply below but its not working. The expected output should be a vector with the results, such as 1's, -1's and 0's based on the function. So when I compared the first case with the first control, the result was -1. So now I was to compare every possible pair to end up with 9 results instead of just 1 because there are 9 possible pairs matching the intervention 1 and 2 – The result should be: 1,0,1,0,-1,0,0,-1,0 Many thanks in advance.

## simulate data
data <- data.frame(
  id = c(1, 5, 6, 11, 15, 21),
  intervention = c(2, 2, 2, 1, 1, 1),
  mortality_30d = c(0, 1, 0, 1, 0, 0)
)

## create new function to compare the outcome and determine result

newfunction <- function (outcome_case, outcome_control){
  
  if (outcome_case < outcome_control) {result = 1}
  if (outcome_case > outcome_control) {result = -1}
  if (outcome_case == outcome_control) {result = 0}
  
  return(result)
  
}

# compare the 1st case and 1st control in terms of mortality
newfunction(data[which(data$intervention == 1)[1], 'mortality_30d'], 
               data[which(data$intervention == 2)[1], 'mortality_30d'])

## use an apply function to compare all 9 possible pairs 
test<-sapply(data$id,function(x) {
  newfunction(data[which(data$intervention == 1),'mortality_30d'], 
                 (data[which(data$intervention == 2),'mortality_30d']))
})

Upvotes: 0

Views: 110

Answers (2)

Martin Gal
Martin Gal

Reputation: 16998

Using your function (with small changes)

new_fun <- function (outcome_case, outcome_control){
  
  if (outcome_case < outcome_control) { 
    return(1)
  } else if (outcome_case > outcome_control) {
      return(-1)
  } else {
    return(0)
  }

}

we could use apply on an indexing array with your interventions:

expand.grid(1:3, 4:6)

gives us

  Var1 Var2
1    1    4
2    2    4
3    3    4
4    1    5
5    2    5
6    3    5
7    1    6
8    2    6
9    3    6

These are the indices of all possible pairs. Using this with apply:

apply(expand.grid(1:3, 4:6), 1, function(x) new_fun(data[x[1], 3], data[x[2], 3]))

returns

#> [1]  1  0  1  0 -1  0  0 -1  0

Edit

If the values of 2 and 1 are randomly distributed through intervention this approach won't work. But we could get the indices by using which and use them with expand.grid:

data_2 <- data.frame(
  id = c(1, 5, 6, 11, 15, 21),
  intervention = c(1, 2, 2, 1, 2, 1), # new intervention column
  mortality_30d = c(0, 1, 0, 1, 0, 0)
)


apply(expand.grid(which(data_2$intervention == 2), which(data_2$intervention == 1)), 
      1, 
      function(x) sign(data_2[x[2], 3] - data_2[x[1], 3]))

This returns

#> [1] -1  0  0  0  1  1 -1  0  0

Upvotes: 1

IRTFM
IRTFM

Reputation: 263481

The outer function will return a matrix of results of 2-way operations and yyou could set it up to give you the sign of the difference. Perhaps:

 outer( data1[1:3, 3],  # appears you want to compare outcomes between interventions
        data1[4:6, 3],  # second intervention mortality
        FUN=function(x,y){ sign(x-y) })
#-------------
     [,1] [,2] [,3]
[1,]   -1    0    0
[2,]    0    1    1
[3,]   -1    0    0

Could do it with nested sapply-s but that would be very clunky.

Upvotes: 2

Related Questions