I want to convert a data frame into a list matrices for each group within my data set (each group has different number of individuals). The column containing actor names should be the rows and the receiver columns should be the columns, in the matrix. Lastly, the matrix should be filled with the numbers from another columns. The data frame looks something like this -
Group Actor Receiver Count
A AA AB 3
A AA AH 6
A AB AH 3
...
And I would like to convert it to
[[A]]
[,AA] [,AB] [,AC] [,AH]
[AA,] 0 3 0 6
[AB,] 0 0 0 3
[AC,] 0 0 0 0
[AH,] 0 0 0 0
followed by matrices for other groups.
CodePudding user response:
We could split the data by 'Group' and use xtabs
lapply(split(df1[-1], df1$Group), function(x)
{
lvls <- sort(unique(c(unlist(x[1:2]), "AC")))
x[1:2] <- lapply(x[1:2], factor, levels = lvls)
xtabs(Count ~ Actor Receiver, data = x)
})
-output
$A
Receiver
Actor AA AB AC AH
AA 0 3 0 6
AB 0 0 0 3
AC 0 0 0 0
AH 0 0 0 0
If we need to convert back
lst1 <- lapply(split(df1[-1], df1$Group), function(x)
{
lvls <- sort(unique(c(unlist(x[1:2]), "AC")))
x[1:2] <- lapply(x[1:2], factor, levels = lvls)
as.data.frame(xtabs(Count ~ Actor Receiver, data = x))
})
out <- do.call(rbind, Map(cbind, Group = names(lst1), lst1))
row.names(out) <- NULL
-output
> out
Group Actor Receiver Freq
1 A AA AA 0
2 A AB AA 0
3 A AC AA 0
4 A AH AA 0
5 A AA AB 3
6 A AB AB 0
7 A AC AB 0
8 A AH AB 0
9 A AA AC 0
10 A AB AC 0
11 A AC AC 0
12 A AH AC 0
13 A AA AH 6
14 A AB AH 3
15 A AC AH 0
16 A AH AH 0
Or may also convert to a 3D array with xtabs
and reconvert with as.data.frame
lvls <- sort(unique(unlist(df1[2:3])))
as.data.frame(xtabs(Count ~ Actor Receiver Group,
transform(df1, Actor = factor(Actor, levels = lvls),
Receiver = factor(Receiver, levels = lvls))))
We may be able to expand the data without having to reshape and then reconvert
library(dplyr)
library(tidyr)
df1 %>%
group_by(Group) %>%
complete(Actor = sort(unique(c(Actor, Receiver, "AC"))),
Receiver = sort(unique(c(Actor, Receiver, "AC"))),
fill = list(Count = 0)) %>%
ungroup
-output
# A tibble: 16 × 4
Group Actor Receiver Count
<chr> <chr> <chr> <int>
1 A AA AA 0
2 A AA AB 3
3 A AA AC 0
4 A AA AH 6
5 A AB AA 0
6 A AB AB 0
7 A AB AC 0
8 A AB AH 3
9 A AC AA 0
10 A AC AB 0
11 A AC AC 0
12 A AC AH 0
13 A AH AA 0
14 A AH AB 0
15 A AH AC 0
16 A AH AH 0
data
df1 <- structure(list(Group = c("A", "A", "A"), Actor = c("AA", "AA",
"AB"), Receiver = c("AB", "AH", "AH"), Count = c(3L, 6L, 3L)),
class = "data.frame", row.names = c(NA,
-3L))