web-dev-qa-db-ja.com

重心とデータ行列の間の距離を計算する方法(kmeansアルゴリズムの場合)

私はクラスタリングとRの学生です。両方をよりよく把握するために、「収束」するまでの各反復の重心とxy行列の間の距離を計算したいと思います。 Rを使用してステップ2と3を解決するにはどうすればよいですか?

_library(fields)
x <- c(3,6,8,1,2,2,6,6,7,7,8,8)
y <- c(5,2,3,5,4,6,1,8,3,6,1,7)

df <- data.frame(x,y) initial matrix
a  <- c(3,6,8)
b  <- c(5,2,3)

df1 <- data.frame(a,b) # initial centroids
_

これが私がやりたいことです:

  1. I0 <- t(rdist(df, df1))ゼロ反復後
  2. 最小距離に基づいてオブジェクトをクラスター化する
  3. クラスター平均に基づいて重心を決定する
  4. I1での繰り返し

kmeans関数を試しました。しかし、いくつかの理由で、それは最後に出なければならないそれらの重心を生成します。つまり、私は次の始まりを定義しました:

_start   <- matrix(c(3,5,6,2,8,3), 3, byrow = TRUE)
cluster <- kmeans(df,centers = start, iter.max = 1) # one iteration
_

kmeansでは、図心の動きを追跡できません。したがって、Rを使用してステップ2と3を適用することにより、「手動で」実行したいと思います。

10
Mamba

あなたの主な質問は、データマトリックスといくつかの点のセット(「中心」)の間の距離をどのように計算するかということのようです。

このために、データマトリックスとポイントのセットを入力として受け取り、データマトリックスの各行(ポイント)のすべての「中心」までの距離を返す関数を作成できます。

これがそのような関数です:

_myEuclid <- function(points1, points2) {
    distanceMatrix <- matrix(NA, nrow=dim(points1)[1], ncol=dim(points2)[1])
    for(i in 1:nrow(points2)) {
        distanceMatrix[,i] <- sqrt(rowSums(t(t(points1)-points2[i,])^2))
    }
    distanceMatrix
}
_

_points1_は、ポイントを行、ディメンションを列とするデータマトリックスです。 _points2_は中心の行列です(再び行としてポイントします)。コードの最初の行は、回答マトリックスを定義するだけです(データマトリックスの行と同じ数の行と、中心と同じ数の列があります)。したがって、結果行列の点_i,j_は、ith点からjth中心までの距離になります。

次に、forループがすべてのセンターで繰り返されます。各中心について、各点から現在の中心までのユークリッド距離を計算し、結果を返します。ここでのこの行:sqrt(rowSums(t(t(points1)-points2[i,])^2))はユークリッド距離です。それを詳しく調べて、問題があれば式を調べてください。 (そこでの転置は、主に減算が行単位で行われていることを確認するために行われます)。

これで、k-meansアルゴリズムを実装することもできます。

_myKmeans <- function(x, centers, distFun, nItter=10) {
    clusterHistory <- vector(nItter, mode="list")
    centerHistory <- vector(nItter, mode="list")

    for(i in 1:nItter) {
        distsToCenters <- distFun(x, centers)
        clusters <- apply(distsToCenters, 1, which.min)
        centers <- apply(x, 2, tapply, clusters, mean)
        # Saving history
        clusterHistory[[i]] <- clusters
        centerHistory[[i]] <- centers
    }

    list(clusters=clusterHistory, centers=centerHistory)
}
_

ご覧のとおり、これも非常に単純な関数です。データマトリックス、中心、距離関数(上記で定義したもの)、および必要な反復回数が必要です。

クラスターは、各ポイントに最も近い中心を割り当てることによって定義されます。そして、センターは、そのセンターに割り当てられたポイントの平均として更新されます。これは基本的なk-meansアルゴリズムです)。

試してみましょう。いくつかのランダムな点を定義します(2次元であるため、列の数= 2)

_mat <- matrix(rnorm(100), ncol=2)
_

その行列から5つのランダムな点を初期中心として割り当てます。

_centers <- mat[sample(nrow(mat), 5),]
_

次に、アルゴリズムを実行します。

_theResult <- myKmeans(mat, centers, myEuclid, 10)
_

10回目の反復の中心は次のとおりです。

_theResult$centers[[10]]
        [,1]        [,2]
1 -0.1343239  1.27925285
2 -0.8004432 -0.77838017
3  0.1956119 -0.19193849
4  0.3886721 -1.80298698
5  1.3640693 -0.04091114
_

実装されたkmeans関数と比較してください。

_theResult2 <- kmeans(mat, centers, 10, algorithm="Forgy")

theResult2$centers
        [,1]        [,2]
1 -0.1343239  1.27925285
2 -0.8004432 -0.77838017
3  0.1956119 -0.19193849
4  0.3886721 -1.80298698
5  1.3640693 -0.04091114
_

正常に動作します。ただし、この関数は反復を追跡します。次のように、最初の4回の反復の進行状況をプロットできます。

_par(mfrow=c(2,2))
for(i in 1:4) {
    plot(mat, col=theResult$clusters[[i]], main=paste("itteration:", i), xlab="x", ylab="y")
    points(theResult$centers[[i]], cex=3, pch=19, col=1:nrow(theResult$centers[[i]]))
}
_

Kmeans

いいね。

ただし、このシンプルな設計により、さらに多くのことが可能になります。たとえば、別の種類の距離(ユークリッドではない)を使用する場合は、データと中心を入力として受け取る任意の関数を使用できます。相関距離の場合は次のとおりです。

_myCor <- function(points1, points2) {
    return(1 - ((cor(t(points1), t(points2))+1)/2))
}
_

そして、それらに基づいてKmeansを実行できます。

_theResult <- myKmeans(mat, centers, myCor, 10)
_

4回の反復で得られる画像は、次のようになります。

enter image description here

5つのクラスターを指定した場合でも、最後に2つ残っていました。これは、2次元の場合、相関は+1または-1のいずれかの値になる可能性があるためです。次に、クラスターを探すときに、複数の中心までの距離が同じであっても、各ポイントが1つの中心に割り当てられます。最初の点が選択されます。

とにかく、これは現在範囲外になっています。要するに、可能な距離メトリックは多数あり、1つの単純な関数を使用すると、任意の距離を使用して、反復にわたって結果を追跡できます。

23