2015-10-07 56 views
0

这是一些数据。纠结集群/ kmeans中心回到原始数据框

df <- data.frame(groupvar=rep(c('a','b'),100),v1=rnorm(200),v2=rnorm(200)) 

现在我做的每一组中的k表示:

require(dplyr) 

kobjs = df %>% group_by(groupvar) %>% 
    do(kclust = kmeans(cbind(.$v1,.$v2),centers=5)) 

“kobjs” 看起来是这样的:

groupvar  kclust 
    (fctr)  (chr) 
1  a <S3:kmeans> 
2  b <S3:kmeans> 

我想抓住集群分配(并且最好,中心点)并将它们追加到原始数据框中。我想你可以使用扫帚来做到这一点:

require(broom) 
merged = kobjs %>% 
    group_by(groupvar) %>% do(augment(.$kclust[[1]],df)) 

但不知何故产生了400X4矩阵,而不是一个200X4。那是怎么发生的?我如何得到我想要的行为?

编辑1:解决了我想要的方式,从aosmith的一些见解。有可能是一个方法,使之更加优雅(是left_join必要吗?),但它是我想要的行为:

kobjs = df %>% 
    do(kmeans(cbind(.$v1,.$v2),centers=5) %>% 
     fitted(method="centers") %>% 
     data.frame(cluster=rownames(.),entry=1:length(.),row.names=NULL)) %>% 
    left_join(df %>% group_by(groupvar) %>% mutate(entry=1:n()), 
      by=c("entry","groupvar")) 

回答

3

在你对整个df使用augment,而不是只使用集各组的时刻。这就是为什么你得到的数据集的长度是预期的两倍。

所以你需要使用kobjs来做类似下面的事情。在制作kobjs之前,我将种子设置为16。

kobjs %>% 
    group_by(groupvar) %>% 
    do(augment(.$kclust[[1]], df[df$groupvar == .$groupvar,])) 

Source: local data frame [200 x 5] 
Groups: groupvar [2] 

    .rownames groupvar   v1   v2 .cluster 
     (chr) (fctr)  (dbl)  (dbl) (fctr) 
1   1  a 0.30291472 0.2203811  1 
2   3  a -0.51381305 0.1480162  1 
3   5  a -0.75246517 -0.6407782  2 
4   7  a 0.06453416 1.2965984  3 
5   9  a -0.62353541 -1.3240648  2 
6   11  a 0.18435121 -1.0513837  5 
7   13  a -0.26481666 2.8117979  4 
8   15  a 0.56643441 0.1434451  1 
9   17  a -0.30406035 -0.1477244  1 
10  19  a 1.62538120 -0.5972593  5 
..  ...  ...   ...  ...  ... 

为了得到更像你想要的东西。

您还有其他选择。例如,你可以在原来的do步骤中使用augment

set.seed(16) 
df %>% group_by(groupvar) %>% 
    do(augment(kmeans(cbind(.$v1,.$v2),centers=5), .)) 

Source: local data frame [200 x 4] 
Groups: groupvar [2] 

    groupvar   v1   v2 .cluster 
    (fctr)  (dbl)  (dbl) (fctr) 
1   a 0.30291472 0.2203811  1 
2   a -0.51381305 0.1480162  1 
3   a -0.75246517 -0.6407782  2 
4   a 0.06453416 1.2965984  3 
5   a -0.62353541 -1.3240648  2 
6   a 0.18435121 -1.0513837  5 
7   a -0.26481666 2.8117979  4 
8   a 0.56643441 0.1434451  1 
9   a -0.30406035 -0.1477244  1 
10  a 1.62538120 -0.5972593  5 
..  ...   ...  ...  ... 

你也可以从kmeans物体拉出cluster这些具有以下do编码添加到数据集。但是,这并不使用扫帚

set.seed(16) 
df %>% group_by(groupvar) %>% 
    do(data.frame(., kclust = kmeans(cbind(.$v1,.$v2),centers=5)$cluster)) 

Source: local data frame [200 x 4] 
Groups: groupvar [2] 

    groupvar   v1   v2 kclust 
    (fctr)  (dbl)  (dbl) (int) 
1   a 0.30291472 0.2203811  1 
2   a -0.51381305 0.1480162  1 
3   a -0.75246517 -0.6407782  2 
4   a 0.06453416 1.2965984  3 
5   a -0.62353541 -1.3240648  2 
6   a 0.18435121 -1.0513837  5 
7   a -0.26481666 2.8117979  4 
8   a 0.56643441 0.1434451  1 
9   a -0.30406035 -0.1477244  1 
10  a 1.62538120 -0.5972593  5 
..  ...   ...  ... ... 

编辑添加例如保存从模型两件事情在一个单一的do通话。

您可以在do中拟合并命名模型对象,然后从中拉出多个汇总值,但它涉及大括号的使用(我不确定它们是否包含在非理性担心方括号中;-) )。

这里有两种方法,一是建立model,拉出拟合值作为fit,并与原始数据集绑定在一起这一切(这是在data.frame第一.代表)。

df %>% group_by(groupvar) %>% 
    do({ 
     model = kmeans(cbind(.$v1, .$v2), centers = 5) 
     fit = fitted(model, methods = "centers") 
     data.frame(., fit, cluster = rownames(fit), row.names = NULL) 
    }) 

我不总是喜欢做大量的命名,所以第二个选项只是直接作用于model并跳过fit一步。

df %>% group_by(groupvar) %>% 
    do({ 
     model = kmeans(cbind(.$v1, .$v2), centers = 5) 
     data.frame(., fitted(model, methods = "centers"), cluster = model$cluster, row.names = NULL) 
    }) 
+0

谢谢。第一个例子是我正在寻找的行为。我喜欢其他两种方式来做到这一点(我猜想我对方括号非常害怕),但问题是我不知道如何在同样的kmeans调用中同时抓取集群分配和中心。例如: do(data.frame(。,kclust = kmeans(cbind(。$ v1,。$ v2),centers = 5)$ cluster,kcenter = fitted(kmeans(cbind(。$ v1,。$ v2) ,中心= 5)) 是两个kmeans调用,而不是一个任何方式来抓住两个相同的电话? –

+0

没关系,我想我想通了 - 看原文编辑 –

+0

@NicholasRoot我添加了一个编辑以展示如何适应模型的一些选择,并在单个“do”调用中抽出东西(无需多次安装) – aosmith