如何在集群中集群

How to cluster within clusters

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

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

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

该图显示了一组空间分布的点(左上角),在右上角的图中按聚类进行颜色编码并按参数值排序。底行显示具有 >10 个点的聚类(左)和按参数值排序的每个聚类的小平面(右)。我希望能够根据最小集群间隔距离 (d=1)

按子集群对这些方面进行颜色编码

任何 pointers/help 感谢。我的可重现代码如下。

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

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

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

应该有一种方法可以结合使用 dotidy,但我总是很难使用 [=12= 使事情按照我想要的方式排列].相反,我通常做的是将基数 R 的 splitpurrrmap_dfr 结合起来。 split 会将数据帧拆分为 Clust 并为您提供一个数据帧列表,然后您可以将其映射。 map_dfr 映射每个数据帧和 returns 单个数据帧。

我从你的 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-04-14。