特征选择也叫特征子集选bai择 ( FSS , Feature Subset Selection ) 。是指从已有的M个特征(Feature)中选择N个特征使得系统的特定指标最优化。这么做的理由如下:
一是可以缓解维数灾难,你的机器学习算法的上限,就是你放入的特征
二是降低学习任务的难度,需要寻求尽量少的特征,但是却能真正把握数据的趋势和模式
三是可以增强一点可解释性,不相关的特征就是噪声。
特征选择的方式有很多比如:过滤式,包裹式,嵌入式。但是很多时候凭借人的直觉就可以去掉一些无关的特征。
1、Filter方法
其主要思想是:对每一维的特征“打分”,即给每一维的特征赋予权重,这样的权重就代表着该维特征的重要性,然后依据权重排序。
主要的方法有:Chi-squared test(卡方检验),ID3(信息增益),correlation coefficient scores(相关系数)
2、Wrapper方法:
其主要思想是:将子集的选择看作是一个搜索寻优问题,生成不同的组合,对组合进行评价,再与其他的组合进行比较。这样就将子集的选择看作是一个是一个优化问题,这里有很多的优化算法可以解决,尤其是一些启发式的优化算法,如GA,PSO,DE,ABC等,详见“优化算法——人工蜂群算法(ABC)”,“优化算法——粒子群算法(PSO)”。
主要方法有:recursive feature elimination algorithm(递归特征消除算法)
3、Embedded方法
其主要思想是:在模型既定的情况下学习出对提高模型准确性最好的属性。这句话并不是很好理解,其实是讲在确定模型的过程中,挑选出那些对模型的训练有重要意义的属性。
主要方法:正则化。如岭回归就是在基本线性回归的过程中加入了正则项。
这里没有严格按照上面的分类给出响应的代码示例。但是会把scikit-learn中提到的一些方法,用Julia代码给出示例。
python代码可以参考:Feature selection
VarianceThreshold是一种简单的特征选择基线方法。它删除了方差不满足某个阈值的所有特征。默认情况下,它会删除所有零方差特征,即在所有样本中具有相同值的特征
using LinearAlgebra
using DataFrames,CSV
using Statistics
using ScikitLearn
@sk_import feature_selection: VarianceThreshold
houses = DataFrame(CSV.File(joinpath(dirname(pathof(DataFrames)),"D:/houses.csv")));
feature = Matrix(houses[:, [:beds,:baths,:sq__ft,:price,:latitude,:longitude]])
#设置阈值,也就是会过滤方差<.8 * (1 - .8)
sel = VarianceThreshold(threshold=.8 * (1 - .8))
mapper = fit!(sel,feature)
#很明显过滤了两个不太相关的特征
fit_transform!(mapper, copy(feature))
# 985×4 Array{Float64,2}:
# 2.0 1.0 836.0 59222.0
# 3.0 1.0 1167.0 68212.0
# 2.0 1.0 796.0 68880.0
# 2.0 1.0 852.0 69307.0
# 2.0 1.0 797.0 81900.0
# 3.0 1.0 1122.0 89921.0
# 3.0 2.0 1104.0 90895.0
using LinearAlgebra
using DataFrames,CSV
using Statistics
using ScikitLearn
@sk_import feature_selection: SelectPercentile
@sk_import feature_selection: SelectKBest
#卡方检验是假设检验的一种,用于分析两个类别变量的相关关系
@sk_import feature_selection: chi2
@sk_import datasets: load_boston
houses = DataFrame(CSV.File(joinpath(dirname(pathof(DataFrames)),"D:/houses.csv")));
feature = Matrix(houses[:, [:beds,:baths,:sq__ft,:price,:latitude,:longitude]])
#负值转为正值
feature[:,6] = feature[:,6]*-1
X = feature
y = feature[:,4]
#设置要选择的特征维度
#这个地方要注意的是因变量Y 必须为整数,不能为浮点数。
selector = SelectKBest(chi2, k=3)
fit_transform!(selector, X,y)
#使用百分比
X,y = load_boston(return_X_y=true)
y = [round(y[i]) for i in 1:length(y)]
selector = SelectPercentile(chi2, percentile=50)
fit_transform!(selector, X,y)
SVM简介
支持向量机(support vector machines, SVM)是一种二分类模型,它的基本模型是定义在特征空间上的间隔最大的线性分类器,间隔最大使它有别于感知机;SVM还包括核技巧,这使它成为实质上的非线性分类器。SVM的的学习策略就是间隔最大化,可形式化为一个求解凸二次规划的问题,也等价于正则化的合页损失函数的最小化问题。SVM的的学习算法就是求解凸二次规划的最优化算法。
SVC和SVR
support vector classify(SVC)支持分类机做二分类的,找出分类面,解决分类问题
support vector regression(SCR)支持回归机做曲线拟合、函数回归 ,做预测,温度,天气,股票
代码示例:
using LinearAlgebra
using DataFrames,CSV
using Statistics
using ScikitLearn
using PyCall
using Colors
using PyPlot
import PyPlot:plot
@sk_import feature_selection: RFE
@sk_import svm: SVC
@sk_import datasets: load_digits
@pyimport numpy as pynumpy
digits = load_digits()
X = digits["images"]
y = digits["target"]
# julia reshape和 Python 中 numpy.reshape的用法还是有区别的,只能用下面的方式 模拟numpy.reshape算法
# X = pynumpy.reshape(digits["images"],(length(digits["images"][:,1,1]), -1))
vector_2D = [X[i,:,:] for i in 1:length(X[:,1,1]) ]
X = convert(Array{Float64,2},X)
#SVM简介
#支持向量机(support vector machines, SVM)是一种二分类模型,它的基本模型是定义在特征空间上的间隔最大的线性分类器,间隔最大使它有别于感知机;SVM还包括核技巧,这使它成为实质上的非线性分类器。SVM的的学习策略就是间隔最大化,可形式化为一个求解凸二次规划的问题,也等价于正则化的合页损失函数的最小化问题。SVM的的学习算法就是求解凸二次规划的最优化算法。
#对SVC和SVR的理解
#support vector classify(SVC)支持分类机做二分类的,找出分类面,解决分类问题
#support vector regression(SCR)支持回归机做曲线拟合、函数回归 ,做预测,温度,天气,股票
svc = SVC(kernel="linear", C=1)
rfe = RFE(estimator=svc, n_features_to_select=1, step=1)
mapper = fit!(rfe, X, y)
# 最终的矩阵
#fit_transform!(mapper,X, y)
#这里毕竟处理的是图像,尝试画一下图吧
ranking = pynumpy.reshape(rfe.ranking_,pynumpy.shape(images[1,:,:]))
# Plot pixel ranking
PyPlot.matshow(ranking, cmap=PyPlot.cm.Blues)
PyPlot.colorbar()
PyPlot.title("Ranking of pixels with RFE")
PyPlot.show()
画图:
L1、L2这种在机器学习方面叫做正则化,统计学领域的人喊她惩罚项,数学界会喊她范数。范数(norm)是数学中的一种基本概念。在泛函分析中,它定义在赋范线性空间中,并满足一定的条件,即①非负性;②齐次性;③三角不等式。它常常被用来度量某个向量空间(或矩阵)中的每个向量的长度或大小。 L1就是曼哈顿距离 和 L2就是欧式距离
使用注意点:
分别使用L1和L2拟合,如果两个特征在L2中系数相接近,在L1中一个系数为0一个不为0,那么其实这两个特征都应该保留,原因是L1对于强相关特征只会保留一个, L2不能直接特征选择,只能约束系数大小。L1可以,因为L1 penalty是一个高维菱形,与最小二乘结合起来的损失函数最优解往往在菱形的边或顶点上,这时候就有系数为0
LinearSVC函数的参数说明如下:
# LinearSVC 线性拟合函数
# penalty : string, ‘l1’ or ‘l2’ (default=’l2’)指定惩罚中使用的规范。 'l2'惩罚是SVC中使用的标准。 'l1'导致稀疏的coef_向量。
# loss : string, ‘hinge’ or ‘squared_hinge’ (default=’squared_hinge’)指定损失函数。 “hinge”是标准的SVM损失(例如由SVC类使用),而“squared_hinge”是hinge损失的平方。
# dual : bool, (default=True)选择算法以解决双优化或原始优化问题。 当n_samples> n_features时,首选dual = False。
# tol : float, optional (default=1e-4)公差停止标准
# C : float, optional (default=1.0) 正则化参数。正则化的强度与C成反比。必须是严格正的。
# multi_class : string, ‘ovr’ or ‘crammer_singer’ (default=’ovr’)如果y包含两个以上的类,则确定多类策略。 “ovr”训练n_classes one-vs-rest分类器,而“crammer_singer”优化所有类的联合目标。 虽然crammer_singer在理论上是有趣的,因为它是一致的,但它在实践中很少使用,因为它很少能够提高准确性并且计算成本更高。 如果选择“crammer_singer”,则将忽略选项loss,penalty和dual。
# fit_intercept : boolean, optional (default=True)是否计算此模型的截距。 如果设置为false,则不会在计算中使用截距(即,预期数据已经居中)。
# intercept_scaling : float, optional (default=1) 当self.fit_intercept为True时,实例向量x变为[x,self.intercept_scaling],即具有等于intercept_scaling的常量值的“合成”特征被附加到实例向量。 截距变为intercept_scaling *合成特征权重注意! 合成特征权重与所有其他特征一样经受l1 / l2正则化。 为了减小正则化对合成特征权重(并因此对截距)的影响,必须增加intercept_scaling。
# class_weight : {dict, ‘balanced’}, optional将类i的参数C设置为SVC的class_weight [i] * C. 如果没有给出,所有课程都应该有一个重量。 “平衡”模式使用y的值自动调整与输入数据中的类频率成反比的权重,如n_samples /(n_classes * np.bincount(y))
# verbose : int, (default=0)启用详细输出。 请注意,此设置利用liblinear中的每进程运行时设置,如果启用,可能无法在多线程上下文中正常工作。
# random_state : int, RandomState instance or None, optional (default=None) 在随机数据混洗时使用的伪随机数生成器的种子。 如果是int,则random_state是随机数生成器使用的种子; 如果是RandomState实例,则random_state是随机数生成器; 如果为None,则随机数生成器是np.random使用的RandomState实例。
# max_iter : int, (default=1000) 要运行的最大迭代次数。
样例代码:
using LinearAlgebra
using DataFrames,CSV
using Statistics
using ScikitLearn
@sk_import feature_selection: SelectFromModel
@sk_import linear_model: LassoCV
@sk_import svm: LinearSVC
@sk_import datasets : load_iris
X, y = load_iris(return_X_y=true)
lsvc = LinearSVC(C=0.01, penalty="l1", dual=false)
model = SelectFromModel(lsvc, prefit=false)
fit_transform!(model, copy(X),y)
lsvc2 = LinearSVC(C=0.01, penalty="l2", dual=false)
model2 = SelectFromModel(lsvc2, prefit=false)
fit_transform!(model, copy(X),y)
待补充.......