R 中的資料探勘演算法/降維/奇異值分解
在本章中,我們將探討奇異值分解(SVD),這是一種矩陣分解方法,利用線性代數知識來進行這樣的分解。
在資料探勘中,此演算法可用於透過顯示重要維度的數量來更好地理解資料庫,並透過減少資料探勘過程中使用的屬性數量來簡化資料庫。這種減少消除了從線性代數角度來看線性相關的非必要資料。例如,假設一個數據庫包含一個欄位,該欄位儲存多個樣本的水溫,另一個欄位儲存其狀態(固體、液體或氣體)。很容易看出,第二個欄位依賴於第一個欄位,因此,SVD 可以輕鬆地向我們表明它對於分析並不重要。
主成分分析 (PCA) 是 SVD 的一個特例。
SVD 是對具有 行和 列的實數或複數矩陣 的因式分解。
其中 是一個維度為 的矩陣, 是另一個維度為 的矩陣, 是一個維度為 的矩陣,與 的維度相同。
此外
和
其中 和 是單位矩陣,大小分別為 和 .
矩陣 的列是矩陣 的 **左奇異向量**,矩陣 (或 的行)的列是 **右奇異向量**。
矩陣 是對角矩陣,其對角線上的值是矩陣 的 **奇異值**。矩陣 中每行上的奇異值永遠不會小於其下方行的值。所有奇異值都大於 .
計算 SVD 就是找到 和 的特徵值和特徵向量。 的特徵向量是 的列,而 的特徵向量是 的列。矩陣 的奇異值(在矩陣 的對角線上)是 和 共有的正特徵值的平方根。
如果 和 具有相同數量的特徵值,則 是一個方陣;否則,特徵值較少的矩陣的特徵值是特徵值較多的矩陣的特徵值。因此, 的奇異值是矩陣的特徵值,位於 和 中,特徵值較少的矩陣中。
矩陣的奇異值數量等於該矩陣的秩,即矩陣中線性無關的列或行的數量。秩不大於 ,因為這是矩陣對角線上元素的數量。奇異值是矩陣 對角線上的元素。正奇異值的數量等於矩陣的秩。
因此,演算法如下
- 計算 通常。
- 計算 的特徵值和特徵向量通常。
- 計算 。
- 計算 的特徵值和特徵向量。
- 計算 和 的公共正特徵值的平方根。
- 最後,將計算出的值分配給 , 和 。
X =
XXT =
XXT 的特徵值為
- 12.744563, 4.000000 和 1.255437
XXT 的特徵向量為
- 0.5417743, 0.5417743, 0.6426206
- 0.7071068, -0.7071068, -2.144010 x 10-16
- 0.4544013, 0.4544013, -0.7661846
XTX =
XTX 的特徵值為
- 12.744563, 4.000000, 1.255437 和 (5.940557 x 10-18)
XTX 的特徵向量為
- 0.6635353, 0.3035190, 0.4835272, 0.4835272
- 0.0000000, 0.5181041 x 10-16, -0.7071068, 0.7071068
- -0.5565257, 0.8110957, 0.1272850, 0.1272850
- 0.5000000, 0.5000000, -0.5000000, -0.5000000
X 的奇異值為 XTX 和 XXT 的共同特徵值的平方根
因此
A =
最後,X 被分解為
X = UAVT =
實現
[edit | edit source]R 內建了一個名為'svd()'的函式用於計算 SVD。
預設情況下,它接收 R 的 原生矩陣 作為引數,並返回一個包含 U、A 和 V 的 資料框。
引數
[edit | edit source]如果不需要計算所有奇異值和向量,可以告訴 svd() 需要多少個元素。
這可以透過將這些值分別分配給 **nu** 和 **nv** 來實現,它們分別代表所需的左奇異向量和右奇異向量數量。
例如,為了只計算一半的向量,可以執行以下操作
svd(X, nu = min(nrow(X), ncol(X)) / 2, nv = min(nrow(X), ncol(X))/2)
返回的物件
[edit | edit source]s = svd(X)
考慮到
X = UAVT
返回的物件是一個包含三個欄位的資料結構
s$d 是包含 X 的奇異值的向量,它來自矩陣 A 的對角線。
s$u 是一個矩陣,它的列包含 X 的左奇異向量。它的行數與 X 的行數相同,它的列數與傳遞給引數 nu 的數字相同。注意,如果 nu 為 0,則不會建立此矩陣。
s$v 是一個矩陣,它的列包含 X 的右奇異向量。它的行數與 X 的列數相同,它的列數與傳遞給引數 nv 的數字相同。注意,如果 nv 為 0,則不會建立此矩陣。
例子
[edit | edit source]在 R 終端或 R 程式中執行以下命令序列,並檢視結果
示例 1
dat <- seq(1,240,2) X <- matrix(dat,ncol=12) s <- svd(X) A <- diag(s$d) s$u %*% A %*% t(s$v) # X = U A V'
示例 2
dat <- seq(1,240,2) X <- matrix(dat,ncol=12) s <- svd(X, nu = nrow(X), nv = ncol(X)) A <- diag(s$d) A <- cbind(A, 0) # Add two columns with zero, in order to A have the same dimensions of X. A <- cbind(A, 0) s$u %*% A %*% t(s$v) # X = U A V'
為了更好地視覺化 SVD 的結果,在這個案例研究中,我們將使用一個表示影像的矩陣,這樣任何對矩陣的更改都可以輕鬆觀察到。
要使用 R 處理影像,應安裝 rimage 包
> install.packages("rimage")
然後將影像載入到 R 中,將其轉換為灰度影像。這樣,我們將得到一個二進位制矩陣,其中 1 表示白色,0 表示黑色。
library(rimage)
tux <- read.jpeg('tux.jpeg')
tux <- imagematrix(tux,type='grey')
我們可以看到此匯入的結果
plot(tux)
為了幫助我們進行降維,讓我們建立一個小的輔助函式,該函式將接收我們的 tux 和我們想要的維度數,並返回我們的新的 tux。
reduce <- function(A,dim) {
#Calculates the SVD
sing <- svd(A)
#Approximate each result of SVD with the given dimension
u<-as.matrix(sing$u[, 1:dim])
v<-as.matrix(sing$v[, 1:dim])
d<-as.matrix(diag(sing$d)[1:dim, 1:dim])
#Create the new approximated matrix
return(imagematrix(u%*%d%*%t(v),type='grey'))
}
現在我們有了矩陣,讓我們看看它有多少奇異值
tux_d <- svd(tux) length(tux_d$d) [1] 335
因此,這個矩陣有 335 個奇異值。讓我們首先嚐試將其減少到只有一個奇異值
plot(reduce(tux,1))
正如我們所看到的,這種近似值從我們的矩陣中刪除了許多有用的資訊。如果它是資料庫,我們肯定已經丟失了重要的資料。
讓我們嘗試使用 10% (35) 個奇異值
plot(reduce(tux,35))
僅使用 10% 的真實資料,我們就能創建出真實資料的非常好的近似值。此外,透過這種方法,我們只需使用最重要的奇異值就可以去除噪聲和線性相關元素。這在資料探勘中非常有用,因為很難確定資料庫是否“乾淨”,如果不是,哪些元素對我們的分析有用或無用。
- 資料探勘演算法基礎 - Mohammed J. Zaki,Wagner Meira Jr. - 第 7.4 章
- 奇異值分解
- http://www.ats.ucla.edu/stat/r/code/svd_demos.htm
- http://stat.ethz.ch/R-manual/R-patched/library/base/html/svd.html


