今週のテーマはK-meansとPCA
K-meansの方は割と理解しやすいというか、直感的に理解しやすい手法だと思います。
次元削減の考え方自体は直感的にわかりやすいのですがその実現方法でいきなりSVDが出てきて、ああそうですかという感じになりました。
2次元に次元削減する際はあるベクトルを選んでそのベクトルへの射影を使う。どのようなベクトルを使えばよいかはそのベクトル(延長)と元の点の距離をもとめすべてのデータの距離の和が最小になるようなベクトルを選べばよい。
ここまではいいけどいきなりsvd()を使いますってなってはあ?となりました。
Matlabのマニュアルによると
[U,S,V] = svd(A) は、A = USV' となるように、行列 A の特異値分解を実行します。
特異値分解とはなにか調べると
- U,Vはユニタリ行列
- 今扱っているのは実数の行列なので転置をとると逆行列になる、このことを後で使う
- 特異値分解と行列の低ランク近似 で検索すると意味を理解するのに役立つ情報が得られました
Programing exerciseの提出物は以下の6つ
- pca.m - Perform principal component analysis
- projectData.m - Projects a data set into a lower dimensional space
- recoverData.m - Recovers the original data from the projection
- findClosestCentroids.m - Find closest centroids (used in K-means)
- computeCentroids.m - Compute centroid means (used in K-means)
- kMeansInitCentroids.m - Initialization for K-means centroids
ex7.mとex7_pca.mの2つのパートに分かれている。
ex7がK-means clustering
ex7_pcaがもちろんPCAについて
上の提出物のファイルの順番はなぜかPACのファイルから書いてあって、順番が逆になっている。
K-meansの方から始める
findClosestCentroids.m
K点のcentroidとの距離を計算して一番近い点を選んでidxに登録する。
普通に二重のforループを書いてやれば難しくはないけどそこはoctaveっぽく書くとforループは二重にしなくて済むようだ。
computeCentroids.m
Xの各点をcentroidに一番近いか分類したので、各centroidに属する点の重心を求めてcentroidを更新する。これもforループは1つでかけるようだけど2つforループを書いて対応。
kMeansInitCentroids.m
これはpdfにあるコードをそのまま利用。
randperm (n)を使って1:nのベクターをシャッフルできる。
1:Xの行数をシャッフルして、ランダム順になったものを最初からKを使ってそれに対応するXの行を選んでcentroidsの初期値にする。
pca.m
pdfにある式を使ってΣを計算してsvd(Σ)とする
projectData.m
svdで計算したUからK個選んでこれを使ってfeatureを削減したZを求める
これも2重のforループを書いてしまったけど、マトリクスのまま1行で書けるようです。
recoverData.m
ZをUを使って元の次元(の近似値)に戻す。
Uは直行行列なので転置をとると逆行列になることを使って逆変換をする。
これさえわかればprojectData.mと同じようにできます。