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