如何在集群中集群
How to cluster within clusters
我在地图上有一组点,每个点都有给定的参数值。我想:
- 在空间上对它们进行聚类并忽略任何少于
10点。我的 df 应该有一个集群的列(集群),每个点属于 [DONE]
- 对每个集群中的参数值进行子集群;在我的 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
。
应该有一种方法可以结合使用 do
和 tidy
,但我总是很难使用 [=12= 使事情按照我想要的方式排列].相反,我通常做的是将基数 R 的 split
和 purrr
的 map_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。
我在地图上有一组点,每个点都有给定的参数值。我想:
- 在空间上对它们进行聚类并忽略任何少于 10点。我的 df 应该有一个集群的列(集群),每个点属于 [DONE]
- 对每个集群中的参数值进行子集群;在我的 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
。
应该有一种方法可以结合使用 do
和 tidy
,但我总是很难使用 [=12= 使事情按照我想要的方式排列].相反,我通常做的是将基数 R 的 split
和 purrr
的 map_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。