【问题标题】:How to cluster within clusters如何在集群内集群
【发布时间】:2018-09-21 20:53:46
【问题描述】:

我在地图上有一组点,每个点都有一个给定的参数值。我想:

  1. 在空间上对它们进行聚类并忽略任何小于 10分。我的 df 应该有一个列 (Clust) 用于每个点所属的集群 [DONE]
  2. 对每个集群内的参数值进行子集群;向我的 df (subClust) 添加一列,用于按子集群对每个点进行分类。

我不知道如何做第二部分,除了可能有循环。

图像显示了一组空间分布点(左上),按簇进行颜色编码,并在右上图中按参数值排序。底行显示具有 >10 个点的集群(左)和按参数值排序的每个集群的构面(右)。正是这些方面,我希望能够根据最小集群分离距离 (d=1) 对子集群进行颜色编码

任何指针/帮助表示赞赏。我的可重现代码如下。

# TESTING
library(tidyverse)
library(gridExtra)

# Create a random (X, Y, Value) dataset
set.seed(36)
x_ex <- round(rnorm(200,50,20))
y_ex <- round(runif(200,0,85))
values <- rexp(200, 0.2)
df_ex <- data.frame(ID=1:length(y_ex),x=x_ex,y=y_ex,Test_Param=values)

# Cluster data by (X,Y) location
d = 4
chc <- hclust(dist(df_ex[,2:3]), method="single")

# Distance with a d threshold - used d=40 at one time but that changes...
chc.d40 <- cutree(chc, h=d) 
# max(chc.d40)

# Join results 
xy_df <- data.frame(df_ex, Clust=chc.d40)

# Plot results
breaks = max(chc.d40)
xy_df_filt <- xy_df %>% dplyr::group_by(Clust) %>% dplyr::mutate(n=n()) %>% dplyr::filter(n>10)# %>% nrow

p1 <- ggplot() +
  geom_point(data=xy_df, aes(x=x, y=y, colour = Clust)) +
  scale_color_gradientn(colours = rainbow(breaks)) +
  xlim(0,100) + ylim(0,100) 

p2 <- xy_df %>% dplyr::arrange(Test_Param) %>%
ggplot() +
  geom_point(aes(x=1:length(Test_Param),y=Test_Param, colour = Test_Param)) +
  scale_colour_gradient(low="red", high="green")

p3 <- ggplot() +
  geom_point(data=xy_df_filt, aes(x=x, y=y, colour = Clust)) +
  scale_color_gradientn(colours = rainbow(breaks)) +
  xlim(0,100) + ylim(0,100) 

p4 <- xy_df_filt %>% dplyr::arrange(Test_Param) %>%
ggplot() +
  geom_point(aes(x=1:length(Test_Param),y=Test_Param, colour = Test_Param)) +
  scale_colour_gradient(low="red", high="green") +
  facet_wrap(~Clust, scales="free")

grid.arrange(p1, p2, p3, p4, ncol=2, nrow=2)

此片段不起作用 - 无法在 dplyr mutate() 内进行管道传输...

# Second Hierarchical Clustering: Try to sub-cluster by Test_Param within the individual clusters I've already defined above
xy_df_filt %>% # This part does not work
  dplyr::group_by(Clust) %>% 
  dplyr::mutate(subClust = hclust(dist(.$Test_Param), method="single") %>% 
                  cutree(, h=1))

下面是一种使用循环的方法 - 但我真的更愿意学习如何使用 dplyr 或其他一些非循环方法来做到这一点。下面是显示子聚类方面的更新图像。

sub_df <- data.frame()
for (i in unique(xy_df_filt$Clust)) {
  temp_df <- xy_df_filt %>% dplyr::filter(Clust == i)
  # Cluster data by (X,Y) location
  a_d = 1
  a_chc <- hclust(dist(temp_df$Test_Param), method="single")

  # Distance with a d threshold - used d=40 at one time but that changes... 
  a_chc.d40 <- cutree(a_chc, h=a_d) 
  # max(chc.d40)

  # Join results to main df
  sub_df <- bind_rows(sub_df, data.frame(temp_df, subClust=a_chc.d40)) %>% dplyr::select(ID, subClust)
}
xy_df_filt_2 <- left_join(xy_df_filt,sub_df, by=c("ID"="ID"))

p4 <- xy_df_filt_2 %>% dplyr::arrange(Test_Param) %>%
ggplot() +
  geom_point(aes(x=1:length(Test_Param),y=Test_Param, colour = subClust)) +
  scale_colour_gradient(low="red", high="green") +
  facet_wrap(~Clust, scales="free")

grid.arrange(p1, p2, p3, p4, ncol=2, nrow=2)

【问题讨论】:

    标签: r dplyr cluster-analysis apply hierarchical-clustering


    【解决方案1】:

    应该有一种方法可以结合使用dotidy,但我总是很难使用do 让事情按照我想要的方式排列。相反,我通常做的是结合来自基本 R 的split 和来自purrrmap_dfrsplit 将通过 Clust 拆分数据框,并为您提供一个数据框列表,然后您可以对其进行映射。 map_dfr 映射每个数据帧并返回单个数据帧。

    我从您的 xy_df_filt 开始,生成了我认为应该与您从 for 循环中获得的 xy_df_filt_2 相同的内容。我做了两幅图,虽然两组簇有点难看。

    xy_df_filt_2 <- xy_df_filt %>%
        split(.$Clust) %>%
        map_dfr(function(df) {
            subClust <- hclust(dist(df$Test_Param), method = "single") %>% cutree(., h = 1)
    
            bind_cols(df, subClust = subClust)
        })
    
    ggplot(xy_df_filt_2, aes(x = x, y = y, color = as.factor(subClust), shape = as.factor(Clust))) +
        geom_point() +
        scale_color_brewer(palette = "Set2")
    

    刻面更清晰

    ggplot(xy_df_filt_2, aes(x = x, y = y, color = as.factor(subClust), shape = as.factor(Clust))) +
        geom_point() +
        scale_color_brewer(palette = "Set2") +
        facet_wrap(~ Clust)
    

    reprex package (v0.2.0) 于 2018 年 4 月 14 日创建。

    【讨论】:

    • 我认为这也是一个不错的答案 - 使用我不熟悉的工具。谢谢。
    • 在 Andrew 的回答中查看我的评论;你的方法不会产生警告,而他的方法会产生。
    【解决方案2】:

    您可以为您的子集群执行此操作...

    xy_df_filt_2 <- xy_df_filt %>% 
                    group_by(Clust) %>% 
                    mutate(subClust = tibble(Test_Param) %>% 
                                      dist() %>% 
                                      hclust(method="single") %>% 
                                      cutree(h=1))
    

    嵌套管道很好。我认为您的版本的问题在于您没有将正确的对象类型传递给dist。 如果您只将单个列传递给 dist,则不需要 tibble 术语,但我将其保留以防您像主集群一样使用多个列。

    您可以使用相同类型的公式,但不使用group_by,从df_ex 计算xy_df

    【讨论】:

    • 你的 tibble(x,y) 应该读作 tibble(Test_Param) 是正确的,因为第二个聚类是基于 Test_Param 距离而不是 x,y。但是你的方法有效。谢谢
    • 是的,当然 - 很抱歉。我已经修改了答案。
    • 我在运行此代码时收到一堆警告(mutate_impl(.data, dots) 中的警告:绑定字符和因子向量,强制转换为字符向量),并且似乎与此问题有关 (@987654321 @) 但我无法解决;我想使用 factor() 或 as.factor() 将 subClust 转换为因子,我想知道 tibble() 是否妨碍了我。卡米尔的回答没有这个问题。
    • @val 是的,这(我认为)只是表明mutate 必须添加因子级别,它通过转换为字符来实现。这只是一个警告 - 我已经处理过其他事情,但这并不一定意味着计算不起作用。
    猜你喜欢
    • 1970-01-01
    • 2014-11-15
    • 2016-03-03
    • 1970-01-01
    • 2019-09-08
    • 2018-03-09
    • 2011-11-28
    • 2013-08-20
    • 2019-11-30
    相关资源
    最近更新 更多