1、爲什麼要降維
以下是在數據集中應用降維的用處:
(1)隨着數據維度不斷降低,數據存儲所需的空間也會隨之減少。
(2)低維數據有助於減少計算/訓練用時。
(3)一些算法在高維度數據上容易表現不佳,降維可提高算法可用性。
(4)降維可以用刪除冗餘特徵解決多重共線性問題。比如我們有兩個變量:“一段時間內在跑步機上的耗時”和“卡路里消耗量”。這兩個變量高度相關,在跑步機上花的時間越長,燃燒的卡路里自然就越多。因此,同時存儲這兩個數據意義不大,只需一個就夠了。
(5)降維有助於數據可視化。如前所述,如果數據維度很高,可視化會變得相當困難,而繪製二維三維數據的圖表非常簡單。
其實通過特徵評價去掉一些不必要的特徵也屬於降維。
2、常用降維算法
降維方法分爲線性核非線性降維,非線性降維又分爲基於核函數和基於特徵值的方法。
線性降維方法:PCA ICA LDA LFA LPP(LE的線性表示)
基於核函數的非線性降維方法:KPCA KICA KDA
基於特徵值的非線性降維方法(流型學習):ISOMAP LLE LE LPP LTSA MVU
3、Julia中提供的代碼庫
MultivariateStats 是一個用於多元統計分析的Julia包。它提供了一套豐富有用的分析技術,如PCA、kernel PCA、CCA、LDA、PLS等。
ScikitLearn.jl 也提供了上面類似的降維函數,但是需要依賴Python的代碼包。
4、特徵降維函數使用說明
這裏重點介紹kernel PCA使用方式
4.1、kernel PCA
MultivariateStats 中的 kernel PCA函數接口參數如下:
參數名稱 |
參數描述 |
默認 |
kernel |
核函數:它接收兩個矢量 x 和 y,並返回標量值。 其他常用核函數參考:https://github.com/theogf/KernelFunctions.jl |
(x,y)->x'y |
solver |
解算器的選擇: :eig: 實際使用 函數eigfact,是一個特徵值分解函數,函數主要是給出矩陣的特徵值和特徵向量 :eigs: 實際使用函數eigs (總是用於稀疏數據),函數主要是通過迭代法來求解矩陣特徵值和特徵向量 |
:eig |
maxoutdim |
最大輸出尺寸,也就是我們實際需要的維度 |
min(d, n) |
inverse |
是否對未預計算的內核執行反變換計算,如果是數據分析,可以不用的 |
false |
β |
學習反變換的嶺迴歸的超參數 (前提是:inverse 爲 true). 如果是數據分析,可以不用主要用於圖像分析 |
1.0 |
tol |
eigs求解器的收斂性 |
0.0 |
maxiter |
eigs解算器的最大迭代次數 |
300 |
常用的核函數爲
函數 |
描述 |
(x,y)->x'y |
線性的 |
(x,y)->(x'y+c)^d |
多項式的 |
(x,y)->exp(-γ*norm(x-y)^2.0) |
徑向基函數 (RBF)。徑向基函數是一個取值僅僅依賴於離原點距離的實值函數,也就是Φ(x)=Φ(‖x‖),比如高斯函數 |
代碼示例
這裏提供一個較爲完整的數據分析流程
using MultivariateStats
using DataFrames,CSV
using Statistics
using LinearAlgebra
using Plots
using Clustering
using Query
using Parsers
import Query:@from
# download("http://samplecsvs.s3.amazonaws.com/Sacramentorealestatetransactions.csv","houses.csv")
houses = DataFrame(CSV.File(joinpath(dirname(pathof(DataFrames)),"D:/houses.csv")));
#####數據清洗-特徵相關性分析,這裏簡單過濾下。
#(1) 像street、city、zip 、latitude 和 longitude 都是地理位置信息相關的。
# 其中street、city、zip其實都太好量化,雖然zip是個數值,但是這個數值是沒有
# 規律無法使用歐式距離來衡量,所以我這裏選擇經緯度:latitude 和 longitude
#(2) 分類問題,type字段其實是一個分類,數據被分爲4類,Residential,Condo,Multi-Family,Unknown
# (3) sale_date 轉成毫秒,或者 可以擴展其他的特徵,比如月份 ,年份等,可能月份更好一點。可惜的是我們只有5月份的數據,索性不用了。
# unique(houses[!,:type])
# occursin("a","Condo,Residential,Multi-Family")
function newType(type::AbstractString)
if type === "Residential"
return 1.0
elseif type === "Condo"
return 2.0
elseif type === "Multi-Family"
return 3.0
end
end
# function parseDate(date::String)
# diffDate = DateTime(2000, 01, 01)
# parseDate =Parsers.parse(DateTime, string("2008-05-",date[9:10]), Parsers.Options(dateformat="m/d/yyyy I:M:S.s p"))
# return (parseDate-diffDate).value
# end
newHouses = @from i in houses begin
@let newType = newType(i.type)
# @let neSaleDate = parseDate(string(i.sale_date))
@where i.sq__ft > 0 && (i.type ==="Residential" || i.type ==="Condo"|| i.type ==="Multi-Family" )
@select {i.beds,i.baths,i.sq__ft,i.price,type=newType,i.latitude,i.longitude }
@collect DataFrame
end
#### sq__ft,i.price,i.latitude,i.longitude這幾個的特徵值比較大,爲了消除各個特徵向量的差異性,對數據做標準化
#使用Z標準化,並把數據變成浮點數
mapcols(x -> x*1.0, newHouses)
function zscore(df::DataFrame)
h_mean = map(mean,eachcol(df[!,1:end]))
h_sdt = map(std,eachcol(df[!,1:end]))
h,c = size(df[!,1:end])
for col in 1:c
mean_v=h_mean[col]
std_v = h_sdt[col]
println(mean_v)
for hex in 1:h
@inbounds df[hex,col] = (df[hex,col]-mean_v)/std_v
end
end
end
zscore(newHouses)
#####現在也沒有特別好的算法來判斷矩陣是線性還是非線性,我這裏通過圖來分析是否是線性數據,
#直觀上看,如果特徵變量之間沒有線性關係,大概率是非線性的數據,
plot(size=(500,500),leg=false)
x = newHouses[:sq__ft]
y = newHouses[:price]
scatter(x,y)
x = newHouses[:latitude]
y = newHouses[:longitude]
scatter(x,y)
#### 未降維之前 kmean 算法分析下
features = collect(Float64,Matrix(newHouses[:, 1:end])');
features
result = kmeans(features, 2)
scatter([newHouses.sq__ft], [newHouses.price], marker_z=result.assignments,
color=:lightrainbow, legend=false)
### 核PCA降維(如果是線性數據可以使用PCA,這兩種常用的降維算法,適用與不同的矩陣)
# fh = disallowmissing(newHouses)
# 核PCA適合處理非線性數據,首先需要判斷數據是屬於線性的還是非線性的
# 如果各個特徵向量之間的差異比較大,可以先做數據的標準化。
#線性函數降維 (x,y)->x'y 也是默認的核函數
thisMtrix = Matrix{Float64}(newHouses[:,:])'
x = thisMtrix
# train a kernel PCA model
M = fit(KernelPCA, x; maxoutdim=2, inverse=true)
# apply kernel PCA model to testing set
Yte = transform(M, x)
# reconstruct testing observations (approximately)
# Xr = reconstruct(M, Yte)
result = kmeans(Yte, 3)
scatter(Yte[1,:], Yte[2,:], marker_z=result.assignments,
color=:lightrainbow, legend=false)
f_result = fuzzy_cmeans(Yte, 3, 2, maxiter=50, display=:iter)
這裏有兩張圖可以對降維前後數據分析效果做對比:
降維前對 sq__ft (面積),price(價格)作圖分析:
降維後作圖分析,明顯更加直觀
其他函數待續。。。。