2017-04-26 95 views
0

使用DBSCAN對象和高爾距離矩陣爲新的數據預測簇標記。 我創建模型時所使用的高爾距離矩陣:如何我在與預測簇標記爲測試數據的基礎上,對訓練數據的DBSCAN聚類分析模型的問題[R

> gowerdist_train <- daisy(analdata_train, 
        metric = "gower", 
        stand = FALSE, 
        type = list(asymm = c(5,6))) 

使用這種gowerdist矩陣,創造了DBSCAN集羣化模型爲:

> sb <- dbscan(gowerdist_train, eps = .23, minPts = 50) 

然後我嘗試使用預測使用的標記測試數據集上述DBSCAN對象:

> predict(sb, newdata = analdata_test, data = analdata_train) 

但我收到以下錯誤:

Error in frNN(rbind(data, newdata), eps = object$eps, sort = TRUE, ...) : x has to be a numeric matrix

我可以在哪裏這個錯誤可能是未來的,這可能是由於不存在尚未測試數據創建的高爾距離矩陣的猜測。 我的問題是,我應該創建一個高爾距離矩陣的所有數據(datanal_train + datanal_test)分開,並將其饋送到預測?算法如何知道列車數據中測試數據的距離,以便標記?

在這種情況下,將在newdata參數是包含ALL(火車+試驗)數據的新高爾距離矩陣?並且預測中的數據參數將是訓練距離矩陣,gowerdist_train?

我不太確定的是預測算法如何區分新創建的gowerdist_all矩陣中的測試數據集和列車數據集?

兩個矩陣(對於所有數據和gowerdist_train新gowerdist)顯然不具有相同的尺寸。此外,它沒有任何意義,我只爲測試數據創建一個高爾距離矩陣,因爲距離必須相對於測試數據,而不是測試數據本身。


編輯:

饋送時,我試圖使用高爾距離矩陣的所有數據(火車+試驗)作爲新的數據和接收到的錯誤來預測:

> gowerdist_all <- daisy(rbind(analdata_train, analdata_test), 
         metric = "gower", 
         stand = FALSE, 
         type = list(asymm = c(5,6))) 
> test_sb_label <- predict(sb, newdata = gowerdist_all, data = gowerdist_train) 

ERROR: Error in 1:nrow(data) : argument of length 0 In addition: Warning message: In rbind(data, newdata) : number of columns of result is not a multiple of vector length (arg 1)

所以,我建議的解決方案不起作用。

+0

對DBSCAN的「預測」並沒有很好的定義。通常,這表示您應該在分類時使用集羣。 –

+0

好的,我聯繫了負責維護dbscan R軟件包的人員,並被告知在dbscan軟件包中執行預測時存在問題(它不適用於距離矩陣),我應該在相應的論壇,所以它在包中被固定。 在此期間,我決定嘗試構建一個算法來完成這項工作。 – Ankhnesmerira

+0

我正在談論這樣做的理論*支持,而不是實現(因爲我不使用R,我不太在乎這個包)。單點可能會導致集羣合併,因此「預測」函數需要能夠返回「它會導致集羣1 + 2合併」,或「它會在這裏產生一個新集羣」等。** * DBSCAN的「預測」的想法*有問題**,並且通常在該方法的早期表示一個糟糕的想法。 –

回答

0

我決定創建一個代碼,使用dbscan中的KNN算法來預測使用gower距離矩陣的聚類標記。代碼不是很漂亮,絕對不是編程高效的,但它的工作原理。歡迎任何可以改善它的建議。

的pseydocode是: 1)計算新的高爾距離矩陣的所有數據,包括測試和列車 2)使用的kNN函數(DBSCAN包上述距離矩陣)來確定k個最近鄰每個測試數據點。 3)確定每個測試點所有那些最近點的聚類標籤。其中一些將沒有聚類標籤,因爲它們本身就是測試點 4)創建一個計數矩陣來計算每個測試點的k個最近點的聚類頻率 5)使用非常簡單的似然性計算來爲測試點基於其鄰居集羣(最大頻率)。這部分也考慮了相鄰的測試點。也就是說,只有當您將相鄰測試點的數量添加到其他羣集時,最大頻率最大時,纔會選擇測試點的羣集。否則,它不會決定該測試點的集羣,並等待下一次迭代,當希望更多的相鄰測試點根據它們的鄰居來確定它們的集羣標籤時。 6)重複上面的步驟(步驟2-5),直到你已經決定了所有簇

**注意:這個算法不會一直收斂。 (一旦你做了數學,這是顯而易見的原因),所以在代碼中,當非集羣測試點的數量在一段時間之後沒有改變時,我就跳出算法。然後我再次用新knn重複2-6(改變最近鄰居的數量,然後再次運行代碼)。這將確保更多的積分參與決定下一輪。我已經嘗試了更大和更小的knn,並且都工作。很高興知道哪一個更好。到目前爲止,我不必運行代碼兩次以確定測試數據點的簇。

下面是代碼:

#calculate gower distance for all data (test + train) 
gowerdist_test <- daisy(all_data[rangeofdataforgowerdist], 
         metric = "gower", 
         stand = FALSE, 
         type = list(asymm = listofasymmvars), 
         weights = Weights) 
summary(gowerdist_test) 

然後使用下面給標籤集羣的代碼測試數據。

#library(dbscan) 
# find the k nearest neibours for each point and order them with distance 
iteration_MAX <- 50 
iteration_current <- 0 
maxUnclusterRepeatNum <- 10 
repeatedUnclustNum <- 0 
unclusteredNum <- sum(is.na(all_data$Cluster)) 
previousUnclustereNum <- sum(is.na(all_data$Cluster)) 
nn_k = 30 #number of neighbourhoods 

while (anyNA(all_data$Cluster) & iteration_current < iteration_MAX) 
{ 
    if (repeatedUnclustNum >= maxUnclusterRepeatNum) { 
    print(paste("Max number of repetition (", maxUnclusterRepeatNum ,") for same unclustered data has reached. Clustering terminated unsuccessfully.")) 
    invisible(gc()) 
    break; 
    } 

     nn_test <- kNN(gowerdist_test, k = nn_k, sort = TRUE) 

    # for the TEST points in all data, find the closets TRAIN points and decide statistically which cluster they could belong to, based on the clusters of the nearest TRAIN points 
    test_matrix <- nn_test$id[1: nrow(analdata_test),] #create matrix of test data knn id's 
    numClusts <- nlevels(as.factor(sb_train$cluster)) 
    NameClusts <- as.character(levels(as.factor(sb_train$cluster))) 
    count_clusters <- matrix(0, nrow = nrow(analdata_test), ncol = numClusts + 1) #create a count matrix that would count number of clusters + NA 
    colnames(count_clusters) <- c("NA", NameClusts) #name each column of the count matrix to cluster numbers 

    # get the cluster number of each k nearest neibhour of each test point 
    for (i in 1:nrow(analdata_test)) 
     for (j in 1:nn_k) 
     { 
     test_matrix[i,j] <- all_data[nn_test$id[i,j], "Cluster"] 
     } 
    # populate the count matrix for the total clusters of the neighbours for each test point 
    for (i in 1:nrow(analdata_test)) 
     for (j in 1:nn_k) 
     { 
     if (!is.na(test_matrix[i,j])) 
      count_clusters[i, c(as.character(test_matrix[i,j]))] <- count_clusters[i, c(as.character(test_matrix[i,j]))] + 1 
     else 
      count_clusters[i, c("NA")] <- count_clusters[i, c("NA")] + 1 
     } 
    # add NA's (TEST points) to the other clusters for comparison 
    count_clusters_withNA <- count_clusters 
    for (i in 2:ncol(count_clusters)) 
     { 
     count_clusters_withNA[,i] <- t(rowSums(count_clusters[,c(1,i)])) 
    } 

    # This block of code decides the maximum count of cluster for each row considering the number other test points (NA clusters) in the neighbourhood 
    max_col_countclusters <- apply(count_clusters,1,which.max) #get the column that corresponds to the maximum value of each row 
    for (i in 1:length(max_col_countclusters)) #insert the maximum value of each row in its associated column in count_clusters_withNA 
     count_clusters_withNA[i, max_col_countclusters[i]] <- count_clusters[i, max_col_countclusters[i]] 
    max_col_countclusters_withNA <- apply(count_clusters_withNA,1,which.max) #get the column that corresponds to the maximum value of each row with NA added 
    compareCountClust <- max_col_countclusters_withNA == max_col_countclusters #compare the two count matrices 
    all_data$Cluster[1:nrow(analdata_test)] <- ifelse(compareCountClust, NameClusts[max_col_countclusters - 1], all_data$Cluster) #you subtract one because of additional NA column 


    iteration_current <- iteration_current + 1 

    unclusteredNum <- sum(is.na(all_data$Cluster)) 
    if (previousUnclustereNum == unclusteredNum) 
     repeatedUnclustNum <- repeatedUnclustNum + 1 
    else { 
     repeatedUnclustNum <- 0 
     previousUnclustereNum <- unclusteredNum 
    } 

    print(paste("Iteration: ", iteration_current, " - Number of remaining unclustered:", sum(is.na(all_data$Cluster)))) 
    if (unclusteredNum == 0) 
     print("Cluster labeling successfully Completed.") 

    invisible(gc()) 
} 

我想你可以使用任何其他類型的聚類算法,它不要緊,你如何決定簇標籤的訓練數據,只要它們在運行代碼之前你all_data。 希望得到這個幫助。 不是最有效或最嚴謹的代碼。所以,很高興看到如何改進它的建議。

*注:我使用t-SNE來比較列車的集羣和測試數據,並且看起來非常乾淨。所以,它似乎在工作。

相關問題