R'de bulunan ve yeni bir veri kümesine kümeler atayan kümelerin merkezlerini alan bir işlev var mı?


14

Çok boyutlu bir veri setinin iki kısmı var, diyelim ki trainve test. Ve tren veri setine dayalı bir model oluşturmak ve test veri setinde doğrulamak istiyorum. Küme sayısı bilinmektedir.

R'de k-ortalamaları kümelemeyi uygulamaya çalıştım ve kümelerin merkezlerini içeren bir nesne aldım:

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

R'de bulunan ve test veri kümeme kümeler atanan kümelerin merkezlerini alan bir işlev var mı?

Deneyebileceğim diğer yöntemler / algoritmalar nelerdir?


Siteye hoş geldiniz, @ user2598356. Bunu daha genel (R'ye özgü olmayan) bir şekilde çerçeveleyebilir misiniz? Yalnızca bir R işlevi istiyorsanız, bu soru CV için konu dışıdır ( yardım sayfamıza bakın ). Ayrıca, çoğaltılabilir bir örneği olmadığı için Yığın Taşması konusunda da konu dışı olacaktır . Bu konuyu burada veya SO konusunda yapmak için düzenleyebilirseniz, lütfen bunu yapın. Aksi takdirde, bu Q kapatılabilir.
gung - Monica'yı eski durumuna getir

Bu soru konu dışı gibi görünüyor çünkü bir R işlevi bulmakla ilgili.
gung - Monica'yı eski durumuna getir

1
Ama son soru ne olacak: "Deneyebileceğim diğer yöntemler / algoritmalar nelerdir?". Aslında aldığım cevap bir CV konusu olan yöntemlerin uygulanmasından endişe duyuyor, yoksa yanılıyor muyum?
user2598356

1
@gung Haklı olabilirsiniz, bu durumda user259'u bu soruyu geçiş için işaretlemeye davet ediyorum. Bununla birlikte, diğer yöntemler ve algoritmalar hakkındaki sorunun son kısmı, topluluğumuzun yararlı yardım ve tavsiye sunmak için iyi bir konumda olabileceğini göstermektedir.
whuber

Teşekkürler! İşlev iyi çalışıyor, ancak 50 binden fazla satırınız varsa çok fazla zaman alıyor. Daha hafif yapmak için bir fikrin var mı?

Yanıtlar:


11

Aşağıdaki işlevle yeni bir veri kümesi için küme atamalarını hesaplayabilirsiniz:

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")

küme ataması

veya k-demektir için uygulanan bir yöntemi olan flexclust paketini kullanabilirsiniz predict:

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")

esneklik taslağı

Ayrıca, sonuçları küme işlevlerinden stats::kmeansveya gibi küme işlevlerinden cluster::pamsınıf nesnelerine dönüştürmek için dönüştürme yöntemleri kccade vardır:

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

Çok teşekkür ederim! Sadece bir soru: kcca yöntemleri başlangıç ​​sayısı ile nasıl ilgilenir (analizi başlangıç ​​noktalarına göre optimize eder mi)?
user2598356

Başlangıç ​​sayısı ile ne demek istiyorsun? stepFlexclustFonksiyon kümelerinin farklı numaralar için tekrar tekrar algoritmalar kümeleme çalışır ve her biri için küme mesafesi çözümü içinde minimum döndürür.
rcs

1

step1: bir vektör ile bir matrisin her satırı arasındaki mesafeyi hesaplayan bir fonksiyon

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

2. adım: vec2mat bilgisayarını input_matrix öğesinin her satırına uygulayan bir işlev

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)))
}

Aşama 3. mat2mat fonksiyonunu uygular

calc_mat2mat_dist(my_input_mat, kmeans_model$centers)

step4. İsteğe bağlı olarak büyük veri kümesi için mat2mat'ı paralelleştirmek için plyr :: ddply ve doMC kullanın

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)
    }

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.