欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

特征工程之特征选择

程序员文章站 2024-03-25 20:35:34
...

一、为什么要做特征选择?

如果一个模型在训练数据上的表现比在测试数据上要好很多,这就表示这个模型过拟合了。过拟合是指模型的参数对于训练数据的特定观测值拟合的非常接近,而训练数据的分布于真实数据的分布并不一致,所以模型具有较高的方差。产生过拟合的原因是因为,对于训练数据集上的模型过于复杂,通常我们可以通过以下几种方式来降低过拟合:

1、收集更多的训练数据

2、通过正则化引入罚项

3、选择一个参数相对较少的简单模型

4、降低数据的维度

特征选择除了防止模型过拟合降低模型的泛化误差之外,它还可以减少硬件资源的损耗,降低模型的开发成本,减少训练的时间。下面我们会介绍通过正则化、随机森林算法进行特征选择。

二、使用L1正则化进行特征选择

常用的正则化有L1正则化和L2正则化,L1正则化和L2正则化都是为代价函数添加罚项,不同的是L1正则化增加的罚项是使用权重绝对值的和而L2正则化增加的罚项时权重的平方和。L1正则化生成的是一个稀疏的特征向量,且大多数的权值为0。如果数据集中包含了许多不相关的特征,尤其是不相关的特征数量大于样本的数量时,通过L1正则化处理之后能降低模型的复杂度。

import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

if __name__ == "__main__":
    data = pd.read_csv("G:/dataset/wine.csv")
    #将data分为特征和类标
    x,y = data.ix[:,1:],data.ix[:,0]
    #对特征进行标准化处理
    std = StandardScaler()
    x_std = std.fit_transform(x)
    #将数据集分为训练集和测试集
    train_x,test_x,train_y,test_y = train_test_split(x_std,y,test_size=0.3,random_state=1)
    #使用L1正则化进行特征选择
    L1_model = LogisticRegression(penalty="l1",C=0.1)
    L1_model.fit(train_x,train_y)
    #判断模型在训练数据上的准确率
    print("training accuracy:",L1_model.score(train_x,train_y))
    #判断模型在测试数据上的准确率
    print("test accuracy:",L1_model.score(test_x,test_y))

特征工程之特征选择

通过模型在训练集和测试集上的准确率可以发现,模型没有产生过拟合,因为训练集和测试集的准确率差不多。

1、查看模型的截距
    #查看logistic模型的截距
    print(L1_model.intercept_)

特征工程之特征选择

2、查看模型的权重系数
    #查看模型的权重系数
    print(L1_model.coef_)

特征工程之特征选择

因为我们使用的是多类别分类的logistic回归,所以它使用一对多(one-vs-Rest,OvR)的方法。第一个权重表示类别1相对于类别2和3的匹配结果,第二个权重表示的是类别2相对于类别1和3的匹配结果,第三个权重表示的是类别3相对于类别1和2的匹配结果。可以发现每一个权重都有13数,其中有很多项的值都为0,这是因为通过L1正则化之后产生的,这13个数表示模型在13个权重上的比重,对应不为0的特征系数,表示是选择的特征。

3、获取L1正则化所选择的列名
    #获取特征的列名,因为第一列表示的酒的类别
    data_cols_name = data.columns[1:]
    #获取第一个特征的系数
    coef1 = L1_model.coef_[0]
    #获取一个特征系数的bool类型的数组,不为0为true
    coef1_bool = coef1 != 0
    print(data_cols_name[coef1_bool])
    #获取第二个特征的系数
    coef2 = L1_model.coef_[1]
    coef2_bool = coef2 != 0
    print(data_cols_name[coef2_bool])
    #获取第三个特征的系数
    coef3 = L1_model.coef_[2]
    coef3_bool = coef3 != 0
    print(data_cols_name[coef3_bool])

特征工程之特征选择

3、参数C对于L1正则化的影响
if __name__ == "__main__":
    data = pd.read_csv("G:/dataset/wine.csv")
    # 将data分为特征和类标
    x, y = data.ix[:, 1:], data.ix[:, 0]
    # 对特征进行标准化处理
    std = StandardScaler()
    x_std = std.fit_transform(x)
    # 将数据集分为训练集和测试集
    train_x, test_x, train_y, test_y = train_test_split(x_std, y, test_size=0.3, random_state=1)

    fig = plt.figure()
    ax = plt.figure(111)
    colors = ["blue","green","red","cyan",
              "magenta","yellow","black","pink",
              "lightgreen","lightblue","gray","indigo",
              "indigo","organge"]
    weights,params = [],[]
    for c in np.arange(-4,6):
        model = LogisticRegression(penalty="l1",C=float(10)**c,random_state=0)
        model.fit(train_x,train_y)
        weights.append(model.coef_[1])
        params.append(float(10)**c)
    weights = np.array(weights)
    for column,color in zip(range(weights.shape[1]),colors):
        plt.plot(params,weights[:,column],label=data.columns[column+1],color=color)
    plt.axhline(0,color="black",linestyle="--",linewidth=3)
    plt.xlim([10**(-5),10**5])
    plt.ylabel("weight coefficent")
    plt.xlabel("C")
    plt.xscale("log")
    plt.legend(loc="upper left")
    plt.show()

特征工程之特征选择

参数C是正则化参数特征工程之特征选择的倒数,,当C越小的时候,所有参数的权重都接近0。通过上面的图,我们可以发现特征与参数C的变化关系。

三、使用随机森林判断特征的重要性

使用随机森林来判断特征的重要性的时候,不需要考虑特征是否是线性可分的,也不需要对特征做归一化或者标准化处理。通过随机森林算法之后,可以知道每一个特征的重要性,特征的重要性之和为1。

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
import matplotlib.pyplot as plt
import numpy as np

if __name__ == "__main__":
    data = pd.read_csv("G:/dataset/wine.csv")
    #将data分为特征和类标
    x,y = data.ix[:,1:],data.ix[:,0]
    #将数据集分为训练集和测试集
    train_x,test_x,train_y,test_y = train_test_split(x,y,test_size=0.3,random_state=1)
    #定义一个由10000颗决策树组成的随机森林模型
    rf_model = RandomForestClassifier(n_estimators=10000,random_state=0,n_jobs=-1)
    #训练
    rf_model.fit(train_x,train_y)
    #获取特征的重要性
    importances = rf_model.feature_importances_
    #对特征的重要性进行排序
    indices = np.argsort(importances)[::-1]
    cols_name = data.columns[1:]
    for f in range(train_x.shape[1]):
        print("%2d) %-*s %f" % (f + 1,30,cols_name[f],importances[indices[f]]))
    plt.title("特征的重要性")
    plt.bar(range(train_x.shape[1]),importances[indices],color="lightblue",align="center")
    plt.xticks(range(train_x.shape[1]),cols_name,rotation=90)
    plt.xlim([-1,train_x.shape[1]])
    plt.show()

特征工程之特征选择

特征工程之特征选择