свернуть/агрегировать некоторые части матрицы смежности одновременно по строкам и столбцам

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

jobnames <-  c("job 1","job 2","job 3","job 4","job 5","job 6","job 7")
jobdat <- matrix(c(
5, 5, 5, 0, 0, 5, 5,
5, 5, 2, 5, 5, 1, 5,
1, 5, 5, 5, 0, 0, 1,
1, 0, 5, 5, 8, 0, 1,
0, 5, 0, 0, 5, 5, 1,
0, 0, 5, 5, 0, 5, 5,
0, 1, 0, 0, 5, 1, 5
           ), 
           nrow = 7, ncol = 7, byrow = TRUE,
           dimnames = list(jobnames,jobnames
                ))

В анализе социальных сетей это рассматривается как направленная взвешенная матрица смежности. Направление сети — от строк к столбцам: Таким образом, мобильность определяется как переход от строки задания к столбцу задания. Диагональ актуальна, так как есть возможность перейти на ту же работу в другую фирму.

Мне нужно свернуть эту матрицу в соответствии с предварительно заданным списком, содержащим индексы заданий, которые следует объединить:

group.list  <-  list(grp1=c(1,2) ,grp2 =c(3,4))

Теперь, поскольку это матрица смежности, она немного отличается от других ответов о том, как свернуть матрицу, которые я нашел здесь и в других местах. Свертывание должно быть одновременным как в строках, так и в столбцах. А некоторые задания вообще не сгруппированы. Таким образом, результат в этом примере должен быть таким:

group.jobnames <-  c("job 1 and 2","job 3 and 4","job 5","job 6","job 7")

 group.jobdat <- matrix(c(
            20,12,5,6,10,
            7,17,8,0,2,
            5,0,5,5,1,
            0,10,0,5,5,
            1,0,5,1,5
            ),
           nrow = 5, ncol = 5, byrow = TRUE,
           dimnames = list(group.jobnames,group.jobnames
                ))

В этом примере группируются два первых задания, а затем два следующих, но в моих реальных данных это может быть любая комбинация (индексов) заданий и любое количество заданий в каждой группе. Таким образом, задание [1,7] могло быть одной группой, а задание [2,3,6] могло быть другой группой, а задание 4 или 5 не группировались. Или любое другое сочетание.

Спасибо за уделенное время,


person emilBeBri    schedule 23.01.2017    source источник
comment
Я не могу реплицировать group.jobdat, учитывая группы, которые вы предоставляете в group.list, и код, создающий group.jobdat, выдает ошибку.   -  person lmo    schedule 23.01.2017
comment
Хорошо, извините, что я не могу исправить это до завтрашнего утра, когда я снова буду за своим компьютером с R.   -  person emilBeBri    schedule 24.01.2017
comment
Звучит неплохо. Дайте мне знать, когда вы это сделаете, и я посмотрю.   -  person lmo    schedule 24.01.2017
comment
отлично, спасибо. Теперь это должно быть воспроизведено.   -  person emilBeBri    schedule 24.01.2017


Ответы (1)


Я считаю, что в предполагаемом выводе и определении group.list есть некоторые опечатки. Если я прав в своей интерпретации, вот решение.

Вот новый group.list, соответствующий именам желаемого вывода. В этой версии группа 2 сопоставляется с 1, а группа 4 сопоставляется с 3, что соответствует тексту в group.jobs.

group.list <- list(grp1=c(1, 3), grp2=c(2, 4))

Имея этот список, постройте вектор группировки

# initial grouping
groups <- seq_len(ncol(jobdat))
# map elements of second list item to values of first list item
groups[match(group.list[["grp2"]], groups)] <- group.list[["grp1"]]

groups
[1] 1 1 3 3 5 6 7

Итак, теперь группы 1 и 2 такие же, как и группы 3 и 4. Теперь мы используем rowsum и пару транспонирований для вычисления вывода.

myMat <- t(rowsum(t(rowsum(jobdat, groups)), groups))
# add the group names
dimnames(myMat) <- list(group.jobnames,group.jobnames)

myMat
            job 1 and 2 job 3 and 4 job 5 job 6 job 7
job 1 and 2          20          12     5     6    10
job 3 and 4           7          20     8     0     2
job 5                 5           0     5     5     1
job 6                 0          10     0     5     5
job 7                 1           0     5     1     5

В ответ на комментарии OP ниже, группировка должна была находиться внутри элементов списка, а не в соответствующих позициях между элементами списка, как я первоначально интерпретировал. Чтобы выполнить эту форму группировки, повторная подача от replace до Reduce выполнит задачу. С group.list, как и в вопросе,

group.list <- list(grp1=c(1, 2), grp2=c(3, 4))

groups <- Reduce(function(x, y) replace(x, x[x %in% y], min(y)),
                 c(list(groups), unname(group.list)))
groups
[1] 1 1 3 3 5 6 7

Здесь replace берет исходную группу, находит элементы в группе, которые находятся в одном из векторов в group.list, и заменяет их минимальным значением этого вектора. Функция Reduce неоднократно применяет эту операцию к исходной групповой переменной, за исключением изменения ее на каждой итерации.

С этим результатом мы используем вышеупомянутые транспозиции и rowsum, чтобы получить

myMat
            job 1 and 2 job 3 and 4 job 5 job 6 job 7
job 1 and 2          20          12     5     6    10
job 3 and 4           7          20     8     0     2
job 5                 5           0     5     5     1
job 6                 0          10     0     5     5
job 7                 1           0     5     1     5
person lmo    schedule 24.01.2017
comment
Я мог бы поклясться, что исправил это сегодня утром. Должно быть забыл нажать сохранить редактирование или что-то в этом роде. Во всяком случае: это почти там! Но это не совсем так, из-за моей опечатки в коде. Итак, есть два аспекта этой проблемы, чтобы я мог понять/использовать это. Я вижу логику в шаге с rowsums/transpose (за исключением того, что я нахожу это немного странным, что нет соответствующей функции colsum() для rowsum(), но что угодно) - person emilBeBri; 24.01.2017
comment
1) Теперь group.list верен правильно, и это не так, как вы его интерпретировали: (также исправлено в моем вопросе): ` group.list ‹- list( grp1=c(1, 2), grp2=c(3, 4))` Так устроен мой групповой список. Однако, если я использую список таким образом, то задание 1 и задание 3 группируются, а задание 2 и 4... И это приводит ко второй проблеме: 2) Я немного запутался, как это сделать со сколь угодно большим количеством групп. В моем фактическом наборе данных 80 групп (+ и небольшое количество заданий, которые не сгруппированы, но также должны быть в новой матрице), - person emilBeBri; 24.01.2017
comment
Большое спасибо, вы действительно помогли мне с чем-то важным в моей диссертации здесь. Хороших выходных. - person emilBeBri; 27.01.2017