k-表示基于节点值的约束聚类

时间:2016-05-26 08:52:13

标签: constraints cluster-analysis k-means

也许我错过了一些东西,因为这似乎是一个简单的问题,但我在网上看了这个并且在文献中没有找到任何东西。

基本上我需要做的是根据位置对一组目的地城市进行聚类(纬度/经度作为每个节点的特征,相似性度量的欧几里德距离),具有固定数量的聚类。一切似乎都很好,而k-means可以解决问题。但是,我对每个群集都有以下约束:每个城市(节点)都有一个分配给它的相应值,每个群集中这些值的总和不应超过固定阈值(所有群集的阈值相同)。有一个简单的方法吗?

2 个答案:

答案 0 :(得分:0)

您有两个选择:

- 您可以使用 rpart 作为群集,并使用权重和minbucket选项。然而,预测的群集会给你带来长方形。

- 您可以查看我找到的源代码 https://searchcode.com/codesearch/view/18689414/

kmeans <-
function(x, centers, iter.max = 10, nstart = 1,
         algorithm = c("Hartigan-Wong", "Lloyd", "Forgy", "MacQueen"))
{
    do_one <- function(nmeth) {
        Z <-
            switch(nmeth,
                   { # 1
                       Z <- .Fortran(C_kmns, x, m, p,
                                centers = centers,
                                as.integer(k), c1 = integer(m), integer(m),
                                nc = integer(k), double(k), double(k), integer(k),
                                double(m), integer(k), integer(k),
                                as.integer(iter.max), wss = double(k),
                                ifault = 0L)
                       switch(Z$ifault,
                              stop("empty cluster: try a better set of initial centers",
                                   call.=FALSE),
                              warning(gettextf("did not converge in %d iterations",
                                               iter.max), call.=FALSE, domain =NA),
                              stop("number of cluster centres must lie between 1 and nrow(x)",
                                   call.=FALSE)
                              )
                       Z
                   },
                   { # 2
                       Z <- .C(C_kmeans_Lloyd, x, m, p,
                               centers = centers, as.integer(k),
                               c1 = integer(m), iter = as.integer(iter.max),
                               nc = integer(k), wss = double(k))
                       if(Z$iter > iter.max)
                           warning("did not converge in ",
                                  iter.max, " iterations", call.=FALSE)
                       if(any(Z$nc == 0))
                           warning("empty cluster: try a better set of initial centers", call.=FALSE)
                       Z
                   },
                   { # 3
                       Z <- .C(C_kmeans_MacQueen, x, m, p,
                               centers = as.double(centers), as.integer(k),
                               c1 = integer(m), iter = as.integer(iter.max),
                               nc = integer(k), wss = double(k))
                       if(Z$iter > iter.max)
                           warning("did not converge in ",
                                   iter.max, " iterations", call.=FALSE)
                       if(any(Z$nc == 0))
                           warning("empty cluster: try a better set of initial centers", call.=FALSE)
                       Z
                    })
        Z
    }
    x <- as.matrix(x)
    m <- as.integer(nrow(x))
    if(is.na(m)) stop("invalid nrow(x)")
    p <- as.integer(ncol(x))
    if(is.na(p)) stop("invalid ncol(x)")
    if(missing(centers))
    stop("'centers' must be a number or a matrix")
    nmeth <- switch(match.arg(algorithm),
                    "Hartigan-Wong" = 1,
                    "Lloyd" = 2, "Forgy" = 2,
                    "MacQueen" = 3)
    if(length(centers) == 1L) {
    if (centers == 1) nmeth <- 3
    k <- centers
        ## we need to avoid duplicates here
        if(nstart == 1)
            centers <- x[sample.int(m, k), , drop = FALSE]
        if(nstart >= 2 || any(duplicated(centers))) {
            cn <- unique(x)
            mm <- nrow(cn)
            if(mm < k)
                stop("more cluster centers than distinct data points.")
            centers <- cn[sample.int(mm, k), , drop=FALSE]
        }
    } else {
    centers <- as.matrix(centers)
        if(any(duplicated(centers)))
            stop("initial centers are not distinct")
        cn <- NULL
    k <- nrow(centers)
        if(m < k)
            stop("more cluster centers than data points")
    }
    if(iter.max < 1) stop("'iter.max' must be positive")
    if(ncol(x) != ncol(centers))
    stop("must have same number of columns in 'x' and 'centers'")
    if(!is.double(x)) storage.mode(x) <- "double"
    if(!is.double(centers)) storage.mode(centers) <- "double"
    Z <- do_one(nmeth)
    best <- sum(Z$wss)
    if(nstart >= 2 && !is.null(cn))
    for(i in 2:nstart) {
        centers <- cn[sample.int(mm, k), , drop=FALSE]
        ZZ <- do_one(nmeth)
        if((z <- sum(ZZ$wss)) < best) {
        Z <- ZZ
        best <- z
        }
    }
    centers <- matrix(Z$centers, k)
    dimnames(centers) <- list(1L:k, dimnames(x)[[2L]])
    cluster <- Z$c1
    if(!is.null(rn <- rownames(x)))
        names(cluster) <- rn
    totss <- sum(scale(x, scale = FALSE)^2)
    structure(list(cluster = cluster, centers = centers, totss = totss,
                   withinss = Z$wss, tot.withinss = best,
                   betweenss = totss - best, size = Z$nc),
          class = "kmeans")
}

## modelled on print methods in the cluster package
print.kmeans <- function(x, ...)
{
    cat("K-means clustering with ", length(x$size), " clusters of sizes ",
        paste(x$size, collapse=", "), "\n", sep="")
    cat("\nCluster means:\n")
    print(x$centers, ...)
    cat("\nClustering vector:\n")
    print(x$cluster, ...)
    cat("\nWithin cluster sum of squares by cluster:\n")
    print(x$withinss, ...)
    cat(sprintf(" (between_SS / total_SS = %5.1f %%)\n",
        100 * x$betweenss/x$totss),
    "Available components:\n", sep="\n")
    print(names(x))
    invisible(x)
}

fitted.kmeans <- function(object, method = c("centers", "classes"), ...)
{
    method <- match.arg(method)
    if (method == "centers") object$centers[object$cl, , drop=FALSE]
    else object$cl
}

请注意,代码会检查这些行是否有改进:

 if((z <- sum(ZZ$wss)) < best) {
        Z <- ZZ
        best <- z
        }

您可以在这里添加约束。

答案 1 :(得分:0)

您可以使用与KMeans相同的原则。在2-3中迭代直到收敛:

  1. 将城市分配到群集(随机)
  2. 计算群集的质心
  3. 将点分配给质心,以便:
    • 指向指定质心的点的距离总和最小化
    • 尊重阈值限制
  4. 在标准KMeans中没有约束。因此,通过将每个点分配给最近的质心,可以容易地执行第二步。在这里,您必须在步骤2中解决优化问题。 如果你只是将它建模为整数编程问题,它可能会更快。 OR Tools具有解决整数规划问题的工具。

    Here是一个python实现,它使用不同的约束进行K-means聚类,包括一个群集中实例总重量最大的约束。