Reputation: 7517
I was wondering what would be the shortest way to turn the output of my summarise()
function into my 3 desired matrices?
z <- "group y1 y2
1 1 2 3
2 1 3 4
3 1 5 4
4 1 2 5
5 2 4 8
6 2 5 6
7 2 6 7
8 3 7 6
9 3 8 7
10 3 10 8
11 3 9 5
12 3 7 6"
dat <- read.table(text = z, header = T)
dat %>%
group_by(group) %>%
summarise(cov = cov(y1, y2) * (n() - 1),
across(c(y1, y2), ~ var(.) * (n() - 1)))
# group DV1 DV2 cov
#1 1 6 2 0
#2 2 2 2 -1
#3 3 6.8 5.2 2.6
group1 = matrix(c(6,0,0,2),2)
group2 = matrix(c(2,-1,-1,2),2)
group3 = matrix(c(6.8,2.6,2.6,5.2),2)
Upvotes: 1
Views: 89
Reputation: 887118
We can do this in a much simpler way. After grouping by 'group', create a list
column in summarise
by taking the cov
of the matrix
created by cbind
ing the 'y1', 'y2', and then multiply by n() - 1
out <- dat %>%
group_by(group) %>%
summarise(mat1 = list(cov(cbind(y1, y2)) * (n() - 1)),
.groups = 'drop')
-output
out$mat1
#[[1]]
# [,1] [,2]
#[1,] 6 0
#[2,] 0 2
#[[2]]
# [,1] [,2]
#[1,] 2 -1
#[2,] -1 2
#[[3]]
# [,1] [,2]
#[1,] 6.8 2.6
#[2,] 2.6 5.2
Or this can be done with group_split
and map
library(purrr)
dat %>%
group_split(group, .keep = FALSE) %>%
map(~ cov(.x) * (nrow(.x) - 1))
In base R
, we can use split
lapply(split(dat[c('y1', 'y2')], dat$group),
function(x) cov(x) * (nrow(x) - 1))
If we need to create three 'group' objects, use list2env
library(stringr)
deframe(out) %>%
set_names(str_c('group', seq_along(.))) %>%
list2env(.GlobalEnv)
group1
# [,1] [,2]
#[1,] 6 0
#[2,] 0 2
group2
# [,1] [,2]
#[1,] 2 -1
#[2,] -1 2
group3
# [,1] [,2]
#[1,] 6.8 2.6
#[2,] 2.6 5.2
Upvotes: 1