数据挖掘流程(三):特征工程

数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已

特征工程是利用数据领域的相关知识来创建能够使机器学习算法达到最佳性能的特征的过程。

特征工程流程:这些过程不是必须全部要有,需要根据业务需求和数据格式特点,适宜调整

    • 数据理解EDA
    • 特征清洗
    • 特征构造
    • 特征选择
    • 特征降维
    • 特征类别不平衡

目录

特征工程

1. 数据理解EDA

1.1 数据简略观测

1.2 数据统计

1.3 数据正态性检验

1.4 绘图

2. 特征清洗

2.1 特征分类不平衡

2.2 缺失值处理

2.3 异常值处理

2.4 数据转换

2.5 数据分桶

2.6 一人多次

3. 特征构造(特征生成)

4. 特征选择

4.1 Filter(过滤式),单变量特征选择

4.2 Wrapper(包装法)

4.3 Embedded(嵌入法)

5. 特征降维

5.1 PCA

5.2 LDA

6. 直接预测


特征工程

1. 数据理解EDA

这一步最重要的是形成分类变量名列表连续变量名列表。这样做的好处:

1)方便查看分类变量数据分布。分类变量正负样本比例全是1或95%是1的,没意义,可以删去;连续变量缺失率大于50%和数值分布范围

2)方便后面的相关性检测。分类变量用卡方检验;连续变量用t检验或方差分析。

1.1 数据简略观测

  • head()
  • shape
  • unique()、nunique()
  • 相关统计量。describe()
  • 数据类型。info()
  • pandas_profiling数据报告,不建议。因为在数据量大时,pandas_profiling生成的数据报告可能出错、生成的图较大较慢。

1.2 数据统计

print('----------------全体变量数据统计描述----------------------')
# 统计全变量体系各变量的平均数、上下四分位数、缺失率
feature_list=[]
mean_list=[]
up_quarter_list=[]
down_quarter_list=[]
miss_list=[]

for i in df_model.columns:
    data = df_model[i]
    stat_result = pd.DataFrame(data.describe())
    # print(stat_result)
    mean_value=stat_result.loc['mean',i]
    up_quarter=stat_result.loc['25%',i]
    down_quarter=stat_result.loc['75%',i]
    num=stat_result.loc['count',i]
    miss_rate=1-num/df_model.shape[0]
    miss_rate="%.2f%%" % (miss_rate * 100)      # 百分数输出

    feature_list.append(i)
    mean_list.append(round(mean_value,2))
    up_quarter_list.append(round(up_quarter,2))
    down_quarter_list.append(round(down_quarter,2))
    miss_list.append(miss_rate)

df_stat=pd.DataFrame({'特征':feature_list,'平均值':mean_list,'上四分位':up_quarter_list,'下四分位':down_quarter_list,'缺失率':miss_list})
df_stat=df_stat.reset_index(drop=True)

writer=pd.ExcelWriter(project_path+'/data/v2.0/df_全体变量数据统计.xlsx')
df_stat.to_excel(writer)
writer.save()

1.3 数据正态性检验

数据正态性检验,是为了方便相关性分析和显著性分析。当样本量巨大时,可以近似认为数据符合正态分布,不用做正态性检验。

  • SPSS。
    • P-P图/Q-Q图
    • k-s和s-w检验。
    • 直方图。Analysis--统计描述--频率
  • python。详见特征选择-相关性分析
  • 查看特征的偏度和峰度

1.4 绘图

  • 画出原始的数据
  • 画出他们的简单的统计特征(mean plots, box plots, residual plots)
  • 画出不同的数据间的相关性
    • 小提琴图。相当于进阶版箱线图,可以看出某个值附近分布的频率。
    • 直方图。便于观察数据分布
    • 箱线图。便于观察数据的异常情况,以及不同数据间的对比。
    • 时序图。便于观察数据特点,例如是否具有周期性、震荡幅度等

2. 特征清洗

2.1 特征分类不平衡

分类变量正负样本分类不平衡,少类别提供信息太少,没有学会如何判别少数类

  • 删除。分类变量正负样本比例全是1或95%是1的,没意义,可以删去
  • 重采样

过采样是针对minority样本,欠采样是针对majority样本;而综合采样是既对minority样本,又对majority样本,同时进行操作的方法

  • 过采样over-sampling。smote,adasyn,TabGan,CTGAN(github)
  • 欠采样under-sampling。cluster centrolds,Tomek's links,Edited Nearest Neighbours,AllKNN,Condensed Nearest Neighbour,MearMiss-1,2,3
    • 尝试其他评价指标。AUC
    • 调整θ值
    • 选择其他模型:决策树等;

例:

原始数据(Original):未经过任何采样处理(1831X21)每条数据有21个特征。其中正例176个(9.6122%),反例1655个(90.3878%)

欠采样(Undersampling):从反例中随机选择176个数据,与正例合并(352X21)

过采样(Oversampling):从正例中反复抽取并生成1655个数据(势必会重复),并与反例合并(3310X21)

SMOTE:也是一种过采样方法。SMOTE通过找到正例中数据的近邻,来合成新的1655-176=1479个“新正例”,并与原始数据合并(3310X21)

欠采样

from imblearn.under_sampling import TomekLinks
 
X_train = train_df.drop(['id', 'type'], axis=1)
y = train_df['label']
tl = TomekLinks()
X_us, y_us = tl.fit_sample(X_train, y)
print(X_us.groupby(['label']).size())
# label
# 0    36069
# 1     2757
 

SMOTE

from imblearn.over_sampling import SMOTE
smote = SMOTE(k_neighbors=5, random_state=42)
X_res, y_res = smote.fit_resample(X_train, y)
X_res.groupby(['label']).size()
# label
# 0    37243
# 1    37243

ADASYN

from imblearn.over_sampling import ADASYN 
adasyn = ADASYN(n_neighbors=5, random_state=42)
X_res, y_res = adasyn.fit_resample(X_train, y)
X_res.groupby(['label']).size()
 
# label
# 0    37243
# 1    36690

综合采样

from imblearn.combine import SMOTETomek
 
smote_tomek = SMOTETomek(random_state=0)
X_res, y_res = smote_tomek.fit_sample(X_train, y)
X_res.groupby(['label']).size()
# label
# 0    36260
# 1    36260

结果:

1)过采样(右上)只是单纯的重复了正例,因此会过分强调已有的正例。如果其中部分点标记错误或者是噪音,那么错误也容易被成倍的放大。因此最大的风险就是对正例过拟合

2)欠采样(左下)抛弃了大部分反例数据,从而弱化了中间部分反例的影响,可能会造成偏差很大的模型。当然,如果数据不平衡但两个类别基数都很大,或许影响不大。数据总是宝贵的,抛弃数据是很奢侈的,因此另一种常见的做法是反复做欠采样,生成1655/176=9

3)SMOTE(右下)可以看出和过采样(右上)有了明显的不同,因为不单纯是重复正例了,而是在局部区域通过K-近邻生成了新的正例。

2.2 缺失值处理

  • 删除。缺失率超过50%的变量删除
  • 传统方法。(均值、中位数)
  • 机器学习。(随机森林rf插补、xgboost)
# 使用随机森林对缺失值进行插补
import pandas as pd
pd.set_option('mode.chained_assignment', None)
import numpy as np
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import GridSearchCV
def missing_value_interpolation(df,missing_list=[]):
    df = df.reset_index(drop=True)
    # 提取存在缺失值的列名
    if not missing_list:
        for i in df.columns:
            if df[i].isnull().sum() > 0:
                missing_list.append(i)
    missing_list_copy = missing_list.copy()
    # 用该列未缺失的值训练随机森林,然后用训练好的rf预测缺失值
    for i in range(len(missing_list)):
        name=missing_list[0]
        df_missing = df[missing_list_copy]
        # 将其他列的缺失值用0表示。
        missing_list.remove(name)
        for j in missing_list:
            df_missing[j]=df_missing[j].astype('str').apply(lambda x: 0 if x=='nan' else x)
        df_missing_is = df_missing[df_missing[name].isnull()]
        df_missing_not = df_missing[df_missing[name].notnull()]
        y = df_missing_not[name]
        x = df_missing_not.drop([name],axis=1)
        # 列出参数列表
        tree_grid_parameter = {'n_estimators': list((10, 50, 100, 150, 200))}
        # 进行参数的搜索组合
        grid = GridSearchCV(RandomForestRegressor(),param_grid=tree_grid_parameter,cv=3)
        #rfr=RandomForestRegressor(random_state=0,n_estimators=100,n_jobs=-1)
        #根据已有数据去拟合随机森林模型
        grid.fit(x, y)
        rfr = RandomForestRegressor(n_estimators=grid.best_params_['n_estimators'])
        rfr.fit(x, y)
        #预测缺失值
        predict = rfr.predict(df_missing_is.drop([name],axis=1))
        #填补缺失值
        df.loc[df[name].isnull(),name] = predict
    return df

  • GAN。伪造数据、fake sample

2.3 异常值处理

  • 删除。箱线图分析删除异常值box-plot
# 过滤异常值,大于正常值超过100倍!
def filter_exce_value(df,feature):
    # 过滤文字!!!!!!!!!!!!!!!!!!!!!!!!!!!
    df=df[df[feature].str.contains('\d')]
    # 过滤异常大值!!!!!!!!!!!!!!!!!!!!!!!!!!
    median_value=df[feature].median()
    df[feature]=df[feature].apply(lambda x: x if abs(float(x)) < (100 * abs(median_value)) else np.nan)
    df=df[df[feature].notnull()]
    return df
  • 孤立森林
  • 长尾截断

2.4 数据转换

一般是用于连续变量不满足正态分布的时候

最重要的一点:如果对因变量进行数据转换,要记得对模型预测结果进行恢复

  • 正态纠偏(修复偏斜特征),box-cox转换

Box-Cox变换通过对因变量进行变换,使得变换过的向量与回归自变量具有线性相依关系,误差也服从正态分布.误差各分量是等方差且相互独立。Box-Cox变换兼顾了变量在时间序列维度上的回归特性,所以也可以用于时间序列方面的预测。

from scipy.stats import boxcox
boxcox_transformed_data = boxcox(original_data)

在一些情况下(P值正态化处理,所以优先使用BOX-COX转换,但是当P值>0.003时两种方法均可,优先考虑普通的平方变换

  • 其他非正态数据转换
    • 对数变换(log)
    • 平方根转换
    • 倒数转换
    • 平方根后取到数,平方根后再取反余弦,幂转换
for col in continuous_list:
    df_final_10_1[col] = df_final_10_1[col].apply(lambda x: np.log(x) if x > 0 else np.nan if x!=x else 0)

  • 中心化。把数据整体移动到以0为中心点的位置,将数据减去这个数据集的平均值
  • 标准化(Z-score)。(x-mean)/std
  • 归一化(Max-min)。(x-min)/(max-min)。从经验上说,归一化是让不同维度之间的特征在数值上有一定的比较性,可以大大提高分类器的准确性。
minmax = MinMaxScaler()
num_data_minmax = minmax.fit_transform(num_data)
num_data_minmax = pd.DataFrame(num_data_minmax, columns=num_data.columns, index=num_data.index)
  • 转换数据类型(astype)
  • 独热编码(one-hot Encoder)
"""类别特征某些需要独热编码一下"""
hot_features = ['bodyType', 'fuelType', 'gearbox', 'notRepairedDamage']
cat_data_hot = pd.get_dummies(cat_data, columns=hot_features)

  • 标签编码(Label Encoder)

2.5 数据分桶

医学数据挖掘里用处不大

  • 等频分桶
  • 等距分桶
  • Best-KS分桶
  • 卡方分桶

2.6 一人多次

3. 特征构造(特征生成)

在特征构造的时候,需要借助一些业务知识(比如医学中的BMI、肌酐转化率),遵循的一般原则就是需要发挥想象力,尽可能多的创造特征,不用先考虑哪些特征可能好,可能不好,先弥补这个广度。

医学数据挖掘一般不需要考虑数值、类别和时间特征

  • 数值特征
  • 类别特征
  • 时间特征

4. 特征选择

filter--主要对应单变量特征选择;wrapper--主要对应多个特征选择。

特征选择原因:对于一个特定的学习算法来说,哪一个特征是有效的是未知的。因此,需要从所有特征中选择出对于学习算法有益的相关特征。而且在实际应用中,经常会出现维度灾难问题。如果只选择所有特征中的部分特征构建模型,那么可以大大减少学习算法的运行时间,也可以增加模型的可解释性

特征选择原则:获取尽可能小的特征子集,不显著降低分类精度、不影响分类分布以及特征子集应具有稳定、适应性强等特点

4.1 Filter(过滤式),单变量特征选择

filter按照发散性或相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征。

优点:运行速度快,是一种非常流行的特征选择方法。

缺点:无法提供反馈,特征选择的标准/规范的制定是在特征搜索算法中完成,学习算法无法向特征搜索算法传递对特征的需求。另外,可能处理某个特征时由于任意原因表示该特征不重要,但是该特征与其他特征结合起来则可能变得很重要

  • 相关性检验。分别计算每个特征与输出值之间的相关系数,设定一个阈值,选择相关系数大于阈值的部分特征

https://note.youdao.com/s/9HR1GEQG

  • 显著性检验
    •  t检验
    • 卡方检验
    • 方差检验。
    • 非参数检验

https://note.youdao.com/s/aTVlqmDy

  • 互信息
  • Relief

独立样本t检验和Mann-Whitney U test

discrete_list = ['gender']
continuous_list = [x for x in df_model.columns if x not in discrete_list]
# 高低剂量组利伐沙班服药前后WBC显著性检验
from scipy.stats import kstest,shapiro
import scipy.stats as st
from scipy.stats import chi2_contingency
##检验是否正态
def norm_test(data):
    if len(data) > 30:
        norm, p = kstest(data, 'norm')
    else:
        norm, p = shapiro(data)
    #print(t,p)
    if p>=0.05:
        return True
    else:
        return False

def test2(data_b, data_p):
    if norm_test(data_b) and norm_test(data_p):
        x = 1
        y = '独立样本T检验'
        t, p = st.ttest_ind(list(data_b),list(data_p), nan_policy='omit')
    else:
        x = 0
        y = 'Mann-Whitney U检验'
        t,p = st.mannwhitneyu(list(data_b),list(data_p))
    return x,y,t,p
def sig_test(df_high,df_low,list):

    field_list=[]
    y_list=[]
    t_list=[]
    p_list=[]
    result_list=[]
    high_mean_list=[]
    low_mean_list=[]
    # high_num_list=[]
    # high_rate_list=[]
    # low_num_list=[]
    # low_rate_list=[]
    for i in range(len(list)):
        field=list[i]
        df_high_nt=df_high[df_high[field].notnull()]
        data_high=df_high_nt[field]
        high_mean=round(data_high.mean(),2)
        # high_num=df_high_nt.shape[0]
        # all_num=df_high.shape[0] + df_low.shape[0]
        # high_rate = "%.2f%%" % (round(high_num/all_num) * 100)
        df_low_nt=df_low[df_low[field].notnull()]
        data_low=df_low_nt[field]
        low_mean=round(data_low.mean(),2)
        # low_num=df_low_nt.shape[0]
        # low_rate="%.2f%%" % (round(low_num/all_num) * 100)
        if data_high.shape[0] >= 10 and data_low.shape[0]>=10:
            x,y,t,p = test2(data_high, data_low)
            if p <=0.05:
                sig='显著'
            else:
                sig='不显著'
            field_list.append(field)
            y_list.append(y)
            t_list.append(t)
            p_list.append(p)
            result_list.append(sig)
            high_mean_list.append(high_mean)
            low_mean_list.append(low_mean)
    df_result=pd.DataFrame({'特征':field_list,
                            '高剂量均值':high_mean_list,
                            '低剂量均值':low_mean_list,
                            '检验指标':y_list,
                            't值':t_list,
                            'p值':p_list,
                            '显著性结果':result_list})
    return df_result
# 住院时长到用药时长的显著性检验
df_inp_time=sig_test(df_lfsb_high,df_lfsb_low,['住院时长'])
df_inp_time=df_inp_time.reset_index(drop=True)

writer=pd.ExcelWriter(project_path+r'/data/result/df_高低剂量组住院时长显著性检验.xlsx')
df_inp_time.to_excel(writer)
writer.save()

卡方检验

## 卡方检验
print('----------------------卡方检验-------------------------')
from scipy.stats import chi2_contingency

r1 = []
r2 = []
tran_test['MPA类药物'] = tran_test['MPA类药物'].astype('str')
for i in range(len(np.unique(tran_test['MPA类药物']))):
    r1.append(
        tran_test[(tran_test['group'] == 0) & (tran_test['MPA类药物'] == np.unique(tran_test['MPA类药物'])[i])].shape[0])
    r2.append(
        tran_test[(tran_test['group'] == 1) & (tran_test['MPA类药物'] == np.unique(tran_test['MPA类药物'])[i])].shape[0])

abcd = np.array([r1, r2])
print(abcd)
result = chi2_contingency(abcd)
print(result)

tran_x_1 = tran_x_1.drop(['group'], axis=1)
test_x_1 = test_x_1.drop(['group'], axis=1)

print(tran_x_1.columns)

pearsonr检验

from scipy import stats
r, p = stats.pearsonr(x,y)

spearmanr检验

#  连续变量,spearmanr相关性检验(统计量r);
print('--------------------------计算连续变量的spearmanr相关性系数---------------------------------')
from scipy import stats
t_list = []
p_list = []
q_list = []

for i in continuous_list:
    # 删除连续变量中的<、>号
    tdm_7_other_filter[i] = tdm_7_other_filter[i].astype('str').apply(lambda x: re.sub(r'<|>', '',x))
    x= tdm_7_other_filter[tdm_7_other_filter[i].astype('float').notnull()][i]
    y= tdm_7_other_filter[tdm_7_other_filter[i].astype('float').notnull()]['test_result']
    t, p = stats.spearmanr(x,y)
    t = round(t, 2)
    p = round(p, 3)
    q = '斯皮尔曼'
    # print(i, t, p)

    t_list.append(t)
    p_list.append(p)
    q_list.append(q)
df_spearmanr= pd.DataFrame(data={'连续检测指标': continuous_list,
                                't值': t_list,
                                'p值': p_list,
                                '方法': q_list})
df_spearmanr_1 = df_spearmanr[df_spearmanr['p值'] <= 0.05]
df_spearmanr_2 = df_spearmanr[df_spearmanr['p值'] >= 0.05]  # 显著性不成立
df_spearmanr = pd.concat([df_spearmanr_1,df_spearmanr_2], axis=0)

df_spearmanr=df_spearmanr.sort_values(by=['p值'],ascending=True)
df_spearmanr = df_spearmanr.reset_index()
del df_spearmanr['index']

writer = pd.ExcelWriter(project_path + '/result/df_12_其他检测指标连续变量的spearmanr相关性检测.xlsx')
df_spearmanr.to_excel(writer)
writer.save()

4.2 Wrapper(包装法)

根据目标函数(通常是预测效果评分)作为评价函数,每次选择若干特征,排除若干特征。

主要方法:递归特征消除算法。

优点:对特征进行搜索时围绕学习算法展开的,对特征选择的标准/规范是在学习算法的需求中展开的,能够考虑学习算法所属的任意学习偏差,从而确定最佳子特征,真正关注的是学习问题本身。由于每次尝试针对特定子集时必须运行学习算法,所以能够关注到学习算法的学习偏差/归纳偏差,因此封装能够发挥巨大的作用。

缺点:运行速度远慢于过滤算法,实际应用用封装方法没有过滤方法流行。

  • 逐步向前(Forward stepwise)
# 判断文件路径是否存在,如果不存在则创建该路径
def mkdir(path):
    folder = os.path.exists(path)
    if not folder:  # 判断是否存在文件夹如果不存在则创建为文件夹
        os.makedirs(path)  # makedirs 创建文件时如果路径不存在会创建这个路径

df = pd.read_excel(project_path+'/data/v2.0/建模用数据集(未插补)20210525-3.xlsx')
if 'Unnamed: 0' in df.columns:
    df = df.drop(['Unnamed: 0'], axis=1)
continuous_list = [
  '年龄', '身高(cm)', '体重(kg)', 'BMI', '他克莫司频次', '他克莫司单次剂量', '他克莫司日剂量',
  'C反应蛋白_检测结果', '丙氨酸氨基转移酶_检测结果', '中性粒细胞总数_检测结果', '低密度脂蛋白胆固醇_检测结果',
  '凝血酶原时间比率_检测结果', '天门冬氨酸氨基转移酶_检测结果', '尿素_检测结果', '尿酸_检测结果',
  '平均RBC血红蛋白浓度_检测结果', '平均红细胞体积_检测结果', '平均红细胞血红蛋白量_检测结果', '平均血小板容积_检测结果',
  '总胆固醇_检测结果', '总胆红素_检测结果', '总蛋白_检测结果', '极低密度脂蛋白胆固醇_检测结果', '活化部分凝血活酶时间_检测结果',
  '淋巴细胞总数_检测结果', '球蛋白_检测结果', '甘油三酯_检测结果', '白/球比值_检测结果', '白细胞计数_检测结果',
  '白蛋白_检测结果', '直接胆红素_检测结果', '红细胞比积测定_检测结果', '肌酐_检测结果', '葡萄糖_检测结果',
  '血小板计数_检测结果', '血浆D-二聚体测定_检测结果', '血红蛋白测定_检测结果', '转氨酶比值_检测结果', '间接胆红素_检测结果',
  '非高密度脂蛋白胆固醇_检测结果', '高密度脂蛋白胆固醇_检测结果', '乳酸脱氢酶_检测结果', '心型肌酸激酶_检测结果',
  '肌酸激酶_检测结果', '尿白细胞(仪器定量)_检测结果', '尿红细胞(仪器定量)_检测结果', 'TDM检测结果'
]
#连续变量取log
df_final_10_1 = df.copy()
#df_final_11_1 = df_final_11.copy()
for col in continuous_list:
    df_final_10_1[col] = df_final_10_1[col].apply(lambda x: np.log(x) if x > 0 else np.nan if x!=x else 0)
def model_xy(model):
    x = model[model.columns[2:-1]]
    y = model['TDM检测结果']
    return x, y
col=['身高(cm)', '他克莫司日剂量', '其他免疫抑制剂', '低密度脂蛋白胆固醇_检测结果', '平均红细胞体积_检测结果', '平均红细胞血红蛋白量_检测结果',
     '白细胞计数_检测结果', '直接胆红素_检测结果', '红细胞比积测定_检测结果']
df_model_4 = df_final_10_1.copy()
x4, y4 = model_xy(df_model_4)
all_all_results = []
for j in range(1,52):
    for xy in [[x4, y4]]:
        train_x, test_x, train_y, test_y = train_test_split(xy[0],xy[1],test_size=0.2,random_state=78)
    # 津源xgboost模型
    sfs = SFS(xgb.XGBRegressor(max_depth=5,
                              learning_rate=0.01,
                              n_estimators=500,
                              min_child_weight=0.5,
                              eta=0.1,
                              gamma=0.5,
                              reg_lambda=10,
                              subsample=0.5,
                              colsample_bytree=0.8,
                              nthread=4,
                              scale_pos_weight=1),
             k_features=j,
             forward=True,
             floating=False,
             verbose=2,
             scoring='r2',
             cv=3)

    sfs = sfs.fit(train_x, train_y)
    # 逐步向前筛选结果,包括特征个数,最优特征组合及其r2
    sfs_result = sfs.subsets_
    print(sfs_result)
    df_sfs = pd.DataFrame(sfs_result)
    # DataFrame转置
    df_sfs_T=pd.DataFrame(df_sfs.values.T,index=df_sfs.columns,columns=df_sfs.index)
    df_sfs_T=df_sfs_T.reset_index(drop=True)
    # 保存逐步向前筛选结果
    r2_list=list(df_sfs_T['avg_score'])
    feature_list=list(df_sfs_T['feature_names'])

    # 根据逐步向前测试结果筛选最优特征组合
    r2_max=max(r2_list)
    print(r2_max)
    r2_max_index=r2_list.index(r2_max)
    df_feature_select=df_sfs_T.iloc[r2_max_index:r2_max_index+1,:]
    all_all_results.append(df_feature_select)
df_feature_select=all_all_results[0]
for j in range(1,len(all_all_results)):
    df_feature_select=pd.concat([df_feature_select,all_all_results[j]],axis=0)
df_feature_select=df_feature_select.reset_index(drop=True)
# 保存模型测试和测试结果到本地文件
writer = pd.ExcelWriter(project_path + '/data/v2.0/df_逐步向前特征测试结果.xlsx')
df_feature_select.to_excel(writer)
writer.save()

  • 逐步向后(Backward stepwise)

4.3 Embedded(嵌入法)

用model进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。

特征选择完成后,还能基于特征选择完成的特征和模型训练出的超参数,再次训练优化。

主要思想:在模型既定的情况下学习出对提高模型准确性最好的特征。也就是在确定模型的过程中,挑选出那些对模型的训练有重要意义的特征。

# 重要性评分
import catboost,xgboost
model_boost=xgboost.XGBRegressor()
model_boost.fit(tran_x,tran_y)
importance = model_boost.feature_importances_
print(tran_x.columns)
print(importance)

df_importance= pd.DataFrame(data={'特征':tran_x.columns,'重要性评分':importance})
df_importance['重要性评分']=df_importance['重要性评分'].apply(lambda x: round(x,3))
df_importance=df_importance.sort_values(['重要性评分'],ascending=False)
df_importance=df_importance.reset_index(drop=True)
writer = pd.ExcelWriter(project_path + '/result/df_19_模型重要性评分.xlsx')
df_importance.to_excel(writer)
writer.save()
  • L1正则化/Lasso regression

L1正则化将系数w的l1范数作为惩罚项加到损失函数上。Lasso能够挑出一些优质特征,同时让其他特征的系数趋于0。当如需要减少特征数的时候它很有用,但是对于数据理解来说不是很好用。

  • L2正则化/Ridge regression

L2正则化对于特征选择来说一种稳定的模型,不像L1正则化那样,系数会因为细微的数据变化而波动。所以L2正则化和L1正则化提供的价值是不同的,L2正则化对于特征理解来说更加有用:表示能力强的特征对应的系数是非零。

5. 特征降维

5.1 PCA

5.2 LDA

6. 直接预测

boosting体系用于基因分析挖掘

SVM体系(kernel函数进行更改),适用于缺失值和异常值存在的情况

DeepLearning,aml-net,tabnet,TabTransformer

  • 不均衡:loss入手,focal loss,teacher-student-network(多网络互学习)
  • 不均衡+小样本:GAN体系,对比学习体系(学习特征的表征向量+下游任务预测)
  • 小样本:建议使用传统机器学习,svm优先(稳定性强);加了正则化的线性模型(L1正则--Lasso回归,L2正则--Ridge回归-->导致的问题是泛化,正则是学习的时候尽量不要给它强规则,而重点学习数据分布和推理逻辑,有一定的降维效果)

你可能感兴趣的:(数据挖掘,数据挖掘,特征工程)