Gibt es eine Funktion in R, die die Zentren der gefundenen Cluster aufnimmt und einem neuen Datensatz Cluster zuordnet?

14

Ich habe zwei Teile eines mehrdimensionalen Datensatzes, nennen wir sie trainund test. Und ich möchte ein Modell auf der Grundlage des Zugdatensatzes erstellen und es dann anhand des Testdatensatzes validieren. Die Anzahl der Cluster ist bekannt.

Ich habe versucht, k-means Clustering in R anzuwenden, und ich habe ein Objekt erhalten, das die Clusterzentren enthält:

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

Gibt es eine Funktion in R, die die Zentren der gefundenen Cluster aufnimmt und meinem Testdatensatz Cluster zuordnet?

Welche anderen Methoden / Algorithmen kann ich ausprobieren?

user2598356
quelle
Willkommen auf der Site, @ user2598356. Können Sie dies allgemeiner (nicht R-spezifisch) formulieren? Wenn Sie nur nach einer R-Funktion fragen, ist diese Frage für den Lebenslauf nicht relevant (siehe unsere Hilfeseite ). Darüber hinaus wäre es auch beim Stack Overflow nicht zum Thema , da es kein reproduzierbares Beispiel gibt . Wenn Sie dies bearbeiten können, um es hier oder auf SO zum Thema zu machen, tun Sie dies bitte. Andernfalls kann dieser Q geschlossen werden.
gung - Wiedereinsetzung von Monica
Diese Frage scheint nicht zum Thema zu gehören, da es darum geht, eine R-Funktion zu finden.
gung - Wiedereinsetzung von Monica
1
Aber was ist mit der letzten Frage: "Was sind die anderen Methoden / Algorithmen, die ich ausprobieren kann?". Die Antwort, die ich bekommen habe, betrifft die Implementierung der Methoden, die ein Thema des Lebenslaufs sind, oder irre ich mich?
user2598356
1
@gung Vielleicht hast du recht. In diesem Fall lade ich user259 ... ein, diese Frage für die Migration zu kennzeichnen. Der letzte Teil der Frage zu anderen Methoden und Algorithmen lässt jedoch vermuten, dass unsere Community in der Lage ist, nützliche Hilfe und Ratschläge anzubieten.
whuber
Vielen Dank! Die Funktion funktioniert gut, aber es dauert zu lange, wenn Sie mehr als 50.000 Zeilen haben. Irgendeine Idee, es leichter zu machen?

Antworten:

11

Sie können die Clusterzuordnungen für einen neuen Datensatz mit der folgenden Funktion berechnen:

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

Clusterzuordnung

oder Sie können das Paket flexclust verwenden , das eine implementierte predictMethode für k-means enthält:

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

flexclust plot

Es gibt auch Konvertierungsmethoden, um die Ergebnisse von Clusterfunktionen wie stats::kmeansoder cluster::pamin Klassenobjekte kccaund umgekehrt zu konvertieren :

as.kcca(cl, data=x)
# kcca object of family ‘kmeans’ 
#
# call:
# as.kcca(object = cl, data = x)
#
# cluster sizes:
#
#  1  2 
#  50 50 
rcs
quelle
Vielen Dank! Nur eine Frage: Wie geht die kcca-Methode mit der Anzahl der Starts um (optimiert sie die Analyse in Bezug auf die Startpunkte)?
user2598356
Was meinst du mit Anzahl der Starts? DasstepFlexclust Funktion führt Clustering-Algorithmen wiederholt für eine unterschiedliche Anzahl von Clustern aus und gibt jeweils das Minimum innerhalb der Cluster-Distanz-Lösung zurück.
RCS
1

Schritt 1: Eine Funktion, die den Abstand zwischen einem Vektor und jeder Zeile einer Matrix berechnet

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

Schritt 2: Eine Funktion, die den vec2mat-Computer auf jede Zeile der input_matrix anwendet

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

Schritt 3. Wenden Sie die mat2mat-Funktion an

calc_mat2mat_dist(my_input_mat, kmeans_model$centers)

Schritt 4. Verwenden Sie optional plyr :: ddply und doMC, um mat2mat für große Datenmengen zu parallelisieren

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

}
XX
quelle