以下是在数据集中应用降维的用处:
(1)随着数据维度不断降低,数据存储所需的空间也会随之减少。
(2)低维数据有助于减少计算/训练用时。
(3)一些算法在高维度数据上容易表现不佳,降维可提高算法可用性。
(4)降维可以用删除冗余特征解决多重共线性问题。比如我们有两个变量:“一段时间内在跑步机上的耗时”和“卡路里消耗量”。这两个变量高度相关,在跑步机上花的时间越长,燃烧的卡路里自然就越多。因此,同时存储这两个数据意义不大,只需一个就够了。
(5)降维有助于数据可视化。如前所述,如果数据维度很高,可视化会变得相当困难,而绘制二维三维数据的图表非常简单。
其实通过特征评价去掉一些不必要的特征也属于降维。
降维方法分为线性核非线性降维,非线性降维又分为基于核函数和基于特征值的方法。
线性降维方法:PCA ICA LDA LFA LPP(LE的线性表示)
基于核函数的非线性降维方法:KPCA KICA KDA
基于特征值的非线性降维方法(流型学习):ISOMAP LLE LE LPP LTSA MVU
MultivariateStats 是一个用于多元统计分析的Julia包。它提供了一套丰富有用的分析技术,如PCA、kernel PCA、CCA、LDA、PLS等。
ScikitLearn.jl 也提供了上面类似的降维函数,但是需要依赖Python的代码包。
这里重点介绍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(价格)作图分析:
降维后作图分析,明显更加直观
其他函数待续。。。。