目前,我尝试在分组数据中找到聚类的中心。通过使用样本数据集和问题定义,我能够在每个组内创建kmeans
聚类。然而,当涉及到获取每个组中每个聚类中心的信息时,我不知道如何获取它们。 https://rdrr.io/cran/broom/man/kmeans_tidiers.html
样本数据取自这里(稍作修改以添加gr
列)样本数据
library(dplyr)library(broom)library(ggplot2)set.seed(2015)sizes_1 <- c(20, 100, 500)sizes_2 <- c(10, 50, 100)centers_1 <- data_frame(x = c(1, 4, 6), y = c(5, 0, 6), n = sizes_1, cluster = factor(1:3))centers_2 <- data_frame(x = c(1, 4, 6), y = c(5, 0, 6), n = sizes_2, cluster = factor(1:3))points1 <- centers_1 %>% group_by(cluster) %>% do(data_frame(x = rnorm(.$n, .$x), y = rnorm(.$n, .$y), gr="1"))points2 <- centers_2 %>% group_by(cluster) %>% do(data_frame(x = rnorm(.$n, .$x), y = rnorm(.$n, .$y), gr="2"))combined_points <- rbind(points1, points2)> combined_points# A tibble: 780 x 4# Groups: cluster [3] cluster x y gr <fctr> <dbl> <dbl> <chr> 1 1 3.66473833 4.285771 1 2 1 0.51540619 5.565826 1 3 1 0.11556319 5.592178 1 4 1 1.60513712 5.360013 1 5 1 2.18001557 4.955883 1 6 1 1.53998887 4.530316 1 7 1 -1.44165622 4.561338 1 8 1 2.35076259 5.408538 1 9 1 -0.03060973 4.980363 110 1 2.22165205 5.125556 1# ... with 770 more rowsggplot(combined_points, aes(x, y)) + facet_wrap(~gr) + geom_point(aes(color = cluster))
到这里为止,一切都很好。当我想为每个组提取每个聚类中心时
clust <- combined_points %>% group_by(gr) %>% dplyr::select(x, y) %>% kmeans(3)> clustK-means clustering with 3 clusters of sizes 594, 150, 36Cluster means: gr x y1 1.166667 6.080832 6.00748852 1.333333 4.055645 0.06541583 1.305556 1.507862 5.2417670
正如我们所见,gr
编号已更改,我不知道这些中心属于哪个组。
我们进一步查看clust
的tidy
格式
> tidy(clust) x1 x2 x3 size withinss cluster1 1.166667 6.080832 6.0074885 594 1095.3047 12 1.333333 4.055645 0.0654158 150 312.4182 23 1.305556 1.507862 5.2417670 36 115.2484 3
我仍然看不到gr 2
的中心信息。
我希望问题已经解释得很清楚了。如果您有任何遗漏的地方,请告诉我!提前感谢!
回答:
kmeans
不理解dplyr的分组,所以它只是找到三个总体中心,而不是在每个组内找到中心。目前,完成此操作的首选方法是输入数据的列表列,例如
library(tidyverse)points_and_models <- combined_points %>% ungroup() %>% select(-cluster) %>% # 清理,移除cluster名称,以便数据可以合并 nest(x, y) %>% # 将输入数据折叠成列表列 mutate(model = map(data, kmeans, 3), # 在输入数据的列表列上迭代模型 centers = map(model, broom::tidy)) # 从模型中提取数据points_and_models#> # A tibble: 2 x 4#> gr data model centers #> <chr> <list> <list> <list> #> 1 1 <tibble [620 × 2]> <S3: kmeans> <data.frame [3 × 5]>#> 2 2 <tibble [160 × 2]> <S3: kmeans> <data.frame [3 × 5]>points_and_models %>% unnest(centers)#> # A tibble: 6 x 6#> gr x1 x2 size withinss cluster#> <chr> <dbl> <dbl> <int> <dbl> <fct> #> 1 1 4.29 5.71 158 441. 1 #> 2 1 3.79 0.121 102 213. 2 #> 3 1 6.39 6.06 360 534. 3 #> 4 2 5.94 5.88 100 194. 1 #> 5 2 4.01 -0.127 50 97.4 2 #> 6 2 1.07 4.57 10 15.7 3
请注意,cluster
列来自模型结果,而不是输入数据。
您也可以使用do
做同样的事情,例如
combined_points %>% group_by(gr) %>% do(model = kmeans(.[c('x', 'y')], 3)) %>% ungroup() %>% group_by(gr) %>% do(map_df(.$model, broom::tidy)) %>% ungroup()
但是do
和按行分组在此时已被软废弃,代码看起来有点笨拙,正如您所见,需要多次显式地ungroup
。