如何在集群内进行集群

时间:2018-04-11 20:35:46

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

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

  1. 在空间上对它们进行聚类,并忽略任何少于的簇 10点。我的df应该有一个列(Clust),每个点属于[DONE]
  2. 对每个群集中的参数值进行子群集;在我的df(subClust)中添加一列,用于按子群分类每个点。
  3. 我不知道怎么做第二部分,除了可能有循环。

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

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

    enter image description here

    # 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)
    

    enter image description here

2 个答案:

答案 0 :(得分:1)

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

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

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

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

答案 1 :(得分:1)

应该有一种方法可以使用dotidy的组合来实现,但我总是很难按照do的方式排列。相反,我通常做的是组合来自基础R的split和来自map_dfr的{​​{1}}。 purrr会将数据框拆分为split,并为您提供可以映射的数据框列表。 Clust映射每个数据帧并返回单个数据帧。

我从您的map_dfr开始,并生成了我认为应该与您从for循环中获得的xy_df_filt相同的内容。我做了两个情节,虽然这两个集群有点难以看清。

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")

reprex package(v0.2.0)创建于2018-04-14。