2
votes

I would like to run a custom function that uses specific columns of a dataframe split by groups. Here is my sample data & function code:

 my_data = data.frame(N = c(12, 12, 24, 24, 12, 12),
                     p = rep(c(.125,.125,.025),2),
                     group = rep(c("dogs","cats"),each=3))

power.sequential <- function(d, nseq, pseq){
  decvec <- NULL
  nvec <- NULL
  for (i in 1:100){
    decvec[i] <- 0
    nvec[i] <- 0
    j <- 1
    x <- NULL
    while(decvec[i] == 0 & nvec[i] < sum(nseq)){
      x <- c(x, rnorm(nseq[j], mean = d))
      p <- t.test(x)$p.value
      nvec[i] <- nvec[i] + nseq[j]
      if (p < pseq[j]) decvec[i] <- 1
      j <- j + 1      
    }
  }
  power <- mean(decvec == 1)
  meanN <- mean(nvec)
  return(list("power" = power, "mean_N" = meanN))
}

Now I want to run this function on each group in my dataframe. This is how the function is called normally:

power.sequential(d = .5,
                 nseq = c(12,12,24),
                 pseq = c(.125,.125,.025))

The function returns two values, and ideally they would each be saved in a separate column of my dataframe. And this is my best try, but it gives an error message:

my_data %>% group_by(group) %>%
  mutate(result = power.sequential(d=.5,nseq=N,pseq=p))

I probably need to reshape my dataframe so that each group is a single row, but I'm stuck on how to proceed.

Here is my desired output, the function outputs two values (power and meanN), each should get its own column.

group power meanN
 dogs  .94   20.28
 cats  .95   27.36
2
Can you show us your desired output? - hpesoj626
Your function is returning a list of two means. mean will accept a vector answer, but always return a scalar result. Do you really want two columns of a scalar result? - De Novo
Yes, I would like two separate columnsin my output. It's possible that it would be easier to tweak how the function outputs the values. - Esther
@Esther I should appreciate the code/details provided with question. It helped me to get the answer quickly. - MKR

2 Answers

1
votes

You can do:

my_data %>%
 group_by(group) %>%
 do(data.frame(power.sequential(d=.5,nseq=.$N,pseq=.$p)[c(1, 2)])) %>%
 data.frame()

That gives:

  group power mean_N
1  cats  0.96  27.24
2  dogs  0.94  21.12
1
votes

The task can be simplified with use of data.table. One can call the function in 'j` section directly and both values will appear as separate column.

library(data.table)

setDT(my_data)
set.seed(1)
my_data[,power.sequential(0.5, N, p), by=group]

# group power mean_N
# 1:  dogs  0.90  24.48
# 2:  cats  0.94  27.72

Note: set.seed(1) has been used to keep the result consistent.