R: Обновить матрицу смежности / фрейм данных, используя попарные комбинации

Вопрос


Допустим, у меня есть этот датафрейм:

# mock data set
df.size = 10
cluster.id<- sample(c(1:5), df.size, replace = TRUE)
letters <- sample(LETTERS[1:5], df.size, replace = TRUE)
test.set <- data.frame(cluster.id, letters)

Будет что-то вроде:

     cluster.id letters
        <int>  <fctr>
 1          5       A
 2          4       B
 3          4       B
 4          3       A
 5          3       E
 6          3       D
 7          3       C
 8          2       A
 9          2       E
10          1       A

Теперь я хочу сгруппировать их по cluster.id и посмотреть, какие буквы я могу найти в кластере, например, cluster 3 содержит буквы A,E,D,C, Тогда я хочу получить все уникальные парные комбинации (но не комбинации с самим собой, поэтому нет A,A например): A,E ; A,D, A,C etc. Затем я хочу обновить попарное расстояние для этих комбинаций в матрице смежности / фрейме данных.

идея


# group by cluster.id
# per group get all (unique) pairwise combinations for the letters (excluding pairwise combinations with itself, e.g. A,A)
# update adjacency for each pairwise combinations

Что я пробовал


# empty adjacency df
possible <- LETTERS
adj.df <- data.frame(matrix(0, ncol = length(possible), nrow = length(possible)))
colnames(adj.df) <- rownames(adj.df) <- possible


# what I tried
update.adj <- function( data ) {
  for (comb in combn(data$letters,2)) {
    # stucked
  }
}

test.set %>% group_by(cluster.id) %>% update.adj(.)

Вероятно, есть простой способ сделать это, потому что я вижу матрицы смежности все время, но я не могу понять это.. Пожалуйста, дайте мне знать, если это не ясно


Ответ на комментарий
Ответ @Manuel Bickel: Для данных, которые я привел в качестве примера (таблица под "будет что-то вроде"): эта матрица будет A ->Z для полного набора данных, имейте это в виду.

  A B C D E
A 0 0 1 1 2
B 0 0 0 0 0
C 1 0 0 1 1
D 1 0 1 0 1
E 2 0 1 1 0

Я объясню, что я сделал:

    cluster.id letters
        <int>  <fctr>
 1          5       A
 2          4       B
 3          4       B
 4          3       A
 5          3       E
 6          3       D
 7          3       C
 8          2       A
 9          2       E
10          1       A

Уместны только кластеры, содержащие более 1 уникальной буквы (потому что нам не нужны комбинации с самим собой, например, кластер 1, содержащий только букву B, поэтому это приведет к комбинации B,B и поэтому не актуально)

 4          3       A
 5          3       E
 6          3       D
 7          3       C
 8          2       A
 9          2       E

Теперь я смотрю для каждого кластера, какие парные комбинации я могу сделать:

кластер 3:

A,E
A,D
A,C
E,D
E,C
D,C

Обновите эти комбинации в матрице смежности:

    A B C D E
    A 0 0 1 1 1
    B 0 0 0 0 0
    C 1 0 0 1 1
    D 1 0 1 0 1
    E 2 0 1 1 0

Затем перейдите к следующему кластеру

кластер 2

А, Е

Обновите матрицу смежности снова:

 A B C D E
A 0 0 1 1 2 <-- note the 2 now
B 0 0 0 0 0
C 1 0 0 1 1
D 1 0 1 0 1
E 2 0 1 1 0

Как реакция на огромный набор данных

library(reshape2)

test.set <- read.table(text = "
                            cluster.id   letters
                       1          5       A
                       2          4       B
                       3          4       B
                       4          3       A
                       5          3       E
                       6          3       D
                       7          3       C
                       8          2       A
                       9          2       E
                       10          1       A", header = T, stringsAsFactors = F)

x1 <- reshape2::dcast(test.set, cluster.id ~ letters)

x1
#cluster.id A B C D E
#1          1 1 0 0 0 0
#2          2 1 0 0 0 1
#3          3 1 0 1 1 1
#4          4 0 2 0 0 0
#5          5 1 0 0 0 0

x2 <- table(test.set)

x2
#          letters
#cluster.id A B C D E
#         1 1 0 0 0 0
#         2 1 0 0 0 1
#         3 1 0 1 1 1
#         4 0 2 0 0 0
#         5 1 0 0 0 0


x1.c <- crossprod(x1)
#Error in crossprod(x, y) : 
#  requires numeric/complex matrix/vector arguments

x2.c <- crossprod(x2)
#works fine

1 ответ

Решение

После вышеупомянутого комментария, здесь код Тайлера Ринкера, используемый с вашими данными. Я надеюсь, что это то, что вы хотите.

ОБНОВЛЕНИЕ: Следуя комментариям ниже, я добавил решение, используя пакет reshape2 для того, чтобы иметь возможность обрабатывать большие объемы данных.

test.set <- read.table(text = "
                            cluster.id   letters
                       1          5       A
                       2          4       B
                       3          4       B
                       4          3       A
                       5          3       E
                       6          3       D
                       7          3       C
                       8          2       A
                       9          2       E
                       10          1       A", header = T, stringsAsFactors = F)

x <- table(test.set)
x
          letters
#cluster.id A B C D E
#         1 1 0 0 0 0
#         2 1 0 0 0 1
#         3 1 0 1 1 1
#         4 0 2 0 0 0
#         5 1 0 0 0 0

#base approach, based on answer by Tyler Rinker
x <- crossprod(x)
diag(x) <- 0 #this is to set matches such as AA, BB, etc. to zero
x

#         letters
# letters 
#         A B C D E
#       A 0 0 1 1 2
#       B 0 0 0 0 0
#       C 1 0 0 1 1
#       D 1 0 1 0 1
#       E 2 0 1 1 0

#reshape2 approach
x <- acast(test.set, cluster.id ~ letters)
x <- crossprod(x)
diag(x) <- 0
x
#   A B C D E
# A 0 0 1 1 2
# B 0 0 0 0 0
# C 1 0 0 1 1
# D 1 0 1 0 1
# E 2 0 1 1 0
Другие вопросы по тегам