【问题标题】:Clustering using daisy and pam in R在 R 中使用 daisy 和 pam 进行聚类
【发布时间】:2026-02-10 03:05:02
【问题描述】:

我正在尝试执行非常简单的聚类分析,但无法获得正确的结果。我对大型数据集的问题是“哪些疾病经常一起报告?”。下面的简化数据样本应导致 2 个集群:1)头痛/头晕 2)恶心/腹痛。但是,我无法正确获取代码。我正在使用pamdaisy 函数。对于这个例子,我手动分配了 2 个集群 (k=2),因为我知道所需的结果,但实际上我探索了几个 k 值。

有谁知道我在这里做错了什么?

library(cluster)
library(dplyr)

dat <- data.frame(ID = c("id1","id1","id2","id2","id3","id3","id4","id4","id5","id5"),
                  PTName = c("headache","dizziness","nausea","abd pain","dizziness","headache","abd pain","nausea","headache","dizziness"))


gower_dist <- daisy(dat, metric = "gower")
k <- 2
pam_fit <- pam(gower_dist, diss = TRUE, k)  # performs cluster analysis
pam_results <- dat %>%
  mutate(cluster = pam_fit$clustering) %>%
  group_by(cluster) %>%
  do(the_summary = summary(.))
head(pam_results$the_summary)

【问题讨论】:

    标签: r cluster-analysis r-daisy


    【解决方案1】:

    您将数据集提供给聚类算法的格式不适合您的目标。事实上,如果您想将报告的疾病分组在一起,但同时在相异矩阵中包含 ID,它们将在矩阵构造中占有一席之地,而您不希望这样,因为您的目标仅涉及疾病。

    因此,我们需要建立一个数据集,其中每一行是一个患有他/她报告的所有疾病的患者,然后仅在数字特征上构建相异矩阵。对于这个任务,我将添加一个列presence,如果患者报告了疾病,则值为 1,否则为 0;零将由函数pivot_wider (link) 自动填充。

    这是我使用的代码,我想我达到了你想要的,如果是这样,请告诉我。

    library(cluster)
    library(dplyr)
    library(tidyr)
    
    dat <- data.frame(ID = c("id1","id1","id2","id2","id3","id3","id4","id4","id5","id5"),
                      PTName = c("headache","dizziness","nausea","abd pain","dizziness","headache","abd pain","nausea","headache","dizziness"),
                      presence = 1)
    # build the wider dataset: each row is a patient
    dat_wider <- pivot_wider(
        dat,
        id_cols = ID,
        names_from = PTName,
        values_from = presence,
        values_fill = list(presence = 0)
    )
    
    # in the dissimalirity matrix construction, we leave out the column ID
    gower_dist <- daisy(dat_wider %>% select(-ID), metric = "gower")
    k <- 2
    
    set.seed(123)
    pam_fit <- pam(gower_dist, diss = TRUE, k) 
    pam_results <- dat_wider %>%
        mutate(cluster = pam_fit$clustering) %>%
        group_by(cluster) %>%
        do(the_summary = summary(.))
    head(pam_results$the_summary)
    

    此外,由于您只使用二进制数据,因此如果它们更适合您的数据,您可以考虑使用 Simple MatchingJaccard 距离而不是 Gower 距离。在 R 中,您可以使用它们来使用

    sm_dist <- dist(dat_wider %>% select(-ID), method = "manhattan")/p
    j_dist <- dist(dat_wider %>% select(-ID), method = "binary")
    

    分别,其中p 是您要考虑的二进制变量的数量。

    【讨论】:

    • 感谢您的 hrlp。它适用于示例,但对于我的真实数据,我收到以下警告。你能解释一下吗?警告消息:在 daisy(dat_pt_wide %>% select(-ID), metric = "gower") 中:二进制变量 1、2、3、4、5、6、7、8、9、10、11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, [...截断]
    • daisy 函数文档中,作者说“请注意,当 2 值数值变量没有指定明确的类型时,菊花会发出警告,因为参考作者建议考虑使用“asymm” ; 警告可能会被 warnBin = FALSE" 静音。恐怕是这个原因,但我不能给你更多信息,而是仔细阅读文档
    • 无论如何,如果您想查看它们,我已经在答案中添加了关于替代距离的建议
    最近更新 更多