Esiste una funzione in R che prende i centri dei cluster che sono stati trovati e assegna i cluster a un nuovo set di dati


14

Ho due parti di un set di dati multidimensionale, chiamiamole trainetest . E voglio costruire un modello basato sul set di dati del treno e quindi convalidarlo sul set di dati di test. Il numero di cluster è noto.

Ho provato ad applicare il clustering k-mean in R e ho ottenuto un oggetto che contiene i centri dei cluster:

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

Esiste una funzione in R che prende i centri dei cluster che sono stati trovati e assegna i cluster al mio set di dati di test?

Quali sono gli altri metodi / algoritmi che posso provare?


Benvenuto nel sito, @ user2598356. Puoi inquadrarlo in un modo più generale (non specifico per R)? Se stai solo chiedendo una funzione R, questa domanda sarebbe fuori tema per CV (vedi la nostra pagina di aiuto ). Inoltre, sarebbe fuori tema anche su Stack Overflow , poiché non ha un esempio riproducibile . Se puoi modificarlo per renderlo sull'argomento qui o su SO, per favore fallo. Altrimenti, questa Q potrebbe essere chiusa.
gung - Ripristina Monica

Questa domanda sembra fuori tema perché riguarda la ricerca di una funzione R.
gung - Ripristina Monica

1
Ma che dire dell'ultima domanda: "Quali sono gli altri metodi / algoritmi che posso provare?". In realtà la risposta che ho ricevuto riguarda l'implementazione dei metodi che è un argomento di CV, o sbaglio?
user2598356

1
@gung Potresti avere ragione, nel qual caso invito l'utente259 ... a contrassegnare questa domanda per la migrazione. Tuttavia, l'ultima parte della domanda su altri metodi e algoritmi suggerisce che la nostra comunità potrebbe essere in una buona posizione per offrire aiuto e consigli utili.
whuber

Grazie! La funzione funziona bene, ma ci vuole troppo tempo se hai più di 50k righe. Qualche idea per renderlo più leggero?

Risposte:


11

È possibile calcolare le assegnazioni dei cluster per un nuovo set di dati con la seguente funzione:

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

assegnazione di cluster

oppure potresti usare il pacchetto flexclust , che ha un predictmetodo implementato per k- mean :

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

trama flexclust

Esistono anche metodi di conversione per convertire i risultati da funzioni cluster come stats::kmeans o cluster::pamin oggetti di classe kccae viceversa:

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

Grazie mille! Solo una domanda: in che modo i metodi kcca gestiscono il numero di avvii (ottimizza l'analisi rispetto ai punti di partenza)?
user2598356

Cosa intendi con numero di avviamenti? La stepFlexclustfunzione esegue ripetutamente algoritmi di clustering per diversi numeri di cluster e restituisce la soluzione minima a distanza di cluster per ciascuno.
rcs,

1

step1: una funzione che calcola la distanza tra un vettore e ogni riga di una matrice

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

passaggio 2: una funzione che applica il computer vec2mat a ogni riga di 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)))
}

step3. applica la funzione mat2mat

calc_mat2mat_dist(my_input_mat, kmeans_model$centers)

step4. Facoltativamente, utilizzare plyr :: ddply e doMC per parallelizzare mat2mat per un set di dati di grandi dimensioni

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

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.