观察结果在 R 行中一起出现的频率

How often observations occur together in rows R

我有一个与下面的数据框相当的数据框:

V1 V2 V3 V4 V5 V6 V7
 A B  C  D  NA NA NA
 A E  F  NA NA NA NA
 D A  C  B  F  E  NA
 A E  NA NA NA NA NA

每一行都是一个病人,数据框中的每个字母代表一个特定的诊断。

我想了解特定诊断一起出现的频率, 例如诊断 A 与诊断 E 按行发生了多少次? (三次)。

I am hoping to produce a matrix like this:
  A B C D E F
A 0 2 2 2 3 2
B 2 0 2
C 2 2 0 etc etc
D 2
E 3
F 2

(I have not completely filled it out)

它本质上是一个邻接矩阵,除了观察值不需要直接相邻,它们只需要在同一行即可。

从这里我会制作一个和弦图。

感谢您的帮助!

我认为手工构建它会很有趣。该算法非常简单。对于每个患者,找到同时发生的诊断并将其写入上三角矩阵。

set.seed(357)
xy <- matrix(sample(LETTERS[1:15], size = 80, replace = TRUE), nrow = 8)

> head(xy)
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] "G"  "F"  "M"  "N"  "D"  "G"  "N"  "H"  "K"  "K"  
[2,] "H"  "I"  "C"  "K"  "H"  "E"  "H"  "E"  "I"  "G"  
[3,] "G"  "C"  "C"  "L"  "N"  "F"  "M"  "K"  "C"  "E"  
[4,] "A"  "K"  "G"  "O"  "I"  "C"  "C"  "B"  "O"  "I"  
[5,] "K"  "O"  "E"  "B"  "M"  "O"  "F"  "C"  "L"  "N"  
[6,] "D"  "H"  "K"  "H"  "I"  "N"  "B"  "F"  "A"  "H" 

# Find all unique diagnoses.
all.diagnoses <- unique(as.vector(xy))
all.diagnoses <- sort(as.character(all.diagnoses))

# This is a way of creating an empty matrix.
out <- matrix(rep(NA, length(all.diagnoses)^2), nrow = length(all.diagnoses),
              dimnames = list(all.diagnoses, all.diagnoses))

for (i in 1:nrow(xy)) {
  combinations <- combn(unique(xy[i, ]), m = 2, simplify = FALSE)
  for (j in 1:length(combinations)) {
    # Add occurrence of each combination to the corresponding combination.
    com <- sort(combinations[[j]])
    out[com[1], com[2]]  <- sum(out[com[1], com[2]], 1, na.rm = TRUE)
  }
}

> out
   A  B  C  D  E  F  G  H  I  J  K  L  M  N  O
A NA  2  1  2 NA  1  1  1  2  1  3  1  1  2  2
B NA NA  2  1  1  2  1  1  2 NA  3  1  1  2  2
C NA NA NA NA  3  2  3  1  2 NA  4  2  2  2  2
D NA NA NA NA NA  2  1  3  2  2  3  1  3  4  2
E NA NA NA NA NA  2  2  1  1 NA  3  2  2  2  1
F NA NA NA NA NA NA  2  2  1 NA  4  2  3  4  1
G NA NA NA NA NA NA NA  2  2 NA  4  1  2  2  1
H NA NA NA NA NA NA NA NA  3  1  3 NA  2  3  1
I NA NA NA NA NA NA NA NA NA  1  3 NA  1  2  2
J NA NA NA NA NA NA NA NA NA NA  1  1  2  2  2
K NA NA NA NA NA NA NA NA NA NA NA  3  4  5  3
L NA NA NA NA NA NA NA NA NA NA NA NA  3  3  2
M NA NA NA NA NA NA NA NA NA NA NA NA NA  5  3
N NA NA NA NA NA NA NA NA NA NA NA NA NA NA  3
O NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA

这是另一种方法,它使用 自连接 为每位患者创建可能的诊断组合:

library(data.table)
library(magrittr)
co_occ_mat <- function(DT) {
  DT[, id := .I] %>% 
    melt("id", na.rm = TRUE, value.name = "diagnosis") %>% 
    unique(by = c("id", "diagnosis")) %>% 
    .[., on = .(id), allow.cartesian = TRUE] %>% 
    .[diagnosis != i.diagnosis] %>% 
    dcast(diagnosis ~ i.diagnosis, length)
} 

有了OP的样本数据,co_occ_mat() returns

fread("V1 V2 V3 V4 V5 V6 V7
 A B  C  D  NA NA NA
 A E  F  NA NA NA NA
 D A  C  B  F  E  NA
 A E  NA NA NA NA NA") %>% 
  co_occ_mat()
   diagnosis A B C D E F
1:         A 0 2 2 2 3 2
2:         B 2 0 2 2 1 1
3:         C 2 2 0 2 1 1
4:         D 2 2 2 0 1 1
5:         E 3 1 1 1 0 2
6:         F 2 1 1 1 2 0

符合OP的预期结果。

co_occ_mat()中的步骤是:

  1. 为每一行添加一个 id 列,即 patient
  2. 重塑为长格式
  3. 删除任何重复项,以防对一位患者的诊断报告不止一次
  4. 通过笛卡尔自连接为每个 id
  5. 创建诊断对
  6. 删除两个诊断相同的对的琐碎案例
  7. 通过重塑为宽格式并计算患者数量来创建共现矩阵

使用来自

的数据
RNGversion("3.6.0")
set.seed(357)
matrix(sample(LETTERS[1:15], size = 80, replace = TRUE), nrow = 8) %>% 
  as.data.table() %T>% print() %>% 
  co_occ_mat()
   V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1:  G  F  M  N  D  G  N  H  K   K
2:  H  I  C  K  H  E  H  E  I   G
3:  G  C  C  L  N  F  M  K  C   E
4:  A  K  G  O  I  C  C  B  O   I
5:  K  O  E  B  M  O  F  C  L   N
6:  D  H  K  H  I  N  B  F  A   H
7:  J  N  D  J  L  K  M  A  O   O
8:  J  D  I  M  O  H  N  O  H   H

我们得到

    diagnosis A B C D E F G H I J K L M N O
 1:         A 0 2 1 2 0 1 1 1 2 1 3 1 1 2 2
 2:         B 2 0 2 1 1 2 1 1 2 0 3 1 1 2 2
 3:         C 1 2 0 0 3 2 3 1 2 0 4 2 2 2 2
 4:         D 2 1 0 0 0 2 1 3 2 2 3 1 3 4 2
 5:         E 0 1 3 0 0 2 2 1 1 0 3 2 2 2 1
 6:         F 1 2 2 2 2 0 2 2 1 0 4 2 3 4 1
 7:         G 1 1 3 1 2 2 0 2 2 0 4 1 2 2 1
 8:         H 1 1 1 3 1 2 2 0 3 1 3 0 2 3 1
 9:         I 2 2 2 2 1 1 2 3 0 1 3 0 1 2 2
10:         J 1 0 0 2 0 0 0 1 1 0 1 1 2 2 2
11:         K 3 3 4 3 3 4 4 3 3 1 0 3 4 5 3
12:         L 1 1 2 1 2 2 1 0 0 1 3 0 3 3 2
13:         M 1 1 2 3 2 3 2 2 1 2 4 3 0 5 3
14:         N 2 2 2 4 2 4 2 3 2 2 5 3 5 0 3
15:         O 2 2 2 2 1 1 1 1 2 2 3 2 3 3 0

出于某种我还不明白的原因,需要在 set.seed(357) 之前调用 RNGversion("3.6.0") 才能重现 Roman 的随机数。

请注意,此测试用例包含每个患者的重复诊断,例如,第 1 行中的 K

这是另一个使用 table 的基本 R 选项:

pairs <- as.data.frame(do.call(rbind, 
    apply(dat, 1L, function(x) t(combn(na.omit(x), 2L)))))

tab <- table(pairs)
ut <- tab
ut[lower.tri(tab)] <- 0L
lt <- tab
lt[upper.tri(tab)] <- 0L
ans <- t(lt) + ut
ans + t(ans)

输出:

   V1
V2  A B C D E F
  A 0 2 2 2 3 2
  B 2 0 2 2 1 1
  C 2 2 0 2 1 1
  D 2 2 2 0 1 1
  E 3 1 1 1 0 2
  F 2 1 1 1 2 0

数据:

dat <- read.table(text="V1 V2 V3 V4 V5 V6 V7
A B  C  D  NA NA NA
A E  F  NA NA NA NA
D A  C  B  'F'  E  NA
A E  NA NA NA NA NA", header=TRUE, colClasses="character")