将R剪切树状图分成最小大小的组

5
有没有一种简单的方法来计算在给定最小大小的情况下产生分组的cut中最低h值?
在这个例子中,如果我想要每个群集至少有十个成员,我应该选择h = 3.80
# using iris data simply for reproducible example
data(iris)
d <- data.frame(scale(iris[,1:4]))
hc <- hclust(dist(d))
plot(hc)

cut(as.dendrogram(hc), h=3.79) # produces 5 groups; group 4 has 7 members

cut(as.dendrogram(hc), h=3.80) # produces 4 groups; no group has <10 members

由于拆分的高度在hc$height中给出,我可以使用hc$height + 0.00001创建一组候选值,然后循环遍历每个切割点。但是,我不知道如何从dendrogram类中解析出簇大小members。例如,cut(as.dendrogram(hc), h=3.80)$lower[[1]]$members返回NULL,而不是期望的66。
请注意,这是一个比Cutting dendrogram into n trees with minimum cluster size in R简单的问题;在这里,我没有指定树的数量,只指定了最小簇大小。非常感谢。

1
作为附注:members是一个属性 - attr(cut(as.dendrogram(hc), h=3.80)$lower[[1]], "members") 返回66。 - lukeA
3个回答

3

感谢@Vlo和@lukeA,我现在能够实现循环。但是,我只是发布这个作为一个起点,并且非常愿意接受更优雅的解决方案。

unnest <- function(x) { # from Vlo's answer
  if(is.null(names(x))) x
  else c(list(all=unname(unlist(x))), do.call(c, lapply(x, unnest)))
}

cuts <- hc$height + 1e-9

min_size <- 10
smallest <- 0
i <- 0

while(smallest < min_size & i <= length(cuts)){
  h_i <- cuts[i <- i+1]
  if(i > length(cuts)){
    warning("Couldn't find a cluster big enough.")
  }
  else  smallest <- 
           Reduce(min, 
                  lapply(X = unnest(cut(as.dendrogram(hc), h=h_i)$lower), 
                         FUN = attr, which = "members") ) # from lukeA's comment
}
h_i # returns desired output: [1] 3.79211

2
此功能可在 dendextend 包中使用 heights_per_k.dendrogram 函数实现(当加载 dendextendRcpp 函数时,还有更快的 C++ 实现)。
## Not run: 
hc <- hclust(dist(USArrests[1:4,]), "ave")
dend <- as.dendrogram(hc)
heights_per_k.dendrogram(dend)
##       1        2        3        4
##86.47086 68.84745 45.98871 28.36531

作为附注,dendextend包有一个cutree.dendrogram方法用于树状图(它的工作方式与hclust对象的cutree非常相似)。

感谢您的回答(以及创建dendextend包,+1)。我已经撤销了您的标签编辑,因为我的问题并不是一个[dendextend]问题,虽然它可能很方便,但[dendextend]并不是唯一的解决方案。上下文 - C8H10N4O2
你好@C8H10N4O2。很高兴你喜欢dendextend :) (有没有可能投一票“V”?)。至于删除标签-我看到了你链接的元数据。在我看来,由于dendextend是一个旨在回答此类问题的软件包-当人们查看dendextend标签时,我更希望他们能找到这个解决方案。即:http://meta.stackexchange.com/questions/26913/should-i-retag-a-question-with-a-tag-that-is-based-on-the-answer-and-not-the-que/26914#26914 由于这是你的问题-显然这是你的决定。 - Tal Galili

1
这并没有回答问题,但如果你决定遍历 h,可能对提取members有用。
此处窃取并修改一些代码。
# Unnest the list/dendogram structure
unnest <- function(x) {
  if(is.null(names(x))) {
    x
  }
  else {
    c(list(all=unname(unlist(x))), do.call(c, lapply(x, unnest)))
  }
}

# Extract the `members` attribute from each dendogram
lapply(X = unnest(cut(as.dendrogram(hc), h=3.8)), FUN = attr, which = "members")

输出:

# Please don't ask me why there are 2 dendograms stored
# in the `$upper` list while `print` displays one

$upper1
[1] 2

$upper2
[1] 2

$lower1
[1] 66

$lower2
[1] 11

$lower3
[1] 24

$lower4
[1] 49

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接