Kris G
Kris G

Reputation: 41

Apply prop.test to each row in a dataframe

Beginner here: I'm trying to apply the prop.test function in r to each row of a dataframe. If I have a large table, how can I apply the function row-wise without referencing each element? I tried the broom::tidy function but this provides only the proportion and I need the 95% confidence intervals.

> a<-data.frame(x=c(1,2,3,4),y=c(5,6,7,8))
> z=rowSums(a)
> b<-cbind(a,z)
> b
  x y  z
1 1 5  6
2 2 6  8
3 3 7 10
4 4 8 12

# inefficient code:
prop.test(b[1,1],b[1,3])
prop.test(b[2,1],b[2,3])
prop.test(b[3,1],b[3,3])
prop.test(b[4,1],b[4,3])

# doesn't provide 95% confidence intervals
broom::tidy(prop.test(b$x, b$z))

Upvotes: 4

Views: 2257

Answers (3)

akrun
akrun

Reputation: 887691

We may need rowwise operation instead of applying prop.test on the entire columns

library(dplyr)
library(tidyr)
library(broom)
b %>%
     rowwise %>%
      summarise(out = list(prop.test(x, z) %>%
             tidy)) %>%
      ungroup %>%
      unnest(cols = c(out))

-output

# A tibble: 4 x 8
  estimate statistic p.value parameter conf.low conf.high method                                               alternative
     <dbl>     <dbl>   <dbl>     <int>    <dbl>     <dbl> <chr>                                                <chr>      
1    0.167      1.5    0.221         1  0.00876     0.635 1-sample proportions test with continuity correction two.sided  
2    0.25       1.12   0.289         1  0.0445      0.644 1-sample proportions test with continuity correction two.sided  
3    0.3        0.9    0.343         1  0.0809      0.646 1-sample proportions test with continuity correction two.sided  
4    0.333      0.75   0.386         1  0.113       0.646 1-sample proportions test with continuity correction two.sided  

Or in base R, it would be Map

do.call(rbind, Map(\(x, y) tidy(prop.test(x, y)), b$x, b$z))

-output

# A tibble: 4 x 8
  estimate statistic p.value parameter conf.low conf.high method                                               alternative
     <dbl>     <dbl>   <dbl>     <int>    <dbl>     <dbl> <chr>                                                <chr>      
1    0.167      1.5    0.221         1  0.00876     0.635 1-sample proportions test with continuity correction two.sided  
2    0.25       1.12   0.289         1  0.0445      0.644 1-sample proportions test with continuity correction two.sided  
3    0.3        0.9    0.343         1  0.0809      0.646 1-sample proportions test with continuity correction two.sided  
4    0.333      0.75   0.386         1  0.113       0.646 1-sample proportions test with continuity correction two.sided  

Upvotes: 2

Alex Reynolds
Alex Reynolds

Reputation: 96976

You could use apply to apply a function to each row of a data frame:

apply(b, 1, function(df) prop.test(df[1], df[3]))

This returns a list:

l <- apply(b, 1, function(df) prop.test(df[1], df[3]))
typeof(l)
[1] "list"

So you could access these by list indices, e.g. [[1]], [[2]], etc. You could also use unlist(l) to unwrap the list, but this may not give results that are as easy to access.

You could also apply by column label:

apply(b, 1, function(df) prop.test(df['x'], df['z']))

Upvotes: 1

KacZdr
KacZdr

Reputation: 1527

Or with a simple function:

myFun <- function(x) {
  for (i in c(1:nrow(x))) {
    print(prop.test(b[i,1],b[i,3]))
  }
}

myFun(b)

Upvotes: 1

Related Questions