Стандартизировать матрицы xtab разных размеров в одно измерение

#r #list #matrix

#r #Список #матрица

Вопрос:

У меня есть список таблиц xtabs разной длины строк, но одинаковой длины столбцов. Имена строк представляют собой комбинации двух буквенных классов, например «A-B», а имена столбцов представляют собой однобуквенный класс, например «A». Я хотел бы сделать все матрицы одинакового размера, а затем добавить их.

Поскольку матрицы в списке имеют разные размеры, я знаю, что сначала мне нужно преобразовать их в одинаковые размеры, прежде чем я смогу их добавить. Я создал матрицу, которая содержит все возможные комбинации буквенных разрядов (36 x 6). Как сделать так, чтобы все матрицы в списке имели те же размеры, что и матрица 36 x 6, и обеспечить соблюдение порядка?

 row.order <- c( "Aa", "A",   "Baa", "Ba",  "B", "Caa")

# all possible combinations 
all.crossings <- expand.grid(row.order, row.order, row.order)

all.crossings <-
all.crossings %>% 
mutate(ij = paste(Var1, Var2, sep = "-"),
     k = Var2,
     Count = 0) %>%
select(ij, k, Count)

# use xtabs to transfor into matrix form
all.crossings <- xtabs(Count~ij k, data = all.crossings)
attributes(all.crossings)$class <- "matrix"
  

Вот как выглядит мой список матриц xtab:

 > data_out.2nd.ord
[[1]]
           k
ij        Aa  A Baa Ba  B Caa
  A-Ba     0  0   0  1  1   0
  A-Baa    0  0   2  1  2   0
  Aa-A     1  2   0  0  0   0
  Aa-Ba    0  0   0  1  0   0
  Aa-Baa   0  2   0  1  1   0
  B-A      0  0   0  1  0   0
  B-B      0  0   1  3 14   5
  B-Ba     0  0   1  1  3   3
  B-Baa    0  0   2  0  0   1
  B-Caa    0  0   1  3  5   7
  Ba-A     0  0   0  2  0   0
  Ba-B     0  0   2  5  3   2
  Ba-Ba    0  0   1  2  5   0
  Ba-Baa   0  1   0  1  1   1
  Ba-Caa   0  0   1  1  2   3
  Baa-A    0  0   0  2  0   0
  Baa-Aa   0  1   0  0  0   0
  Baa-B    0  0   0  2  1   2
  Baa-Ba   0  0   3  2  1   0
  Baa-Baa  1  0   3  2  1   0
  Baa-Caa  0  0   1  0  1   0
  Caa-B    0  0   0  0  6   6
  Caa-Ba   0  0   0  0  1   0
  Caa-Baa  0  0   1  0  0   0
  Caa-Caa  0  0   0  2  5  12

[[2]]
     k
ij        Aa  A Baa Ba  B Caa
  A-A      0  0   2  0  0   0
  A-Aa     0  1   0  0  0   0
  A-Ba     0  0   1  3  1   0
  Aa-A     0  1   0  0  0   0
  B-B      0  0   2  3 13   6
  B-Ba     0  0   2  4  3   1
  B-Baa    0  0   2  0  1   0
  B-Caa    0  0   1  1  8   5
  Ba-B     0  1   0  6  2   2
  Ba-Ba    1  2   2  1  1   0
  Ba-Baa   0  0   1  1  2   1
  Ba-Caa   0  0   0  2  0   1
  Baa-A    0  1   2  0  0   0
  Baa-Aa   0  1   0  0  0   0
  Baa-B    0  0   1  3  1   0
  Baa-Ba   0  1   2  1  1   0
  Baa-Baa  0  2   0  5  0   1
  Baa-Caa  0  0   0  1  1   0
  Caa-B    0  0   0  2  6   5
  Caa-Ba   0  0   1  2  0   3
  Caa-Baa  1  1   0  1  0   0
  Caa-Caa  0  0   0  1  7  14

[[3]]
     k
ij        Aa  A Baa Ba  B Caa
  A-A      0  0   0  1  1   0
  A-Baa    0  1   1  1  1   0
  Aa-A     0  2   0  0  0   0
  B-A      0  1   0  0  0   0
  B-B      0  0   2  3 14   3
  B-Ba     0  1   1  5  4   3
  B-Baa    0  0   2  0  1   0
  B-Caa    0  1   1  2  3   6
  Ba-A     0  0   2  0  1   0
  Ba-Aa    0  0   1  0  0   0
  Ba-B     0  0   0  2  2   2
  Ba-Ba    0  0   4  4  3   0
  Ba-Baa   0  0   2  2  2   2
  Ba-Caa   0  0   0  0  1   3
  Baa-A    0  0   3  0  0   0
  Baa-Aa   0  0   0  0  1   0
  Baa-B    0  0   0  2  0   1
  Baa-Ba   0  0   2  3  2   0
  Baa-Baa  0  0   2  0  1   0
  Baa-Caa  0  0   0  2  0   0
  Caa-B    0  0   0  0  9   7
  Caa-Ba   0  0   0  1  1   3
  Caa-Baa  0  0   0  1  0   0
  Caa-Caa  0  0   0  1  7  12
  

все матрицы в dput(head(lapply(data_out.2nd.ord, как.matrix),3)):

 list(structure(c(0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
2L, 0L, 2L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 2L, 0L, 0L, 0L, 0L, 1L, 1L, 2L, 
1L, 0L, 2L, 1L, 0L, 1L, 0L, 0L, 0L, 3L, 3L, 1L, 0L, 0L, 1L, 0L, 
1L, 1L, 0L, 1L, 1L, 1L, 3L, 1L, 0L, 3L, 2L, 5L, 2L, 1L, 1L, 2L, 
0L, 2L, 2L, 2L, 0L, 0L, 0L, 0L, 2L, 1L, 2L, 0L, 0L, 1L, 0L, 14L, 
3L, 0L, 5L, 0L, 3L, 5L, 1L, 2L, 0L, 0L, 1L, 1L, 1L, 1L, 6L, 1L, 
0L, 5L, 0L, 0L, 0L, 0L, 0L, 0L, 5L, 3L, 1L, 7L, 0L, 2L, 0L, 1L, 
3L, 0L, 0L, 2L, 0L, 0L, 0L, 6L, 0L, 0L, 12L), .Dim = c(25L, 6L
), .Dimnames = list(ij = c("A-Ba", "A-Baa", "Aa-A", "Aa-Ba", 
"Aa-Baa", "B-A", "B-B", "B-Ba", "B-Baa", "B-Caa", "Ba-A", "Ba-B", 
"Ba-Ba", "Ba-Baa", "Ba-Caa", "Baa-A", "Baa-Aa", "Baa-B", "Baa-Ba", 
"Baa-Baa", "Baa-Caa", "Caa-B", "Caa-Ba", "Caa-Baa", "Caa-Caa"
), k = c("Aa", "A", "Baa", "Ba", "B", "Caa")), class = c("xtabs", 
"table"), call = xtabs(formula = n ~ ij   k, data = .)), structure(c(0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 2L, 0L, 
0L, 1L, 1L, 0L, 1L, 2L, 0L, 0L, 0L, 1L, 0L, 2L, 0L, 1L, 0L, 2L, 
2L, 2L, 1L, 0L, 2L, 1L, 0L, 2L, 0L, 1L, 2L, 0L, 0L, 0L, 1L, 0L, 
0L, 0L, 0L, 3L, 0L, 3L, 4L, 0L, 1L, 6L, 1L, 1L, 2L, 0L, 0L, 3L, 
1L, 5L, 1L, 2L, 2L, 1L, 1L, 0L, 0L, 1L, 0L, 13L, 3L, 1L, 8L, 
2L, 1L, 2L, 0L, 0L, 0L, 1L, 1L, 0L, 1L, 6L, 0L, 0L, 7L, 0L, 0L, 
0L, 0L, 6L, 1L, 0L, 5L, 2L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 
5L, 3L, 0L, 14L), .Dim = c(22L, 6L), .Dimnames = list(ij = c("A-A", 
"A-Aa", "A-Ba", "Aa-A", "B-B", "B-Ba", "B-Baa", "B-Caa", "Ba-B", 
"Ba-Ba", "Ba-Baa", "Ba-Caa", "Baa-A", "Baa-Aa", "Baa-B", "Baa-Ba", 
"Baa-Baa", "Baa-Caa", "Caa-B", "Caa-Ba", "Caa-Baa", "Caa-Caa"
), k = c("Aa", "A", "Baa", "Ba", "B", "Caa")), class = c("xtabs", 
"table"), call = xtabs(formula = n ~ ij   k, data = .)), structure(c(0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 2L, 1L, 0L, 1L, 0L, 1L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
1L, 0L, 0L, 2L, 1L, 2L, 1L, 2L, 1L, 0L, 4L, 2L, 0L, 3L, 0L, 0L, 
2L, 2L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 3L, 5L, 0L, 2L, 0L, 
0L, 2L, 4L, 2L, 0L, 0L, 0L, 2L, 3L, 0L, 2L, 0L, 1L, 1L, 1L, 1L, 
1L, 0L, 0L, 14L, 4L, 1L, 3L, 1L, 0L, 2L, 3L, 2L, 1L, 0L, 1L, 
0L, 2L, 1L, 0L, 9L, 1L, 0L, 7L, 0L, 0L, 0L, 0L, 3L, 3L, 0L, 6L, 
0L, 0L, 2L, 0L, 2L, 3L, 0L, 0L, 1L, 0L, 0L, 0L, 7L, 3L, 0L, 12L
), .Dim = c(24L, 6L), .Dimnames = list(ij = c("A-A", "A-Baa", 
"Aa-A", "B-A", "B-B", "B-Ba", "B-Baa", "B-Caa", "Ba-A", "Ba-Aa", 
"Ba-B", "Ba-Ba", "Ba-Baa", "Ba-Caa", "Baa-A", "Baa-Aa", "Baa-B", 
"Baa-Ba", "Baa-Baa", "Baa-Caa", "Caa-B", "Caa-Ba", "Caa-Baa", 
"Caa-Caa"), k = c("Aa", "A", "Baa", "Ba", "B", "Caa")), class = c("xtabs", 
"table"), call = xtabs(formula = n ~ ij   k, data = .)))
  

Комментарии:

1. Вы сделали это с помощью tidyverse? Там есть что-то, что вызывает ошибку ( Error in terms.formula(formula, data = data) : object '.' not found ) при попытке присвоить этой структуре имя .

2. Да, я использовал tidyverse.

3. Как насчет замены этого вывода выводом из dput( head( lapply( data_out.2nd.ord, as.matrix), 3) , чтобы интерпретатор R попытался найти исходный источник данных? И мы не получаем результат, содержащий 15 таблиц.

4. @ 42- Я обновил вопрос с выводом.

Ответ №1:

Когда я пытаюсь вставить вывод dput из вопроса в R, он выдает ошибку, поэтому мы использовали ввод, показанный в Примечании в конце.

Вот два разных подхода.

1) zoo Устанавливает nms значение объединения имен строк, а затем преобразует каждую матрицу в zoo, используя ее имена строк в качестве индекса и объединяя каждый такой объект zoo с объектом zoo нулевой ширины, имеющим индекс nms . На этом этапе каждый объект zoo имеет одинаковые имена строк и столбцов. Наконец, суммируйте их с помощью Reduce .

 library(zoo)

nms <- Reduce(union, lapply(L, rownames))
Lz <- lapply(L, function(x) merge(zoo(x, rownames(x)), zoo(, nms), fill = 0))
m <- as.matrix(Reduce(` `, Lz))
head(m)
##       Aa A Baa Ba B Caa
## A-A    0 0   2  1 1   0
## A-Aa   0 1   0  0 0   0
## A-Ba   0 0   1  4 2   0
## A-Baa  0 1   3  2 3   0
## Aa-A   1 5   0  0 0   0
## Aa-Ba  0 0   0  1 0   0
  

2) as.data.frame Используется as.data.frame для преобразования каждого компонента списка L в длинную форму, aggregate результирующих фреймов данных, а затем используется xtabs для преобразования обратно в широкую форму.

 dd <- do.call("rbind", lapply(L, as.data.frame))
ag <- aggregate(Freq ~., dd, sum)
names(ag) <- c("ij", "k", "Freq")
xt <- xtabs(Freq ~., ag)
head(xt)
##         k
## ij       Aa A Baa Ba B Caa
##   A-Ba    0 0   1  4 2   0
##   A-Baa   0 1   3  2 3   0
##   Aa-A    1 5   0  0 0   0
##   Aa-Ba   0 0   0  1 0   0
##   Aa-Baa  0 2   0  1 1   0
##   B-A     0 1   0  1 0   0
  

Примечание

 Lines1 <- " Aa  A Baa Ba  B Caa
  A-Ba     0  0   0  1  1   0
  A-Baa    0  0   2  1  2   0
  Aa-A     1  2   0  0  0   0
  Aa-Ba    0  0   0  1  0   0
  Aa-Baa   0  2   0  1  1   0
  B-A      0  0   0  1  0   0
  B-B      0  0   1  3 14   5
  B-Ba     0  0   1  1  3   3
  B-Baa    0  0   2  0  0   1
  B-Caa    0  0   1  3  5   7
  Ba-A     0  0   0  2  0   0
  Ba-B     0  0   2  5  3   2
  Ba-Ba    0  0   1  2  5   0
  Ba-Baa   0  1   0  1  1   1
  Ba-Caa   0  0   1  1  2   3
  Baa-A    0  0   0  2  0   0
  Baa-Aa   0  1   0  0  0   0
  Baa-B    0  0   0  2  1   2
  Baa-Ba   0  0   3  2  1   0
  Baa-Baa  1  0   3  2  1   0
  Baa-Caa  0  0   1  0  1   0
  Caa-B    0  0   0  0  6   6
  Caa-Ba   0  0   0  0  1   0
  Caa-Baa  0  0   1  0  0   0
  Caa-Caa  0  0   0  2  5  12"

Lines2 <- "Aa  A Baa Ba  B Caa
  A-A      0  0   2  0  0   0
  A-Aa     0  1   0  0  0   0
  A-Ba     0  0   1  3  1   0
  Aa-A     0  1   0  0  0   0
  B-B      0  0   2  3 13   6
  B-Ba     0  0   2  4  3   1
  B-Baa    0  0   2  0  1   0
  B-Caa    0  0   1  1  8   5
  Ba-B     0  1   0  6  2   2
  Ba-Ba    1  2   2  1  1   0
  Ba-Baa   0  0   1  1  2   1
  Ba-Caa   0  0   0  2  0   1
  Baa-A    0  1   2  0  0   0
  Baa-Aa   0  1   0  0  0   0
  Baa-B    0  0   1  3  1   0
  Baa-Ba   0  1   2  1  1   0
  Baa-Baa  0  2   0  5  0   1
  Baa-Caa  0  0   0  1  1   0
  Caa-B    0  0   0  2  6   5
  Caa-Ba   0  0   1  2  0   3
  Caa-Baa  1  1   0  1  0   0
  Caa-Caa  0  0   0  1  7  14"

Lines3 <- "Aa  A Baa Ba  B Caa
  A-A      0  0   0  1  1   0
  A-Baa    0  1   1  1  1   0
  Aa-A     0  2   0  0  0   0
  B-A      0  1   0  0  0   0
  B-B      0  0   2  3 14   3
  B-Ba     0  1   1  5  4   3
  B-Baa    0  0   2  0  1   0
  B-Caa    0  1   1  2  3   6
  Ba-A     0  0   2  0  1   0
  Ba-Aa    0  0   1  0  0   0
  Ba-B     0  0   0  2  2   2
  Ba-Ba    0  0   4  4  3   0
  Ba-Baa   0  0   2  2  2   2
  Ba-Caa   0  0   0  0  1   3
  Baa-A    0  0   3  0  0   0
  Baa-Aa   0  0   0  0  1   0
  Baa-B    0  0   0  2  0   1
  Baa-Ba   0  0   2  3  2   0
  Baa-Baa  0  0   2  0  1   0
  Baa-Caa  0  0   0  2  0   0
  Caa-B    0  0   0  0  9   7
  Caa-Ba   0  0   0  1  1   3
  Caa-Baa  0  0   0  1  0   0
  Caa-Caa  0  0   0  1  7  12"

t1 <- as.table(as.matrix(read.table(text = Lines1, strip.white = TRUE)))
t2 <- as.table(as.matrix(read.table(text = Lines2, strip.white = TRUE)))
t3 <- as.table(as.matrix(read.table(text = Lines3, strip.white = TRUE)))

L <- list(t1, t2, t3)
  

Ответ №2:

Создайте функцию, которая имеет R-код для этого псевдокода для своего тела и возвращает измененный all.crossings:

 for each rowname in data-matrix{
     add this row from datamatrix to matching row in all.crossings
                                }
  

Фактический код:

 addmat <- function(X, res){ for( r in rownames(X)) { res[r, ] <- X[r,] res[r,] }; res}
  

Это должно быть довольно просто, потому что при извлечении строки может использоваться индексация символов, а затем и присвоение.

Затем выполните цикл for по элементам в data_out.2nd.ord , чтобы запустить эту функцию три раза.

  res <- all.crossings; for( s in seq_along(dat) ){  
                                    res <- addmat( dat[[s]], res=res) }
  

Результат по предложенным данным:

 > res
         k
ij        Aa A Baa Ba  B Caa
  A-A      0 0   2  1  1   0
  A-Aa     0 1   0  0  0   0
  A-B      0 0   0  0  0   0
  A-Ba     0 0   1  4  2   0
  A-Baa    0 1   3  2  3   0
  A-Caa    0 0   0  0  0   0
  Aa-A     1 5   0  0  0   0
  Aa-Aa    0 0   0  0  0   0
  Aa-B     0 0   0  0  0   0
  Aa-Ba    0 0   0  1  0   0
  Aa-Baa   0 2   0  1  1   0
  Aa-Caa   0 0   0  0  0   0
  B-A      0 1   0  1  0   0
  B-Aa     0 0   0  0  0   0
  B-B      0 0   5  9 41  14
  B-Ba     0 1   4 10 10   7
  B-Baa    0 0   6  0  2   1
  B-Caa    0 1   3  6 16  18
  Ba-A     0 0   2  2  1   0
  Ba-Aa    0 0   1  0  0   0
  Ba-B     0 1   2 13  7   6
  Ba-Ba    1 2   7  7  9   0
  Ba-Baa   0 1   3  4  5   4
  Ba-Caa   0 0   1  3  3   7
  Baa-A    0 1   5  2  0   0
  Baa-Aa   0 2   0  0  1   0
  Baa-B    0 0   1  7  2   3
  Baa-Ba   0 1   7  6  4   0
  Baa-Baa  1 2   5  7  2   1
  Baa-Caa  0 0   1  3  2   0
  Caa-A    0 0   0  0  0   0
  Caa-Aa   0 0   0  0  0   0
  Caa-B    0 0   0  2 21  18
  Caa-Ba   0 0   1  3  2   6
  Caa-Baa  1 1   1  2  0   0
  Caa-Caa  0 0   0  4 19  38
attr(,"class")
[1] "matrix"
attr(,"call")
xtabs(formula = Count ~ ij   k, data = all.crossings)
  

Комментарии:

1. Я добавил вывод

2. Глядя на мой код, мне интересно, можно ли сделать функцию addmat более эффективной? Возможно, просто: function( inp, res){ res[ rownames(inp) ] <- inp; res} , и было бы векторизовано и, вероятно, более эффективно.