data.frame 行中公共值的成对计数

Pairwise count of common values in rows of a data.frame

提问人:Ilaria 提问时间:2/4/2023 最后编辑:Darren TsaiIlaria 更新时间:2/6/2023 访问量:142

问:

我有一个包含许多行 (>9000) 和列 (148) 的数据框。第一列具有用于实验的唯一代码,其他列填充了实验中测试的克隆的名称。我想要一个矩阵,其中包含每个实验中常见克隆的数量(成对)。

我的数据集示例:

Exp_No    Clone1    Clone2   Clone3    Clone4
Exp1      Egxn2     Egxn11   Egxn6     Egxn13
Exp2      Egxn4     Egxn13   Egxn16    Egxn6
Exp3      Egxn2     Egxn6    Egxn11    Egxn18
Exp4      Egxn6     Egxn14   Egxn4     Egxn18
Exp5      Egxn2     Egxn11   Egxn6     Egxn13
Exp6      Egxn4     Egxn2    Egxn5     Egxn18

我需要什么:

Exp1  Exp2  2
Exp1  Exp3  3
Exp1  Exp4  1    
Exp1  Exp5  4
Exp1  Exp6  1
Exp2  Exp3  1
Exp2  Exp4  2
...

以此类推,适用于所有行对。有什么建议吗?提前谢谢你,已经上几个小时了!我找不到解决这个问题的方法。

R 数据帧 成对 比较

评论


答:

1赞 Darren Tsai 2/4/2023 #1

您可以堆叠所有列,然后按克隆的名称将其合并到自身。Clone

因为dplyr 1.1.0
library(dplyr)

df_long <- df %>%
  tidyr::pivot_longer(contains('Clone'), names_to = NULL)

df_long %>%
  inner_join(df_long, by = join_by(value, y$Exp_No > x$Exp_No)) %>%
  count(Exp_No.x, Exp_No.y)

# # A tibble: 15 × 3
#    Exp_No.x Exp_No.y     n
#    <chr>    <chr>    <int>
#  1 Exp1     Exp2         2
#  2 Exp1     Exp3         3
#  3 Exp1     Exp4         1
#  4 Exp1     Exp5         4
#  5 Exp1     Exp6         1
#  6 Exp2     Exp3         1
#  7 Exp2     Exp4         2
#  8 Exp2     Exp5         2
#  9 Exp2     Exp6         1
# 10 Exp3     Exp4         2
# 11 Exp3     Exp5         3
# 12 Exp3     Exp6         2
# 13 Exp4     Exp5         1
# 14 Exp4     Exp6         2
# 15 Exp5     Exp6         1

dplyr 1.0.0或更早
df_long %>%
  inner_join(df_long, by = "value") %>%
  filter(Exp_No.y > Exp_No.x) %>%
  count(Exp_No.x, Exp_No.y)

数据
df <- read.table(text = "
Exp_No    Clone1    Clone2   Clone3    Clone4
Exp1      Egxn2     Egxn11   Egxn6     Egxn13
Exp2      Egxn4     Egxn13   Egxn16    Egxn6
Exp3      Egxn2     Egxn6    Egxn11    Egxn18
Exp4      Egxn6     Egxn14   Egxn4     Egxn18
Exp5      Egxn2     Egxn11   Egxn6     Egxn13
Exp6      Egxn4     Egxn2    Egxn5     Egxn18", header = TRUE)

评论

0赞 Ilaria 2/4/2023
谢谢达伦,它有效!我只需要在内存不足时拆分文件,但它可以工作!谢谢limmion!
1赞 jblood94 2/5/2023 #2

根据评论更新:

tcrossprod在稀疏矩阵上会提供良好的性能。使用 131 行和 165 列进行演示,其中 s 存在:NA

library(Matrix) # for sparse matrices
library(data.table) # final solution will be stored as a data.table

m <- as(
  triu( # get the upper triangle of the symmetric matrix
    tcrossprod( # tcrossprod to get the pairwise common clone counts
      # convert the data.frame to a sparse matrix with nrow(df) rows and
      # length(unique(unlist(df[,-1]))) columns (the number of unique clones
      # in the dataset)
      sparseMatrix(
        rep(1:131, 165)[i <- which(!is.na(cl <- unlist(df[,-1], 0, 0)))],
        as.numeric(gsub("Egxn", "", cl[i])),
        x = 1L
      )
    ), k = 1 # don't keep the diagonal (comparing rows with themselves)
  ), "TsparseMatrix" # set the result as a triangular matrix
)

# build the final answer
dtPairs <- setorder(
  data.table(
    # the Exp1 and Exp2 columns are row indices from df
    # sparse matrix indices are zero-based, so add one
    Exp1 = attr(m, "i") + 1L,
    Exp2 = attr(m, "j") + 1L,
    Common = attr(m, "x")
  ), Exp1, Exp2 # sort by Exp1 then by Exp2
)

dtPairs[1:10,]
#>     Exp1 Exp2 Common
#>  1:    1    2     18
#>  2:    1    3     26
#>  3:    1    4     11
#>  4:    1    5     13
#>  5:    1    6     25
#>  6:    1    7      6
#>  7:    1    8     10
#>  8:    1    9     17
#>  9:    1   10     23
#> 10:    1   11     13

nrow(dtPairs)
#> [1] 8515

数据:

df <- cbind(
  data.frame(Exp_No = paste0("Exp", 1:131)),
  matrix(
    replicate(131, c(sample(paste0("Egxn", 1:1e3), cl <- sample(100:165, 1)), rep(NA_character_, 165L - cl))),
    131, 165, 1, list(NULL, paste0("Clone", 1:165))
  )
)

评论

0赞 Ilaria 2/6/2023
嗨,jblood94 和 @Darren Tsai,当用于整个数据集时,我无法让代码工作。我已经消除了一些我可以没有的记录,我的数据集现在由 131 个实验制作,其中种植了不同数量的克隆(最多 165 个)。由于在每次实验中植入的克隆数量不是恒定的,因此某些行将具有 NA。有没有办法让我上传 csv 以便您可以运行您的脚本?我不确定 NA 是否导致脚本错误地计算了常见克隆的数量。.再次感谢您的帮助,非常感谢!
0赞 jblood94 2/6/2023
您只需要在构建稀疏矩阵时删除 s。查看更新。NA
0赞 Ilaria 2/15/2023
嗨,jblood94,感谢您再次提供帮助!将尝试再次运行脚本。伊拉里亚