R中是否有一个函数可以获取找到的簇的中心并将簇分配给新数据集


14

我有一个多维数据集的两个部分,我们称它们为traintest。我想基于火车数据集构建一个模型,然后在测试数据集上对其进行验证。簇数是已知的。

我试图在R中应用k-means聚类,但得到了一个包含聚类中心的对象:

kClust <- kmeans(train, centers=N, nstart=M)

R中是否有一个功能可以获取找到的簇的中心并将簇分配给我的测试数据集?

我可以尝试其他哪些方法/算法?


欢迎来到该站点,@ user2598356。您能以更一般的方式(非R特定)构架吗?如果您只要求R函数,那么CV可能就没有这个问题了(请参阅我们的帮助页面)。而且,由于它没有可复制的示例,因此它在Stack Overflow上也将成为主题。如果您可以对此进行编辑以使其在此处或在主题上成为主题,请这样做。否则,此Q可能会关闭。
gung-恢复莫妮卡

这个问题似乎离题,因为它与找到R函数有关。
gung-恢复莫妮卡

1
但是最后一个问题是什么:“我可以尝试的其他方法/算法有哪些?”。实际上,我得到的答案与CV主题中方法的实现有关,还是我错了?
user2598356 2013年

1
@gung您可能是正确的,在这种情况下,我邀请user259 ...将此问题标记为要迁移。但是,关于其他方法和算法的问题的最后一部分表明,我们的社区可能会很乐于提供有用的帮助和建议。
whuber

谢谢!该函数运行良好,但是如果您的行数超过5万,则会花费太多时间。有减轻它重量的想法吗?

Answers:


11

您可以使用以下函数为新数据集计算群集分配:

clusters <- function(x, centers) {
  # compute squared euclidean distance from each sample to each cluster center
  tmp <- sapply(seq_len(nrow(x)),
                function(i) apply(centers, 1,
                                  function(v) sum((x[i, ]-v)^2)))
  max.col(-t(tmp))  # find index of min distance
}

# create a simple data set with two clusters
set.seed(1)
x <- rbind(matrix(rnorm(100, sd = 0.3), ncol = 2),
           matrix(rnorm(100, mean = 1, sd = 0.3), ncol = 2))
colnames(x) <- c("x", "y")
x_new <- rbind(matrix(rnorm(10, sd = 0.3), ncol = 2),
               matrix(rnorm(10, mean = 1, sd = 0.3), ncol = 2))
colnames(x_new) <- c("x", "y")

cl <- kmeans(x, centers=2)

all.equal(cl[["cluster"]], clusters(x, cl[["centers"]]))
# [1] TRUE
clusters(x_new, cl[["centers"]])
# [1] 2 2 2 2 2 1 1 1 1 1

plot(x, col=cl$cluster, pch=3)
points(x_new, col= clusters(x_new, cl[["centers"]]), pch=19)
points(cl[["centers"]], pch=4, cex=2, col="blue")

集群分配

或者,您可以使用flexclust软件包,该软件包predict为k均值提供了一种已实现的方法:

library("flexclust")
data("Nclus")

set.seed(1)
dat <- as.data.frame(Nclus)
ind <- sample(nrow(dat), 50)

dat[["train"]] <- TRUE
dat[["train"]][ind] <- FALSE

cl1 = kcca(dat[dat[["train"]]==TRUE, 1:2], k=4, kccaFamily("kmeans"))
cl1    
#
# call:
# kcca(x = dat[dat[["train"]] == TRUE, 1:2], k = 4)
#
# cluster sizes:
#
#  1   2   3   4 
#130 181  98  91 

pred_train <- predict(cl1)
pred_test <- predict(cl1, newdata=dat[dat[["train"]]==FALSE, 1:2])

image(cl1)
points(dat[dat[["train"]]==TRUE, 1:2], col=pred_train, pch=19, cex=0.3)
points(dat[dat[["train"]]==FALSE, 1:2], col=pred_test, pch=22, bg="orange")

挠线图

还有一些转换方法可以将结果从群集函数(如stats::kmeans或)cluster::pam转换为类的对象,kcca反之亦然:

as.kcca(cl, data=x)
# kcca object of family ‘kmeans’ 
#
# call:
# as.kcca(object = cl, data = x)
#
# cluster sizes:
#
#  1  2 
#  50 50 

非常感谢你!只是一个问题:kcca方法如何处理开始次数(它是否针对起点优化了分析)?
user2598356 2013年

您的开始次数是什么意思?该stepFlexclust函数针对不同数量的群集重复运行群集算法,并为每个群集算法返回群集距离解决方案中的最小值。
rcs 2013年

1

步骤1:计算向量与矩阵每一行之间距离的函数

calc_vec2mat_dist = function(x, ref_mat) {
    # compute row-wise vec2vec distance 
    apply(ref_mat, 1, function(r) sum((r - x)^2))
}

步骤2:将vec2mat计算机应用到input_matrix的每一行的功能

calc_mat2mat_dist = function(input_mat, ref_mat) {

    dist_mat = apply(input_mat, 1, function(r) calc_vec2mat_dist(r, ref_mat))

    # transpose to have each row for each input datapoint
    # each column for each centroids
    cbind(t(dist_mat), max.col(-t(dist_mat)))
}

第三步。应用mat2mat函数

calc_mat2mat_dist(my_input_mat, kmeans_model$centers)

步骤4。(可选)使用plyr :: ddply和doMC为大型数据集并行化mat2mat

library(doMC)
library(plyr)

pred_cluster_para = function(input_df, center_mat, cl_feat, id_cols, use_ncore = 8) {
    # assign cluster lables for each individual (row) in the input_df 
    # input: input_df   - dataframe with all features used in clustering, plus some id/indicator columns
    # input: center_mat - matrix of centroid, K rows by M features
    # input: cl_feat    - list of features (col names)
    # input: id_cols    - list of index cols (e.g. id) to include in output 
    # output: output_df - dataframe with same number of rows as input, 
    #         K columns of distances to each clusters
    #         1 column of cluster_labels
    #         x column of indices in idx_cols

    n_cluster = nrow(center_mat)
    n_feat = ncol(center_mat)
    n_input = nrow(input_df)

    if(!(typeof(center_mat) %in% c('double','interger') & is.matrix(center_mat))){
        stop('The argument "center_mat" must be numeric matrix')
    } else if(length(cl_feat) != n_feat) {
        stop(sprintf('cl_feat size: %d , center_mat n_col: %d, they have to match!',length(cl_feat), n_feat))
    } else {
        # register MultiCore backend through doMC and foreach package
        doMC::registerDoMC(cores = use_ncore)

        # create job_key for mapping/spliting the input data
        input_df[,'job_idx'] = sample(1:use_ncore, n_input, replace = TRUE)

        # create row_key for tracing the original row order which will be shuffled by mapreduce
        input_df[,'row_idx'] = seq(n_input)

        # use ddply (df input, df output) to split-process-combine
        output_df = ddply(
            input_df[, c('job_idx','row_idx',cl_feat,id_cols)], # input big data 
            'job_idx',                       # map/split by job_idx
            function(chunk) {                # work on each chunk
                dist = data.frame(calc_mat2mat_dist(chunk[,cl_feat], center_mat))
                names(dist) = c(paste0('dist2c_', seq(n_cluster)), 'pred_cluster')
                dist[,id_cols] = chunk[,id_cols]
                dist[,'row_idx'] = chunk[,'row_idx']
                dist                        # product of mapper
                        }, .parallel = TRUE) # end of ddply
        # sort back to original row order

        output_df = output_df[order(output_df$row_idx),]
        output_df[c('job_idx')] = NULL
        return(output_df)
    }

}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.