一、归一化

### --- 归一化

~~~ # 距离类模型归一化的要求
~~~ 什么是归一化?我们把 X 放到数据框中来看一眼,你是否观察到,每个特征的均值差异很大?
~~~ 有的特征数值很大,有的特征数值很小,这种现象在机器学习中被称为"量纲不统一"。
~~~ KNN 是距离类模型,欧氏距离的计算公式中存在着特征上的平方和:

|NO.Z.00004|——————————|BigDataEnd|——|Arithmetic&Machine.v04|——|Machine:监督学习算法.v03|_归一化

~~~     如果某个特征xi的取值非常大,其他特征的取值和它比起来就不算什么,
~~~ 那么距离的大小很大程度都会由这个xi来决定,
~~~ 其他的特征之间的距离可能就无法对d(A,B)的大小产生什么影响,
~~~ 这种现象会让KNN这样的距离类模型的效果大打折扣。
~~~ 然而在实际分析情景当中,绝大多数数据集都会存在各特征值量纲不同的情况,
~~~ 此时若要使用 KNN 分类器,则需要先对数据集进行归一化处理,即是将所有的数据压缩都同一个范围内。
~~~ 当数据(x)按照最小值中心化后,再按极差(最大值-最小值)缩放,数据移动了最小值个单位,
~~~ 并且会被收敛到[0,1]之间,而这个过程,就称作数据归一化(Normalization,又称 Min-Max Scaling)。

|NO.Z.00004|——————————|BigDataEnd|——|Arithmetic&Machine.v04|——|Machine:监督学习算法.v03|_最小值_02

### --- 先分数据集,再做归一化

~~~ 直接在全数据集 X 上进行了归一化,然后放入交叉验证绘制学习曲线,这种做法是错误的。
~~~ 真正正确的方式是,先分训练集和测试集,再归一化!
~~~ 为什么?想想看归一化的处理手段,我们是使用数据中的最小值和极差在对数据进行压缩处理,
~~~ 如果我们在全数据集上进行归一化,那最小值和极差的选取是会参考测试集中的数据的状况的。
~~~ 因此,当我们归一化后,无论我们如何分割数据,都会由一部分测试集的信息被“泄露”给训练集,
~~~ 这会使得我们的模型效果被高估。
~~~ 在现实业务中,我们只知道训练集的数据,不了解测试集究竟会长什么样,
~~~ 所以我们要利用训练集上的最小值和极差来归一化测试集。
### --- 通过 python 实现

data = [[-1,2],[-0.5,6],[0,10],[1,18]]
data=pd.DataFrame(data)
(data-np.min(data,axis=0))/(np.max(data,axis=0)-np.min(data,axis=0))

|NO.Z.00004|——————————|BigDataEnd|——|Arithmetic&Machine.v04|——|Machine:监督学习算法.v03|_最小值_03

### --- 通过 sklearn 实现

from sklearn.preprocessing import MinMaxScaler as mms
Xtrain,Xtest,Ytrain,Ytest=train_test_split(X,y,test_size=0.2,random_state=420)
#归一化
MMS_01=mms().fit(Xtrain) #求训练集最大/小值
MMS_02=mms().fit(Xtest) #求测试集最大/小值
#转换
X_train=MMS_01.transform(Xtrain)
X_test =MMS_02.transform(Xtest)
score=[]
var=[]
for i in range(1,20):
clf=KNeighborsClassifier(n_neighbors=i)
cvresult=CVS(clf,X_train,Ytrain,cv=5) # 交叉验证的每次得分
score.append(cvresult.mean())
var.append(cvresult.var())
plt.plot(krange,score,color="k")
plt.plot(krange,np.array(score)+np.array(var)*2,c="red",linestyle="--")
plt.plot(krange,np.array(score)-np.array(var)*2,c="red",linestyle="--")
plt.show()

|NO.Z.00004|——————————|BigDataEnd|——|Arithmetic&Machine.v04|——|Machine:监督学习算法.v03|_数据_04

score.index(max(score))+1

~~~ # 输出参数
8
~~~     最终的到 k 最优值为 8,无论 random_state 取什么值,最优 k 值不会相差太多。
~~~ 把经过交叉验证、归一化处理之后,我们得到最优 k 为 8,
~~~ 放在归一化后的训练集重新建模,然后在归一化后的测试集中查看结果分数:
clf=KNeighborsClassifier(n_neighbors=6,weights='distance').fit(X_train,Ytrain)
score=clf.score(X_test,Ytest)
score

~~~ # 输出参数
0.956140350877193

二、距离的惩罚

### --- 距离的惩罚

~~~ 最近邻点距离远近修正在对未知分类过程中, “一点一票” 的规则是 KNN 模型优化的一个重要步骤。
~~~ 也就是说,对于原始分类模型而言,在选取最近的 k 个元素之后,将参考这些点的所属类别,
~~~ 并对其进行简单计数,而在计数的过程中这些点 “一点一票” ,
~~~ 这些点每个点对分类目标点的分类过程中影响效力相同。
~~~ 但这实际上是不公平的,就算是最近邻的 k 个点,每个点的分类目标点的距离仍然有远近之别,
~~~ 而近的点往往和目标分类点有更大的可能性属于同一类别( 该假设也是 KNN 分类模型的基本假设) 。
~~~ 关于惩罚因子的选取有很多种方法, 最常用的就是根据每个最近邻 ????= 距离的不同对其作加权,
~~~ 加权方法为设置wi 权重,该权重计算公式为

|NO.Z.00004|——————————|BigDataEnd|——|Arithmetic&Machine.v04|——|Machine:监督学习算法.v03|_归一化_05

~~~     这里需要注意的是,关于模型的优化方法只是在理论上而言进行优化会提升模型判别效力,
~~~ 但实际应用过程中最终能否发挥作用,本质上还是取决于优化方法和实际数据情况的契合程度,
~~~ 如果数据本身存在大 量异常值点,则采用距离远近作为惩罚因子则会有较好的效果,反之则不然。
~~~ 因此在实际我们进行模型优化的过程当中,是否起到优化效果还是要以最终模型运行结果为准。
~~~ 在sklearn中,我们可以通过参数 weights 来控制是否适用距离作为惩罚因子。

for i in range(1,20):
clf=KNeighborsClassifier(n_neighbors=i,weights='distance')
cvresult=CVS(clf,X_train,Ytrain,cv=5) # 交叉验证的每次得分
score.append(cvresult.mean())
var.append(cvresult.var())
plt.plot(krange,score,color="k")
plt.plot(krange,np.array(score)+np.array(var)*2,c="red",linestyle="--")
plt.plot(krange,np.array(score)-np.array(var)*2,c="red",linestyle="--")
plt.show()

|NO.Z.00004|——————————|BigDataEnd|——|Arithmetic&Machine.v04|——|Machine:监督学习算法.v03|_最小值_06

score.index(max(score))+1

~~~ # 输出参数
6
clf=KNeighborsClassifier(n_neighbors=6,weights='distance').fit(X_train,Ytrain)
score=clf.score(X_test,Ytest)
score

~~~ # 输出参数
0.9473684210526315

Walter Savage Landor:strove with none,for none was worth my strife.Nature I loved and, next to Nature, Art:I warm'd both hands before the fire of life.It sinks, and I am ready to depart

                                                                                                                                                   ——W.S.Landor