How to take the average of every 3 rows ?

mydf <- data.frame("results"=seq(1:12))

How can I take the average of every 3 rows?

I tried using sweep but I get errors like Error in array(STATS, dims[perm]) : 'dims' cannot be of length 0

Is this what yo are trying to do?

mydf <- data.frame("results"=seq(1:12))
GroupLabels <- 0:(nrow(mydf) - 1) %/%  3
mydf$Group <- GroupLabels
library(dplyr)
Avgs <- mydf %>% group_by(Group) %>% summarize(Avg = mean(results))
`summarise()` ungrouping output (override with `.groups` argument)
Avgs
# A tibble: 4 x 2
  Group   Avg
  <dbl> <dbl>
1     0     2
2     1     5
3     2     8
4     3    11
1 Like

@FJCC

Oh, I can see how your solution works here but it points out that I think my question isn't properly clarified.

EDIT:

Maybe I should just ask you if you know of a solution to get the exact problem I'm struggling with. I have a data frame with hundreds of rows. I want to take the average of every 3 rows, and place them into the rows from which they were averaged (which means all averaged results will be repeated x3). And, since my list is already sorted in order of replicates I want to apply "R1", "R2", and "R3" as a pattern all the way down.

Here's what I ultimately have been trying to get to:

data averages replicate
1 2 R1
2 2 R2
3 2 R3
4 5 R1
5 5 R2
6 5 R3
7 8 R1
8 8 R2
9 8 R3
10 11 R1
11 11 R2
12 11 R3
13 14 R1
14 14 R2
15 14 R3
16 17 R1
17 17 R2
18 17 R3

EDIT2:

I got the second part, now it says R1/R2/R3 repeating all the way down

mydf$replicate[seq(1,nrow(mydf),3,)] <- "R1"
mydf$replicate[seq(2,nrow(mydf),3,)] <- "R2"
mydf$replicate[seq(3,nrow(mydf),3,)] <- "R3"

You can use inner_join() to include the calculated averages in the original data frame and, as long as the data always has data in groups of three, it is easy to add the replicate labels.

mydf <- data.frame("results"=seq(1:12))
GroupLabels <- 0:(nrow(mydf) - 1)%/% 3
mydf$Group <- GroupLabels
library(dplyr)
Avgs <- mydf %>% group_by(Group) %>% summarize(Avg = mean(results))
`summarise()` ungrouping output (override with `.groups` argument)
mydf <- inner_join(mydf, Avgs, by = "Group") %>% 
   select(-Group) %>% 
   mutate(Replicate = rep(c("R1", "R2", "R3"), nrow(mydf)/3))
mydf
   results Avg Replicate
1        1   2        R1
2        2   2        R2
3        3   2        R3
4        4   5        R1
5        5   5        R2
6        6   5        R3
7        7   8        R1
8        8   8        R2
9        9   8        R3
10      10  11        R1
11      11  11        R2
12      12  11        R3
1 Like

This works!!!

Many thanks!

find_means <- function(x,y,z) {
  stopifnot(length(x:y) %% z == 0)
  for (i in z) do.call(rbind,split(x:y, rep(1:z, length(x:y)/z))) -> m
  return(colMeans(m))
}

find_means(1,12,3)
#> [1]  2  5  8 11

when using mutate instead of summarise we can even skip the inner_join:

Avgs <- mydf %>% 
   group_by(Group) %>% 
   mutate(Avg = mean(results)) %>% 
    # as the data is still grouped we can just define the 3 replicates
   mutate(Replicate = rep(c("R1", "R2", "R3")))

@FJCC

Hi again FJCC,

I've been spending some time trying to apply a previous solution you helped me with (here in this thread) to additionally performing a t-test (in addition to taking means).

So, if I have a data frame like this:

mydf <- data.frame("replicate"=c("R1","R2","R3","R1","R2","R3","R1","R2","R3","R1","R2","R3","R1","R2","R3","R1","R2","R3"),
                   "variables"=c(1,1.1,2,10,11,10.1,100,100.1,100.2,2,2.1,2.2,11,11.1,11.2,500,500.5,500.1),
                   "mu"=c(1,1,1,10,10,10,100,100,100,2,2,2,11,11,11,5,5,5))

There are groups of 3 just like last time. For the first group of 3, the t.test code would be
t.test(c(1.0,1.1,2.0), mu=1

But I want to apply it using something similar to how you previously showed me how to get averages by these groups. The trouble is - I can't seem to easily swap out mean for t.test

#Trying to add a p-value 
GroupLabels <- 0:(nrow(mydf) - 1)%/% 3
mydf$Group <- GroupLabels
pval <- mydf %>% group_by(Group) %>% summarize(pval = t.test(variables, mu=mu))
mydf <- inner_join(mydf, pval, by = "Group") %>% 
  select(-Group)

I get this:

Error: Problem with `summarise()` input `pval`.
x 'mu' must be a single number
i Input `pval` is `t.test(variables, mu = mu)`.
i The error occurred in group 1: Group = 0.
Run `rlang::last_error()` to see where the error occurred.

Do I need to group these differently?

There are two problems with your code. Within your call to t.test, you pass your mu column to the mu parameter. But the mu column is a vector of three values for every group. All of the values are the same but that still does not satisfy the requirement that mu be a single number. You can fix that by passing the mu column to a function that returns a single value. I chose mean() but you could use median, max, min or any other function that returns one value from the three you give it. The second problem is that you assign the value of t.text() to the new column pval but t.test() does not return a single value, it returns a list of values. You need to extract the p value from that list. Try this

mydf <- data.frame("replicate"=c("R1","R2","R3","R1","R2","R3","R1","R2","R3","R1","R2","R3","R1","R2","R3","R1","R2","R3"),
                   "variables"=c(1,1.1,2,10,11,10.1,100,100.1,100.2,2,2.1,2.2,11,11.1,11.2,500,500.5,500.1),
                   "mu"=c(1,1,1,10,10,10,100,100,100,2,2,2,11,11,11,5,5,5))
GroupLabels <- 0:(nrow(mydf) - 1)%/% 3
mydf$Group <- GroupLabels
pval <- mydf %>% group_by(Group) %>% summarize(pval = t.test(variables, mu=mean(mu))$p.value)
mydf <- inner_join(mydf, pval, by = "Group") %>% 
  select(-Group)
1 Like

Thank you!

I was tinkering with others ways of just taking any value of the mu column since all 3 are the same, but taking the mean works well too. My main problem was exactly as you mentioned ; I need to get the p-value from the list returned by t.test().

Thanks again!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.