I wanted to post a tidyverse
-based solution to this and was prepared to insert the standard rant about how great dplyr and tidyr are for this kind of thing.
But given the unique format of your particular data frame, I don't think the tidyverse approach (at least not the one I came up with) is all that great.
Nonetheless, here it is:
require(tidyverse)
# an example data frame
dat <- data.frame(1:3, 2:4, 3:5, 10:12, 11:13, 12:14)
# rename each column to its position
col_positions <- 1:dim(dat)[2]
names(dat) <- col_positions
# define the number of replicates per group
N_GROUPS <- 3
# the tidyr / dplyr functions
result <-
dat %>%
mutate(row_num = row_number()) %>%
gather(column, value, -row_num) %>%
mutate(column = as.numeric(column)) %>%
mutate(col_group = ((column - 1) %/% N_GROUPS) + 1) %>%
group_by(row_num, col_group) %>%
summarize(mean_val = mean(value)) %>%
spread(col_group, mean_val) %>%
ungroup() %>%
select(-row_num)
The result
data frame looks like this:
# A tibble: 3 x 2
`1` `2`
* <dbl> <dbl>
1 2 11
2 3 12
3 4 13
...which I think is the output you want.
Let me unpack the tidyverse a bit:
mutate(row_num = row_number()) %>%
This adds a column to the data frame with the row numbers of the original data frame.
gather(column, value, -row_num) %>%
This converts the data frame to "long" format, with one record per row. So if the original data frame had six columns and n
rows, the new one will have 6*n
rows, and three columns, one named column
, one named value
and our extra row_num
column not included in the gather()
call.
mutate(column = as.numeric(column)) %>%
This makes the values in the column
column into numbers so we can use arithmetic to define the column groups.
mutate(col_group = ((column - 1) %/% N_GROUPS) + 1) %>%
The groups of columns are defined here using integer division.
group_by(row_num, col_group) %>%
We group our long data frame by row_num
(of the original data frame) and the column group we defined above.
summarize(mean_val = mean(value)) %>%
This calculates the mean of each group.
spread(col_group, mean_val)
This converts the data frame from "long" format back to the wide format.
ungroup() %>%
select(-row_num)
The last two functions just get rid of the row_num
column to get the output in the format you want. If you don't mind having the row_num
column there, you don't need them.