精华内容
下载资源
问答
  • 2019-01-26 10:05:00

    我们可以将一连串的时间特征进行拆分,比如:2015-03-08 10:30:00.360000+00:00, 我们可以将其转换为日期类型,然后从里面提取年,月,日等时间信息

    对于一些hour,month等信息,我们也可以使用pd.cut将hour信息按照时刻转换为离散数据,如morning,afternonn等等

    代码:

    第一步:载入数据

    第二步:将数据转换为DataFrame格式

    第三步:使用pd.Timestamp将字符串格式转换为时间格式

    第四步:使用.apply提取时间格式中的各个属性特征

    第五步:提取与时刻相关的属性

    第六步:使用pd.cut对hour特征进行切分,转换为离散特征

    第七步:使用LabelEncoder对离散数据进行数字编码

    import pandas as pd
    
    # 第一步:构造DataFrame数据
    time_stamps = ['2015-03-08 10:30:00.360000+00:00', '2017-07-13 15:45:05.755000-07:00',
                   '2012-01-20 22:30:00.254000+05:30', '2016-12-25 00:30:00.000000+10:00']
    
    # 第二步: 将time_stamps转换为DataFrame格式
    time_pd = pd.DataFrame(time_stamps, columns=['Times'])
    
    # 第三步: 使用pd.Timestamp 将字符串类型转换为日期格式
    time_pd['stamp'] = [pd.Timestamp(time) for time in time_pd['Times'].values]
    # print(time_pd[['stamp', 'Times']])

                                        字符串时间日期化,从外表看两者并没有区别

    # 第四步:使用.apply对每一个数据提取属性, lambda表示输入是x,返回是x.year
    time_pd['year'] = time_pd['stamp'].apply(lambda x: x.year)
    time_pd['month'] = time_pd['stamp'].apply(lambda x: x.month)
    time_pd['day'] = time_pd['stamp'].apply(lambda x: x.day)
    time_pd['DayOfWeek'] = time_pd['stamp'].apply(lambda d: d.dayofweek)
    time_pd['DayName'] = time_pd['stamp'].apply(lambda d: d.weekday_name)
    time_pd['DayOfYear'] = time_pd['stamp'].apply(lambda d: d.dayofyear)
    time_pd['WeekOfYear'] = time_pd['stamp'].apply(lambda d: d.weekofyear)
    time_pd['Quarter'] = time_pd['stamp'].apply(lambda d: d.quarter)
    
    # 第五步: 提取与时刻有关的特征
    time_pd['Hour'] = time_pd['stamp'].apply(lambda d: d.hour)
    time_pd['Minute'] = time_pd['stamp'].apply(lambda d: d.minute)
    time_pd['Second'] = time_pd['stamp'].apply(lambda d: d.second)
    time_pd['MUsecond'] = time_pd['stamp'].apply(lambda d: d.microsecond)   #毫秒
    time_pd['UTC_offset'] = time_pd['stamp'].apply(lambda d: d.utcoffset())
    
    # 第六步:使用pd.cut将hour的数据进行切分,分成几个过程
    cut_hour = [-1, 5, 11, 16, 21, 23]
    cut_labels = ['last night', 'morning', 'afternoon', 'evening', 'Night']
    time_pd['Hour_cut'] = pd.cut(time_pd['Hour'], bins=cut_hour, labels=cut_labels)
    print(time_pd['Hour_cut'].head())

         hour数据转换为离散的数据格式

    # 第七步:使用LabelEncoder对标签进行数值转换
    from sklearn.preprocessing import LabelEncoder
    
    La = LabelEncoder()
    time_pd['Hour_number'] = La.fit_transform(time_pd['Hour_cut'])
    label_dict = {classes: number for number, classes in enumerate(La.classes_)}
    print(time_pd[['Hour_cut', 'Hour_number']])
    print(label_dict)

                      离散特征转换为数字映射

     

    转载于:https://www.cnblogs.com/my-love-is-python/p/10322671.html

    更多相关内容
  • 本篇内容给大家详细讲解了特征工程的知识,包括数据清洗(数据对齐、缺失值处理、异常值处理),特征构建,特征变换,特征选择与实战特征工程经验等内容。

    作者:韩信子@ShowMeAI
    教程地址http://www.showmeai.tech/tutorials/41
    本文地址http://www.showmeai.tech/article-detail/208
    声明:版权所有,转载请联系平台与作者并注明出处
    收藏ShowMeAI查看更多精彩内容

    引言

    机器学习; 数据处理与特征工程; 引言–特征工程; 8-1

    上图为大家熟悉的机器学习建模流程图,ShowMeAI在前序机器学习实战文章 Python机器学习算法应用实践中和大家讲到了整个建模流程非常重要的一步,是对于数据的预处理和特征工程,它很大程度决定了最后建模效果的好坏,在本篇内容汇总,我们给大家展开对数据预处理和特征工程的实战应用细节做一个全面的解读。

    特征工程

    首先我们来了解一下「特征工程」,事实上大家在ShowMeAI的实战系列文章 Python机器学习综合项目-电商销量预估Python机器学习综合项目-电商销量预估<进阶> 中已经看到了我们做了特征工程的处理。

    如果我们对特征工程(feature engineering)做一个定义,那它指的是:利用领域知识和现有数据,创造出新的特征,用于机器学习算法;可以手动(manual)或自动(automated)。

    • 特征:数据中抽取出来的对结果预测有用的信息。
    • 特征工程:使用专业背景知识和技巧处理数据,使得特征能在机器学习算法上发挥更好的作用的过程。

    在业界有一个很流行的说法:

    数据与特征工程决定了模型的上限,改进算法只不过是逼近这个上限而已。

    机器学习; 数据处理与特征工程; 引言–特征工程; 特征工程的定义; 8-2

    这是因为,在数据建模上,「理想状态」和「真实场景」是有差别的,很多时候原始数据并不是规矩干净含义明确充分的形态:

    机器学习; 数据处理与特征工程; 引言 -特征工程; 特征工程的意义; 8-3

    而特征工程处理,相当于对数据做一个梳理,结合业务提取有意义的信息,以干净整齐地形态进行组织:

    机器学习; 数据处理与特征工程; 引言 -特征工程; 特征工程的意义; 8-4

    特征工程有着非常重要的意义:

    • 特征越好,灵活性越强。只要特征选得好,即使是一般的模型(或算法)也能获得很好的性能,好特征的灵活性在于它允许你选择不复杂的模型,同时运行速度也更快,也更容易理解和维护。
    • 特征越好,构建的模型越简单。有了好的特征,即便你的参数不是最优的,你的模型性能也能仍然会表现的很好,所以你就不需要花太多的时间去寻找最优参数,这大大的降低了模型的复杂度,使模型趋于简单。
    • 特征越好,模型的性能越出色。显然,这一点是毫无争议的,我们进行特征工程的最终目的就是提升模型的性能。

    本篇内容,ShowMeAI带大家一起来系统学习一下特征工程,包括「特征类型」「数据清洗」「特征构建」「特征变换」「特征选择」等板块内容。


    我们这里用最简单和常用的Titanic数据集给大家讲解。

    Titanic数据集是非常适合数据科学和机器学习新手入门练习的数据集,数据集为1912年泰坦尼克号沉船事件中一些船员的个人信息以及存活状况。我们可以根据数据集训练出合适的模型并预测新数据(测试集)中的存活状况。

    Titanic数据集可以通过 seaborn 工具库直接加载,如下代码所示:

    import pandas as pd
    import numpy as np
    import seaborn as sns
    df_titanic = sns.load_dataset('titanic')
    

    其中数据集的数据字段描述如下图所示:

    机器学习; 数据处理与特征工程; 引言 -特征工程; Titanic数据集介绍; 8-5

    1.特征类型

    在具体演示Titanic的数据预处理与特征工程之前,ShowMeAI再给大家构建一些关于数据的基础知识。

    1.1 结构化 vs 非结构化数据

    数据可以分为「结构化数据」和「非结构化数据」,比如在互联网领域,大部分存储在数据库内的表格态业务数据,都是结构化数据;而文本、语音、图像视频等就属于非结构化数据。

    机器学习; 数据处理与特征工程; 特征类型; 结构化 V.S. 非结构化; 8-6

    1.2 定量 vs 定性数据

    对于我们记录到的数据,我们通常又可以以「定量数据」和「定性数据」对齐进行区分,其中:

    • 定量数据:指的是一些数值,用于衡量数量与大小。
      • 例如高度,长度,体积,面积,湿度,温度等测量值。
    • 定性数据:指的是一些类别,用于描述物品性质。
      • 例如纹理,味道,气味,颜色等。

    机器学习; 数据处理与特征工程; 特征类型; 定量 V.S. 定性; 8-7

    如下图是两类数据示例以及它们常见的处理分析方法的总结:

    机器学习; 数据处理与特征工程; 特征类型; 定量 V.S. 定性; 8-8

    2.数据清洗

    实际数据挖掘或者建模之前,我们会有「数据预处理」环节,对原始态的数据进行数据清洗等操作处理。因为现实世界中数据大体上都是不完整、不一致的「脏数据」,无法直接进行数据挖掘,或者挖掘结果差强人意。

    脏数据产生的主要成因包括

    • 篡改数据
    • 数据不完整
    • 数据不一致
    • 数据重复
    • 异常数据

    数据清洗过程包括数据对齐、缺失值处理、异常值处理、数据转化等数据处理方法,如下图所示:

    机器学习; 数据处理与特征工程; 数据清洗; 8-9

    下面我们注意对上述提到的处理方法做一个讲解。

    2.1 数据对齐

    采集到的原始数据,格式形态不一,我们会对时间、字段以及相关量纲等进行数据对齐处理,数据对齐和规整化之后的数据整齐一致,更加适合建模。如下图为一些处理示例:

    机器学习; 数据处理与特征工程; 数据清洗; 数据对齐; 8-10

    (1) 时间

    • 日期格式不一致【2022-02-20202202202022/02/2020/02/2022】。
    • 时间戳单位不一致,有的用秒表示,有的用毫秒表示。
    • 使用无效时间表示,时间戳使用0表示,结束时间戳使用FFFF表示。

    (2) 字段

    • 姓名写了性别,身份证号写了手机号等。

    (3) 量纲

    • 数值类型统一【如1、2.0、3.21E3、四】。
    • 单位统一【如180cm、1.80m】。

    2.2 缺失值处理

    数据缺失是真实数据中常见的问题,因为种种原因我们采集到的数据并不一定是完整的,我们有一些缺失值的常见处理方式:

    • 不处理(部分模型如XGBoost/LightGBM等可以处理缺失值)。
    • 删除缺失数据(按照样本维度或者字段维度)。
    • 采用均值、中位数、众数、同类均值或预估值填充。

    具体的处理方式可以展开成下图:

    机器学习; 数据处理与特征工程; 数据清洗; 缺失值处理; 8-11

    下面回到我们的Titanic数据集,我们演示一下各种方法:


    我们先对数据集的缺失值情况做一个了解(汇总分布):

    df_titanic.isnull().sum()
    
    survived         0
    pclass           0
    sex              0
    age            177
    sibsp            0
    parch            0
    fare             0
    embarked         2
    class            0
    who              0
    adult_male       0
    deck           688
    embark_town      2
    alive            0
    alone            0
    

    (1) 删除

    最直接粗暴的处理是剔除缺失值,即将存在遗漏信息属性值的对象 (字段,样本/记录) 删除,从而得到一个完备的信息表。优缺点如下:

    • 优点:简单易行,在对象有多个属性缺失值、被删除的含缺失值的对象与初始数据集的数据量相比非常小的情况下有效;
    • 不足:当缺失数据所占比例较大,特别当遗漏数据非随机分布时,这种方法可能导致数据发生偏离,从而引出错误的结论。

    在我们当前Titanic的案例中,embark_town字段有 2 个空值,考虑删除缺失处理下。

    df_titanic[df_titanic["embark_town"].isnull()]
    df_titanic.dropna(axis=0,how='any',subset=['embark_town'],inplace=True)
    

    机器学习; 数据处理与特征工程; 数据清洗; 缺失值处理; 8-12

    (2) 数据填充

    第2大类是我们可以通过一些方法去填充缺失值。比如基于统计方法、模型方法、结合业务的方法等进行填充。

    机器学习; 数据处理与特征工程; 数据清洗; 缺失值处理; 8-13

    ① 手动填充

    根据业务知识来进行人工手动填充。

    ② 特殊值填充

    将空值作为一种特殊的属性值来处理,它不同于其他的任何属性值。如所有的空值都用unknown填充。一般作为临时填充或中间过程。

    代码实现

    df_titanic['embark_town'].fillna('unknown', inplace=True)
    

    ③ 统计量填充

    若缺失率较低,可以根据数据分布的情况进行填充。常用填充统计量如下:

    • 中位数:对于数据存在倾斜分布的情况,采用中位数填补缺失值。
    • 众数:离散特征可使用众数进行填充缺失值。
    • 平均值:对于数据符合均匀分布,用该变量的均值填补缺失值。

    中位数填充——fare:缺失值较多,使用中位数填充

    机器学习; 数据处理与特征工程; 数据清洗; 缺失值处理; 8-14

    df_titanic['fare'].fillna(df_titanic['fare'].median(), inplace=True) 
    

    众数填充——embarked:只有两个缺失值,使用众数填充

    df_titanic['embarked'].isnull().sum()
    #执行结果:2
    df_titanic['embarked'].fillna(df_titanic['embarked'].mode(), inplace=True)
    df_titanic['embarked'].value_counts()
    #执行结果:
    #S    64
    

    同类均值填充

    age:根据 sex、pclass 和 who 分组,如果落在相同的组别里,就用这个组别的均值或中位数填充。

    df_titanic.groupby(['sex', 'pclass', 'who'])['age'].mean()
    
    age_group_mean = df_titanic.groupby(['sex', 'pclass', 'who'])['age'].mean().reset_index()
    
    def select_group_age_median(row):
        condition = ((row['sex'] == age_group_mean['sex']) &
                    (row['pclass'] == age_group_mean['pclass']) &
                    (row['who'] == age_group_mean['who']))
        return age_group_mean[condition]['age'].values[0]
    
    df_titanic['age'] =df_titanic.apply(lambda x: select_group_age_median(x) if np.isnan(x['age']) else x['age'],axis=1)
    

    机器学习; 数据处理与特征工程; 数据清洗; 缺失值处理; 8-15

    ④ 模型预测填充

    如果其他无缺失字段丰富,我们也可以借助于模型进行建模预测填充,将待填充字段作为Label,没有缺失的数据作为训练数据,建立分类/回归模型,对待填充的缺失字段进行预测并进行填充。

    机器学习; 数据处理与特征工程; 数据清洗; 缺失值处理; 8-16

    最近距离邻法(KNN)

    • 先根据欧式距离或相关分析来确定距离具有缺失数据样本最近的 K K K 个样本,将这 K K K 个值加权平均/投票来估计该样本的缺失数据。

    回归(Regression)

    • 基于完整的数据集,建立回归方程。对于包含空值的对象,将已知属性值代入方程来估计未知属性值,以此估计值来进行填充。当变量不是线性相关时会导致有偏差的估计,常用线性回归。

    我们以 Titanic 案例中的 age 字段为例,讲解一下:

    • age 缺失量较大,这里我们用 sex、pclass、who、fare、parch、sibsp 六个特征构建随机森林模型,填充年龄缺失值。
    df_titanic_age = df_titanic[['age', 'pclass', 'sex', 'who','fare', 'parch', 'sibsp']]
    df_titanic_age = pd.get_dummies(df_titanic_age)
    df_titanic_age.head()
    
    # 乘客分成已知年龄和未知年龄两部分
    known_age = df_titanic_age[df_titanic_age.age.notnull()]
    unknown_age = df_titanic_age[df_titanic_age.age.isnull()]
    # y 即目标年龄
    y_for_age = known_age['age']
    # X 即特征属性值
    X_train_for_age = known_age.drop(['age'], axis=1)
    X_test_for_age = unknown_age.drop(['age'], axis=1)
    from sklearn.ensemble import RandomForestRegressor
    rfr = RandomForestRegressor(random_state=0, n_estimators=2000, n_jobs=-1)
    rfr.fit(X_train_for_age, y_for_age)
    # 用得到的模型进行未知年龄结果预测
    y_pred_age = rfr.predict(X_test_for_age)
    # 用得到的预测结果填补原缺失数据
    df_titanic.loc[df_titanic.age.isnull(), 'age'] = y_pred_age
    
    sns.distplot(df_titanic.age)
    

    机器学习; 数据处理与特征工程; 数据清洗; 缺失值处理; 8-17

    ⑤ 插值法填充

    还可以用插值法对数据填充,细分一下包括线性插值、多重插补、热平台插补、拉格朗日插值、牛顿插值等。

    机器学习; 数据处理与特征工程; 数据清洗; 缺失值处理; 8-18


    线性插值法

    使用插值法可以计算缺失值的估计值,所谓的插值法就是通过两点 ( x 0 , y 0 ) (x_0, y_0) (x0,y0) ( x 1 , y 1 ) (x_1, y_1) (x1,y1) 估计中间点的值。假设 y = f ( x ) y=f(x) y=f(x) 是一条直线,通过已知的两点来计算函数 f ( x ) f(x) f(x),然后只要知道 x x x 就能求出 y y y,以此方法来估计缺失值。

    机器学习; 数据处理与特征工程; 数据清洗; 缺失值处理; 8-19

    .interpolate(method = 'linear', axis)方法将通过linear插值使用沿着给定axis的值替换 NaN 值,这个差值也就是前后或者上下的中间值

    df_titanic['fare'].interpolate(method = 'linear', axis = 0)
    

    同时,也可用行值插入

    df_titanic['fare'].interpolate(method = 'linear', axis = 1)
    

    多重插补(Multiple Imputation)

    多值插补的思想来源于贝叶斯估计,认为待插补的值是随机的,它的值来自于已观测到的值。具体实践上通常是估计出待插补的值,然后再加上不同的噪声,形成多组可选插补值。根据某种选择依据,选取最合适的插补值。

    机器学习; 数据处理与特征工程; 数据清洗; 缺失值处理; 8-20

    多重插补方法分为三个步骤:

    • ① 为每个空值产生一套可能的插补值,这些值反映了无响应模型的不确定性;每个值都可以被用来插补数据集中的缺失值,产生若干个完整数据集合;
    • ② 每个插补数据集合都用针对完整数据集的统计方法进行统计分析;
    • ③ 对来自各个插补数据集的结果,根据评分函数进行选择,产生最终的插补值。

    ⑥ 哑变量填充

    有另外一种非常有意思的填充方式,叫做「哑变量填充」,在变量为离散型,且不同值较少的情况下可以采用,以 Titanic 数据为例:

    • 性别 SEX 变量,存在 male,fameal,NA(缺失)三个不同的值,可将该列转换成IS_SEX_MALEIS_SEX_FEMALEIS_SEX_NA
    • 若某个变量存在十几个不同的值,可根据每个值的频数,将频数较小的值归为一类other,降低维度。此做法可最大化保留变量的信息。

    机器学习; 数据处理与特征工程; 数据清洗; 缺失值处理; 8-21

    以下为参考代码示例:

    sex_list = ['MALE', 'FEMALE', np.NaN, 'FEMALE', 'FEMALE', np.NaN, 'MALE']
    df = pd.DataFrame({'SEX': sex_list})
    display(df)
    
    df.fillna('NA', inplace=True)
    df = pd.get_dummies(df['SEX'],prefix='IS_SEX')
    display(df)
    

    # 原始数据
     SEX
    0    MALE
    1    FEMALE
    2    NaN
    3    FEMALE
    4    FEMALE
    5    NaN
    6    MALE
    # 填充后
     IS_SEX_FEMALE     IS_SEX_MALE    IS_SEX_NA
    0    0                 1                0
    1    1                 0                0
    2    0                 0                1
    3    1                 0                0
    4    1                 0                0
    5    0                 0                1
    6    0                 1 
    

    当特征值缺失超过 80 % 80\% 80% 以上,建议删除【或加入「是」「否」标记位信息】,容易影响模型效果

    df_titanic.drop(["deck"],axis=1)
    

    2.3 异常值处理

    数据质量也会很大程度影响机器学习应用效果,数据的错误值或异常值可能会造成测量误差或异常系统条件的结果,给模型学习带来很大的问题。实际我们很多时候会有异常值检测与处理环节,下面给大家做一个梳理。

    (1) 异常检测方法

    ① 基于统计分析

    通常用户用某个统计分布对数据点进行建模,再以假定的模型,根据点的分布来确定是否异常。

    如通过分析统计数据的散度情况,即数据变异指标,对数据的分布情况有所了解,进而通过数据变异指标来发现数据中的异常点数据。

    常用的数据变异指标有极差四分位数间距均差标准差变异系数等等,如变异指标的值大表示变异大、散布广;值小表示离差小,较密集。

    比如,最大最小值可以用来判断这个变量的取值是否超过了合理的范围,如客户的年龄为 − 20 -20 20 岁或 200 200 200 岁,为异常值。

    ② 3σ原则

    如果数据近似正态分布,在 3 σ 3 \sigma 3σ 原则下,异常值为一组测定值中与平均值的偏差超过 3 3 3 倍标准差的值。

    • 如果数据服从正态分布,距离平均值 3 σ 3 \sigma 3σ 之外的值出现的概率为 P ( ∣ x − μ ∣ > 3 σ ) ≤ 0.003 P(\left | x-\mu \right | >3\sigma) \le 0.003 P(xμ>3σ)0.003,属于极个别的小概率事件。
    • 如果数据不服从正态分布,也可以用远离平均值的多少倍标准差来描述。

    机器学习; 数据处理与特征工程; 数据清洗; 异常值处理; 8-22

    ③ 箱线图分析

    大家还记得在数据分析部分有一个很有效的工具叫做箱线图,箱线图提供了识别异常值的一个标准:如果一个值小于 Q 1 − 1.5 I Q R Q_1-1.5IQR Q11.5IQR 或大于 Q 3 + 1.5 I Q R Q_3+1.5IQR Q3+1.5IQR 的值,则被称为异常值。

    • Q 1 Q_1 Q1 为下四分位数,表示全部观察值中有四分之一的数据取值比它小;
    • Q 4 Q_4 Q4 为上四分位数,表示全部观察值中有四分之一的数据取值比它大;
    • I Q R IQR IQR 为四分位数间距,是上四分位数 Q 1 Q_1 Q1 与下四分位数 Q 3 Q_3 Q3 的差值,包含了全部观察值的一半。

    箱型图判断异常值的方法以四分位数和四分位距为基础,四分位数具有鲁棒性: 25 % 25 \% 25% 的数据可以变得任意远并且不会干扰四分位数,所以异常值不能对这个标准施加影响。因此箱型图识别异常值比较客观,在识别异常值时有一定的优越性。

    机器学习; 数据处理与特征工程; 数据清洗; 异常值处理; 8-23

    sns.catplot(y="fare",x="survived", kind="box", data=df_titanic,palette="Set2")
    

    机器学习; 数据处理与特征工程; 数据清洗; 异常值处理; 8-24

    ④ 基于模型检测

    我们也可以基于模型对异常值检测,基本思路是先建立一个数据模型,那些同模型不能完美拟合的对象就视作异常。

    • 如果模型是簇的集合,则异常是不显著属于任何簇的对象。
    • 在使用回归模型时,异常是相对远离预测值的对象。

    机器学习; 数据处理与特征工程; 数据清洗; 异常值处理; 8-25

    优点:有坚实的统计学理论基础,当存在充分的数据和所用的检验类型的知识时,这些检验可能非常有效。

    缺点:对于多元数据,可用的选择少一些,并且对于高维数据,这些检测可能性很差。

    ⑤ 基于距离

    我们还有基于距离的方法可以用于异常检测。这类方法基于下面这个假设:如果一个数据对象和大多数点距离都很远,那这个对象就是异常。通过定义对象之间的临近性度量,根据距离判断异常对象是否远离其他对象,主要使用的距离度量方法有绝对距离(曼哈顿距离)、欧氏距离和马氏距离等方法。

    机器学习; 数据处理与特征工程; 数据清洗; 异常值处理; 8-26

    • 优点
      • 基于距离的方法比基于统计类方法要简单得多;因为为一个数据集合定义一个距离的度量要比确定数据集合的分布容易的多。

    • 缺点
      • 基于邻近度的方法需要 O ( m 2 ) O(m2) O(m2) 时间,大数据集不适用;
      • 该方法对参数的选择也是敏感的;
      • 不能处理具有不同密度区域的数据集,因为它使用全局阈值,不能考虑这种密度的变化。

    ⑥ 基于密度

    一个很直接的异常检测思路是基于分布密度来做,具体为:考察当前点周围密度,局部异常点/离群点的局部密度显著低于大部分近邻点。这类方法适用于非均匀的数据集。

    机器学习; 数据处理与特征工程; 数据清洗; 异常值处理; 8-27

    • 优点
      • 给出了对象是离群点的定量度量,并且即使数据具有不同的区域也能够很好的处理。

    • 缺点
      • 与基于距离的方法一样,这些方法必然具有 O ( m 2 ) O(m2) O(m2) 的时间复杂度。
      • 对于低维数据使用特定的数据结构可以达到 O ( m l o g m ) O(mlogm) O(mlogm)
      • 参数选择困难。
      • 虽然算法通过观察不同的k值,取得最大离群点得分来处理该问题,但是,仍然需要选择这些值的上下界。

    ⑦ 基于聚类

    我们可以基于聚类的方法进行异常检测,远离 cluster 的样本更可能是异常值。

    不过该方法会受到聚类 cluster 个数 k k k 的影响,一种策略是对于不同的簇个数重复该分析;另一种方法是找出大量小簇,其想法是:

    • 较小的簇倾向于更加凝聚;
    • 如果存在大量小簇时一个对象是异常点,则它多半是一个真正的异常点。
    • 不利的一面是一组异常点可能形成小簇而逃避检测。

    机器学习; 数据处理与特征工程; 数据清洗; 异常值处理; 8-28

    • 优点
      • 基于线性和接近线性复杂度(k均值)的聚类技术来发现离群点可能是高度有效的;
      • 簇的定义通常是离群点的补,因此可能同时发现簇和离群点。

    • 缺点
      • 产生的离群点集和它们的得分可能非常依赖所用的簇的个数和数据中离群点的存在性;
      • 聚类算法产生的簇的质量对该算法产生的离群点的质量影响非常大。

    ⑧ 基于邻近度的异常点检测

    同样的,我们也有基于近邻度的思路来做异常检测,我们认为异常点远离大部分的点。这种方法比统计学方法更一般、更容易使用,因为确定数据集的有意义的邻近性度量比确定它的统计分布更容易。一个对象的异常点得分由到它的 K − K- K 最近邻的距离给定,所以异常点得分对 K K K 的取值高度敏感:

    • 如果 K K K 太小(例如 1 1 1),则少量的邻近异常异常点可能导致较异常低的异常点得分。
    • 如果 K K K 太大,则点数少于 K K K 的簇中所有的对象可能都成了异常异常点。

    为了使该方案对于 K K K 的选取更具有鲁棒性,可以使用 K K K 个最近邻的平均距离。

    机器学习; 数据处理与特征工程; 数据清洗; 异常值处理; 8-29

    优点

    • 简单

    缺点

    • 基于邻近度的方法需要 O ( m 2 ) O(m2) O(m2) 时间,大数据集不适用;
    • 该方法对参数的选择也是敏感的;
    • 不能处理具有不同密度区域的数据集,因为它使用全局阈值,不能考虑这种密度的变化。

    在数据处理阶段将离群点作为影响数据质量的异常点考虑,而不是作为通常所说的异常检测目标点,一般采用较为简单直观的方法,结合箱线图和 MAD 的统计方法判断变量的离群点。如下为绘制散点图根据分布直接判断。

    sns.scatterplot(x="fare", y="age", hue="survived",data=df_titanic,palette="Set1")
    

    机器学习; 数据处理与特征工程; 数据清洗; 异常值处理; 8-30

    (2) 异常处理方法

    对异常值处理,需要具体情况具体分析,异常值处理方法常用的有以下几种:

    • 删除含有异常值的记录;
      • 某些筛选出来的异常样本是否真的是不需要的异常特征样本,最好结合业务再确认一编,防止正常样本被过滤。
    • 将异常值视为缺失值,交给缺失值处理方法来处理;
    • 使用均值/中位数/众数来修正;
    • 不处理。

    3.特征构建

    前序的数据预处理过程能保证我们拿到干净整齐准确的数据,但这些数据未必对于建模是最有效的,下一步我们通常会进行特征构建,结合业务场景产生衍生变量来提升数据表达能力和模型建模效果。

    3.1 统计特征构建

    统计特征是一类非常有效的特征,尤其在时序问题场景中,以下为统计特征构建的一些思考维度和方法:

    机器学习; 数据处理与特征工程; 特征构建; 统计特征构建; 8-31

    • ① 基于业务规则、先验知识等构建新特征。
    • ② 四分位数、中位数、平均值、标准差、偏差、偏度、偏锋、离散系统。
    • ③ 构造长、短期统计量(如周、月)。
    • ④ 时间衰减(越靠近观测权重值高)。

    回到Titanic数据集,我们来看看结合业务理解,我们可以做哪些新特征:


    年龄处理

    我们对年龄 age 字段进行进一步处理,考虑到不同的年龄段对应的人群可能获救概率不同,我们根据年龄值分成不同区间段,对应到 child、young、midlife、old 等

    def age_bin(x):
     if x <= 18:
     return 'child'
     elif x <= 30:
     return 'young'
     elif x <= 55:
     return 'midlife'
     else:
     return 'old'
    df_titanic['age_bin'] = df_titanic['age'].map(age_bin)
    df_titanic['age_bin'].unique()
    执行结果:
    array(['young', 'midlife', 'child', 'old'], dtype=object)
    

    抽取「称呼」特征

    我们在 name 字段里,可以看到各种不同的称呼,如「Mr」「Master」「Dr」等,这些称呼体现了乘客的身份等信息,我们可以对其做抽取构建新的特征。

    # 提取称呼
    df_titanic['title'] = df_titanic['name'].map(lambda x: x.split(',')[1].split('.')[0].strip())
    
    df_titanic['title'].value_counts()
    

    执行结果如下:

    Mr              757
    Miss            260
    Mrs             197
    Master           61
    Rev               8
    Dr                8
    Col               4
    Ms                2
    Major             2
    Mlle              2
    Dona              1
    Sir               1
    Capt              1
    Don               1
    Lady              1
    Mme               1
    the Countess      1
    Jonkheer          1
    

    我们做一个简单的「称呼」统计

    # 对称呼细分,是官员,还是皇室,还是女士、先生、小姐
    df_titanic['title'].unique()
    

    执行结果:

    array(['Mr', 'Mrs', 'Miss', 'Master', 'Don', 'Rev', 'Dr', 'Mme', 'Ms',
     'Major', 'Lady', 'Sir', 'Mlle', 'Col', 'Capt', 'the Countess',
     'Jonkheer', 'Dona'], dtype=object)
    

    下面我们对这些「称呼」「称谓」做一个规范化统一。

    title_dictionary = {
     "Mr": "Mr",
     "Mrs": "Mrs",
     "Miss": "Miss",
     "Master": "Master",
     "Don": "Royalty",
     "Rev": "Officer",
     "Dr": "Officer",
     "Mme": "Mrs",
     "Ms": "Mrs",
     "Major": "Officer",
     "Lady": "Royalty",
     "Sir": "Royalty",
     "Mlle": "Miss",
     "Col": "Officer",
     "Capt": "Officer",
     "the Countess": "Royalty",
     "Jonkheer": "Royalty",
     "Dona": 'Mrs'
    }
    df_titanic['title'] = df_titanic['title'].map(title_dictionary)
    df_titanic['title'].value_counts()
    

    执行结果如下:

    Mr         757
    Miss       262
    Mrs        201
    Master      61
    Officer     23
    Royalty      5
    

    抽取家庭规模

    在 Titanic 上,有的成员之间有亲属关系,考虑到家族大小对于最终是否获救也有影响,我们可以构建一个 family_size 的特征,用于表征家庭规模。

    df_titanic['family_size'] = df_titanic['sibsp'] + df_titanic['parch'] + 1
    df_titanic['family_size'].head()
    

    执行结果如下:

    0    2
    1    2
    2    1
    3    2
    4    1
    

    3.2 周期值

    在电商等场景下,数据有一定的周期规律,我们可以提取一些周期值作为有效信息。

    机器学习; 数据处理与特征工程; 特征构建; 周期值; 8-32

    时序周期的一些考虑维度如下:

    • ①前n个周期/天/月/年的周期值,如过去 5 天分位数、平均值等
    • ②同比/环比

    3.3 数据分桶

    数据分桶,是对连续值属性处理的一种常用方法,它指的是我们把连续数值切段,并把连续值归属到对应的段中。数据分桶也叫做数据分箱或离散化。

    机器学习; 数据处理与特征工程; 特征构建; 数据分桶; 8-33

    (1) 等频、等距分桶

    (a) 自定义分箱

    指根据业务经验或者常识等自行设定划分的区间,然后将原始数据归类到各个区间中。

    (b) 等距分箱

    按照相同宽度将数据分成几等份。

    从最小值到最大值之间,均分为 N N N 等份。如果 A A A B B B 为最小最大值,则每个区间的长度为 W = ( B − A ) / N W=(B−A)/N W=(BA)/N,区间边界值为 A + W A+W A+W A + 2 W A+2W A+2W c d o t s cdots cdots A + ( N − 1 ) W A+(N−1)W A+(N1)W

    机器学习; 数据处理与特征工程; 特征构建; 数据分桶; 8-34

    等距分箱只考虑边界,每个等份里面的实例数量可能不等。等距分桶的缺点是受到异常值的影响比较大。

    © 等频分箱

    将数据分成几等份,每等份数据里面的个数是一样的。

    机器学习; 数据处理与特征工程; 特征构建; 数据分桶; 8-35

    在等频分箱中,区间的边界值要经过计算获得,最终每个区间包含大致相等的实例数量。比如说 N = 5 N=5 N=5,每个区间应该包含大约 20 % 20 \% 20% 的实例。


    • 数值变量分箱

    我们先对船票价格做一个等频切分(大家如果对船票价格进行分布绘图,会发现是很长尾的分布,并不适合等距切分),看看分开的区间段。

    # qcut 等频率分箱
    df_titanic['fare_bin'], bins = pd.qcut(df_titanic['fare'], 5, retbins=True)
    df_titanic['fare_bin'].value_counts()
    

    结果如下:

    (7.854, 10.5]        184
    (21.679, 39.688]     180
    (-0.001, 7.854]      179
    (39.688, 512.329]    176
    (10.5, 21.679]       172
    bins #array([  0.    ,   7.8542,  10.5   ,  21.6792,  39.6875, 512.3292])
    

    下面根据区间段对其进行等频切分

    # 对船票fare进行分段分桶
    def fare_cut(fare):
        if fare <=  7.8958:
            return 0
        if fare <= 10.5:
            return 1
        if fare <= 21.6792:
            return 2
        if fare <=  39.6875:
            return 3
        return 4
    
    df_titanic['fare_bin'] = df_titanic['fare'].map(fare_cut)
    

    相比船票价格,年龄 age 字段的分布更加集中,且区间大小比较明确,我们采用等距切分,代码如下:

    # cut 等距离分箱
    bins = [0, 12, 18, 65, 100]
    pd.cut(df_titanic['age'], bins).value_counts
    

    (2) Best-KS分桶

    • 1.将特征值值进行从小到大的排序。
    • 2.计算出 K S KS KS 最大的那个值,即为切点,记为 D D D。然后把数据切分成两部分。
    • 3.重复步骤2,进行递归, D D D 左右的数据进一步切割。直到 K S KS KS 的箱体数达到我们的预设阈值即可。
    • 4.连续型变量:分箱后的 K S KS KS ≤ \le 分箱前的 K S KS KS
    • 5.分箱过程中,决定分箱后的 K S KS KS 值是某一个切点,而不是多个切点的共同作用。这个切点的位置是原始 K S KS KS 值最大的位置。

    (3) 卡方分桶

    自底向上的(即基于合并的)数据离散化方法,依赖于卡方检验:具有最小卡方值的相邻区间合并在一起,直到满足确定的停止准则。

    机器学习; 数据处理与特征工程; 特征构建; 数据分桶; 8-36

    基本思想

    如果两个相邻的区间具有非常类似的类分布,则这两个区间可以合并;否则,它们应当保持分开。而低卡方值表明它们具有相似的类分布。


    实现步骤

    • ①预先定义一个卡方的阈值
    • ②初始化;根据要离散的属性对实例进行排序,每个实例属于一个区间
    • ③合并区间
      • 计算每一对相邻区间的卡方值
      • 将卡方值最小的一对区间合并

    代码实现:https://github.com/Lantianzz/Scorecard-Bundle

    (4) 最小熵法分箱

    还有最小熵分箱法,需要使总熵值达到最小,也就是使分箱能够最大限度地区分因变量的各类别。

    熵是信息论中数据无序程度的度量标准,提出信息熵的基本目的是找出某种符号系统的信息量和冗余度之间的关系,以便能用最小的成本和消耗来实现最高效率的数据存储、管理和传递。

    数据集的熵越低,说明数据之间的差异越小,最小熵划分就是为了使每箱中的数据具有最好的相似性。给定箱的个数,如果考虑所有可能的分箱情况,最小熵方法得到的箱应该是具有最小熵的分箱。

    3.4 特征组合

    我们在有些场景下会考虑特征组合构建强特征,如下为常用的特征组合构建方式:

    1. 离散+离散:构建笛卡尔积(即两两组合「且」关系)。
    2. 离散+连续:连续特征分桶后进行笛卡尔积或基于类别特征 group by 构建统计特征。
    3. 连续+连续:加减乘除,多项式特征,二阶差分等。

    机器学习; 数据处理与特征工程; 特征构建; 特征组合; 8-37


    • 多项式特征

    针对连续值特征,我们对几个特征构建多项式特征,以达到特征组合与高阶增强的作用。

    机器学习; 数据处理与特征工程; 特征构建; 特征组合; 8-38

    在Titanic的例子中,如下为数值型特征:

    df_titanic_numerical = df_titanic[['age','sibsp','parch','fare','family_size']]
    df_titanic_numerical.head()
    

    我们可以参考下述代码构建多项式特征

    # 扩展数值特征
    from sklearn.preprocessing import PolynomialFeatures
    poly = PolynomialFeatures(degree=2, include_bias=False, interaction_only=False)
    df_titanic_numerical_poly = poly.fit_transform(df_titanic_numerical)
    pd.DataFrame(df_titanic_numerical_poly, columns=poly.get_feature_names()).head()
    

    机器学习; 数据处理与特征工程; 特征构建; 特征组合; 8-39

    在构建完成特征后,我们查看下衍生新特征变量的相关性情况,下面的热力图heatmap里颜色越深相关性越大:

    sns.heatmap(pd.DataFrame(df_titanic_numerical_poly, columns=poly.get_feature_names()).corr())
    

    机器学习; 数据处理与特征工程; 特征构建; 特征组合; 8-40

    4.特征变换

    我们对于构建完的特征,会做一些「特征变换」的操作,以适应不同的模型,更好地完成建模。

    机器学习; 数据处理与特征工程; 特征变换; 8-41

    4.1 标准化(Standardization)

    标准化操作也称作 Z-score 变换,它使数值特征列的算数平均为 0 0 0,方差(以及标准差)为 1 1 1,如下图所示。

    机器学习; 数据处理与特征工程; 特征变换; 标准化; 8-42

    注意:如果数值特征列中存在数值极大或极小的outlier(通过EDA发现),应该使用更稳健(robust)的统计数据:用中位数而不是算术平均数,用分位数(quantile)而不是方差。这种标准化方法有一个重要的参数:(分位数下限,分位数上限),最好通过EDA的数据可视化确定。免疫outlier。


    标准化操作的参考代码如下:

    from sklearn.preprocessing import StandardScale
    #标准化模型训练
    Stan_scaler = StandardScaler()
    Stan_scaler.fit(x)
    x_zscore = Stan_scaler.transform(x)
    x_test_zscore = Stan_scaler.transform(x_test)
    joblib.dump(Stan_scaler,'zscore.m')  #写入文件
    

    4.2 归一化(Normalization)

    归一化操作会基于向量模长调整数据幅度大小,但并不会改变原始数据的顺序。如下图所示:

    机器学习; 数据处理与特征工程; 特征变换; 归一化; 8-43

    4.3 幅度缩放(scaling)

    幅度缩放是为了让不同特征的取值在大体一致的数量级和数据区间内,比较常用的方法是最大最小值缩放,如下图所示:

    机器学习; 数据处理与特征工程; 特征变换; 幅度缩放; 8-44

    下面为幅度缩放操作的参考代码:

    from sklearn import preprocessing
    min_max_scaler = preprocessing.MinMaxScaler()
    min_max_scaler.fit_transform(x)
    x_minmax = min_max_scaler.transform(x)
    x_test_minmax = min_max_scaler.transform(x_test)
    joblib.dump(min_max_scaler,'min_max_scaler.m')  #写入文件
    

    4.4 归一化 VS 标准化

    归一化和标准化是两个非常常见的特征变换操作,下面我们来对比一下标准化和归一化:

    • 目的不同,归一化是为了消除纲量压缩到 [ 0 , 1 ] [0,1] [0,1] 区间;标准化只是调整特征整体的分布。
    • 归一化与最大,最小值有关;标准化与均值,标准差有关。
    • 归一化输出在 [ 0 , 1 ] [0,1] [0,1] 之间;标准化无限制。

    它们分别的适用场景可以归纳总结如下:

    • 在分类、聚类算法中(参考ShowMeAI教程 图解机器学习算法:从入门到精通系列教程),需要使用距离来度量相似性的时候(如 SVM、KNN)或者使用 PCA 技术进行降维的时候,标准化(Z-score standardization)表现更好。

    • 在不涉及距离度量、协方差计算、数据不符合正太分布的时候,可以使用第一种方法或其他归一化方法。例如图像处理时,将 RGB 图像转换为灰度图像后将其值限定在 [ 0 , 255 ] [0,255] [0,255] 的范围。

    • 基于树的模型(如随机森林、GBDT、XGBoost、LightGBM等,具体模型参考ShowMeAI教程 图解机器学习算法:从入门到精通系列教程)不需要进行特征的归一化。如果是基于参数的模型或者基于距离的模型(逻辑回归、K-Means聚类、神经网络等),因为需要对参数或者距离进行计算,都需要进行归一化。

    4.5 非线性变换

    我们在有些场景下,还会对数值字段进行分布调整或者校正,利用统计或数学变换来减轻数据分布倾斜的影响。使原本密集的区间的值尽可能的分散,原本分散的区间的值尽量的聚合。

    大部分变换函数都属于幂变换函数簇,主要作用是稳定方差,保持分布接近于正态分布并使得数据与分布的平均值无关。

    我们来看看一些典型的非线性统计变换。

    (1) log变换

    log 变换通常用来创建单调的数据变换。主要作用为稳定方差,始终保持分布接近于正态分布并使得数据与分布的平均值无关。

    • log 变换倾向于拉伸那些落在较低的幅度范围内自变量值的范围,倾向于压缩或减少更高幅度范围内的自变量值的范围,从而使得倾斜分布尽可能的接近正态分布。
    • 针对一些数值连续特征的方差不稳定,特征值重尾分布我们需要采用 log 化来调整整个数据分布的方差,属于方差稳定型数据转换。

    log 变换属于幂变换函数簇,数学表达式为

    y = l o g b ( x ) y=log_{b}(x) y=logb(x)

    机器学习; 数据处理与特征工程; 特征变换; 非线性变换; 8-45

    下面我们对 Titanic 数据集中的船票价格字段进行 log1p 变换,示例代码如下:

    sns.distplot(df_titanic.fare,kde=False)
    

    机器学习; 数据处理与特征工程; 特征变换; 非线性变换; 8-46

    df_titanic['fare_log'] = np.log((1+df_titanic['fare']))
    sns.distplot(df_titanic.fare_log,kde=False)
    

    机器学习; 数据处理与特征工程; 特征变换; 非线性变换; 8-47

    (2) box-cox变换

    box-cox 变换是 box 和 cox 在1964年提出的一种广义幂变换方法,是统计建模中常用的一种数据变换,用于连续的响应变量不满足正态分布的情况。box-cox 变换之后,可以一定程度上减小不可观测的误差和预测变量的相关性。

    box-cox 变换的主要特点是引入一个参数,通过数据本身估计该参数进而确定应采取的数据变换形式,box-cox 变换可以明显地改善数据的正态性、对称性和方差相等性,对许多实际数据都是行之有效的。


    box-cox 变换函数数学表达式如下:

    y ( λ ) = { y λ − 1 λ , λ ≠ 0 ln ⁡ y , λ = 0 y(\lambda)=\left\{\begin{array}{ll} \frac{y^{\lambda}-1}{\lambda}, & \lambda \neq 0 \\ \ln y, & \lambda=0 \end{array}\right. y(λ)={λyλ1,lny,λ=0λ=0

    生成的变换后的输出 y y y,是输入 x x x 和变换参数的函数;当 λ = 0 \lambda=0 λ=0 时,该变换就是自然对数 log 变换,前面我们已经提到过了。 λ \lambda λ 的最佳取值通常由最大似然或最大对数似然确定。

    机器学习; 数据处理与特征工程; 特征变换; 非线性变换; 8-48

    下面我们对Titanic数据集中的船票价格字段进行 box-cox 变换,示例代码如下:

    # 从数据分布中移除非零值
    fare_positive_value = df_titanic[(~df_titanic['fare'].isnull()) & (df_titanic['fare']>0)]['fare']
    import scipy.stats as spstats
    # 计算最佳λ值
    l, opt_lambda = spstats.boxcox(fare_positive_value)
    print('Optimal lambda value:', opt_lambda) # -0.5239075895755266
    # 进行 Box-Cox 变换
    fare_boxcox_lambda_opt = spstats.boxcox(df_titanic[df_titanic['fare']>0]['fare'],lmbda=opt_lambda)
    sns.distplot(fare_boxcox_lambda_opt,kde=Fal
    

    机器学习; 数据处理与特征工程; 特征变换; 非线性变换; 8-49

    4.6 离散变量处理

    对于类别型的字段特征(比如颜色、类型、好坏程度),有很多模型并不能直接处理,我们对其进行编码后能更好地呈现信息和支撑模型学习。有以下常见的类别型变量编码方式:

    (1) 标签编码(label encoding)

    标签编码(label encoding)是最常见的类别型数据编码方式之一,编码值介于 0 0 0 和 n_classes-1 之间的标签。

    机器学习; 数据处理与特征工程; 特征变换; 离散变量处理; 8-50

    例如:比如有 [ d o g , c a t , d o g , m o u s e , r a b b i t ] [dog,cat,dog,mouse,rabbit] [dog,cat,dog,mouse,rabbit],我们把其转换为 [ 0 , 1 , 0 , 2 , 3 ] [0,1,0,2,3] [0,1,0,2,3]

    • 优点:相对于 OneHot 编码,LabelEncoder 编码占用内存空间小,并且支持文本特征编码。
    • 缺点:它的编码方式给不同类别带来了额外的大小顺序关系,在有些计算型模型(比如逻辑回归)里有影响,它可以使用在树模型中。

    标签编码的参考代码如下:

    from sklearn.preprocessing import LabelEncoder
    le = LabelEncoder()
    le.fit(["超一线", "一线", "二线", "三线"])
    print('特征:{}'.format(list(le.classes_)))
    # 输出 特征:['一线', '三线', '二线', '超一线']
    print('转换标签值:{}'.format(le.transform(["超一线", "一线", "二线"])))
    # 输出 转换标签值:array([3 0 2]...)
    print('特征标签值反转:{}'.format(list(le.inverse_transform([2, 2, 1]))))
    # 输出 特征标签值反转:['二线', '二线', '三线
    

    (2) 独热向量编码(one hot encoding )

    独热编码通常用于处理类别间不具有大小关系的特征。

    机器学习; 数据处理与特征工程; 特征变换; 离散变量处理; 8-51

    例如:特征:血型,一共有四种类别 ( A , B , A B , O ) (A,B,AB,O) (A,B,AB,O),采用独热编码后,会把血型变成有一个4维的稀疏向量

    • A表示为 [ 1 , 0 , 0 , 0 ] [1,0,0,0] [1,0,0,0]
    • B表示为 [ 0 , 1 , 0 , 0 ] [0,1,0,0] [0,1,0,0]
    • AB表示为 [ 0 , 0 , 1 , 0 ] [0,0,1,0] [0,0,1,0]
    • O表示为 [ 0 , 0 , 0 , 1 ] [0,0,0,1] [0,0,0,1]

    最终生成的稀疏向量的维度,和类别数相同。

    • 优点:独热编码解决了分类器不好处理属性数据的问题,在一定程度上也起到了扩充特征的作用。它的值只有 0 0 0 1 1 1,不同的类型存储在垂直的空间。
    • 缺点:只能对数值型变量二值化,无法直接对字符串型的类别变量编码。当类别的数量很多时,特征空间会变得非常大。在这种情况下,一般可以用 PCA 来减少维度。而且 one hot encoding+PCA 这种组合在实际中也非常有用。

    如果借助于pandas工具库(查看ShowMeAI数据分析系列教程数据科学工具速查 | Pandas使用指南 进行详细了解),独热向量编码的 Python 代码参考示例如下:

    sex_list = ['MALE', 'FEMALE', np.NaN, 'FEMALE', 'FEMALE', np.NaN, 'MALE']
    df = pd.DataFrame({'SEX': sex_list})
    display(df)
    df.fillna('NA', inplace=True)
    df = pd.get_dummies(df['SEX'],prefix='IS_SEX')
    display(df)
    

    最终变换前后的结果如下:

    # 原始数据
     SEX
    0   MALE
    1   FEMALE
    2   NaN
    3   FEMALE
    4   FEMALE
    5   NaN
    6   MALE
    
    # 独热向量编码后
     IS_SEX_FEMALE     IS_SEX_MALE    IS_SEX_NA
    0    0                 1                0
    1    1                 0                0
    2    0                 0                1
    3    1                 0                0
    4    1                 0                0
    5    0                 0                1 
    

    下面我们对’sex’, ‘class’, ‘pclass’, ‘embarked’, ‘who’, ‘family_size’, 'age_bin’这些字段都进行独热向量编码。

    pd.get_dummies(df_titanic, columns=['sex', 'class', 'pclass', 'embarked', 'who', 'family_size', 'age_bin'],drop_first=True)
    

    机器学习; 数据处理与特征工程; 特征变换; 离散变量处理; 8-52

    当然,我们也可以借助SKLearn(查看ShowMeAI教程 SKLearn最全应用指南AI建模工具速查 | Scikit-learn使用指南 详细学习),进行独热向量编码实现:

    import numpy as np
    from sklearn.preprocessing import OneHotEncoder
    # 非负整数表示的标签列表
    labels = [0,1,0,2]
    # 行向量转列向量
    labels = np.array(labels).reshape(len(labels), -1)
    # 独热向量编码
    enc = OneHotEncoder()
    enc.fit(labels)
    targets = enc.transform(labels).toarray()
    # 如果不加 toarray() 的话,输出的是稀疏的存储格式,即索引加值的形式,也可以通过参数指定 sparse = False 来达到同样的效果
    

    输出结果如下:

    array([[ 1.,  0.,  0.],
     [ 0.,  1.,  0.],
     [ 1.,  0.,  0.],
     [ 0.,  0.,  1.]])
    

    (3) 标签二值化(LabelBinarizer)

    功能与 OneHotEncoder 一样,但是 OneHotEncoder 只能对数值型变量二值化,无法直接对字符串型的类别变量编码,而 LabelBinarizer 可以直接对字符型变量二值化。

    示例代码如下:

    from sklearn.preprocessing import LabelBinarizer
    lb=LabelBinarizer()
    labelList=['yes', 'no', 'no', 'yes','no2']
    # 将标签矩阵二值化
    dummY=lb.fit_transform(labelList)
    print("dummY:",dummY)
    # 逆过程
    yesORno=lb.inverse_transform(dummY)
    print("yesOrno:",yesORno)
    

    输出如下:

    dummY: [[0 0 1]
     [1 0 0]
     [1 0 0]
     [0 0 1]
     [0 1 0]]
    yesOrno: ['yes' 'no' 'no' 'yes' 'no2']
    

    4.7 降维

    在实际的机器学习项目中,我们可能还会做降维处理,主要因为数据存在以下几个问题:

    • 数据的多重共线性:特征属性之间存在着相互关联关系。多重共线性会导致解的空间不稳定, 从而导致模型的泛化能力弱。
    • 高纬空间样本具有稀疏性,导致模型比较难找到数据特征。
    • 过多的变量会妨碍模型查找规律。
    • 仅仅考虑单个变量对于目标属性的影响可能忽略变量之间的潜在关系。

    机器学习; 数据处理与特征工程; 特征变换; 降维; 8-53

    通过特征降维希望达到的目的:

    • 减少特征属性的个数
    • 确保特征属性之间是相互独立的

    常用的降维方法有:

    • PCA
    • SVD
    • LDA
    • T-sne等非线性降维

    这里降维的讲解,我们给大家基于 iris 数据集讲解:

    from sklearn import datasets
    
    iris_data = datasets.load_iris()
    
    X = iris_data.data
    y = iris_data.target
    
    def draw_result(X, y):
        plt.figure()
        # 提取 Iris-setosa
        setosa = X[y == 0]
        # 绘制点:参数 1 x 向量,y 向量
        plt.scatter(setosa[:, 0], setosa[:, 1], color="red", label="Iris-setosa")
    
        versicolor = X[y == 1]
        plt.scatter(versicolor[:, 0], versicolor[:, 1], color="orange", label="Iris-versicolor")
    
        virginica = X[y == 2]
        plt.scatter(virginica[:, 0], virginica[:, 1], color="blue", label="Iris-virginica")
    
        plt.legend()
        plt.show()
    
    draw_result(X, y)
    

    机器学习; 数据处理与特征工程; 特征变换; 降维; 8-54

    (1) PCA(Principal Component Analysis)

    关于PCA主成分分析降维算法,大家可以查阅ShowMeAI文章 图解机器学习 | 降维算法详解 进行详细学习。

    PCA降维的参考代码实现如下:

    import numpy as np
    from sklearn.decomposition import PCA
    pca = PCA(n_components=2)
    newX = pca.fit_transform(X)
    draw_result(newX, y)
    

    机器学习; 数据处理与特征工程; 特征变换; 降维–PCA; 8-55

    (2) SVD(Singular Value Decomposition)

    SVD方法的主要步骤如下:

    A T A = ( U Σ V T ) T U Σ V T = V Σ T U T U Σ V T = V Σ T Σ V T = V Σ 2 V T A^{T} A=\left(U \Sigma V^{T}\right)^{T} U \Sigma V^{T}=V \Sigma^{T} U^{T} U \Sigma V^{T}=V \Sigma^{T} \Sigma V^{T}=V \Sigma^{2} V^{T} ATA=(UΣVT)TUΣVT=VΣTUTUΣVT=VΣTΣVT=VΣ2VT

    所以 V V V A T A A^{T} A ATA 特征值分解的特征向量按列组成的正交矩阵, Σ 2 \Sigma^{2} Σ2 A T A A^{T} A ATA 特征值组成的对角矩阵,也可以看出 $A_{m \times n} $ 的奇异值 σ i \sigma_{i} σi A T A A^{T} A ATA 特征值 λ i \lambda_{i} λi 的平方根。

    σ i = λ i \sigma_{i}=\sqrt{\lambda_{i}} σi=λi


    假如 A T A A^{T} A ATA 的特征向量为 v i v_{i} vi U U U 中对应的 u i u_{i} ui 则可以由下式求出:

    u i = A v i σ i u_{i}=\frac{A v_{i}}{\sigma_{i}} ui=σiAvi

    也即奇异值分解的关键在于对 A T A A^{T} A ATA 进行特征值分解。


    对应的代码参考实现如下:

    from sklearn.decomposition import TruncatedSVD
    iris_2d = TruncatedSVD(2).fit_transform(X)
    draw_result(iris_2d, y)
    

    机器学习; 数据处理与特征工程; 特征变换; 降维–SVD; 8-56

    PCA vs SVD

    PCA求解关键在于求解协方差矩阵 C = 1 m X X T C=\frac{1}{m} X X^{T} C=m1XXT 的特征值分解。

    SVD关键在于 A T A A^{T} A ATA 的特征值分解。


    很明显二者所解决的问题非常相似,都是对一个实对称矩阵进行特征值分解,如果取:

    A = X T m A=\frac{X^{T}}{\sqrt{m}} A=m XT

    则有:

    A T A = ( X T m ) T X T m = 1 m X X T A^{T} A=\left(\frac{X^{T}}{\sqrt{m}}\right)^{T} \frac{X^{T}}{\sqrt{m}}=\frac{1}{m} X X^{T} ATA=(m XT)Tm XT=m1XXT

    此时SVD与PCA等价,所以PCA问题可以转化为SVD问题求解。

    (3) LDA(Linear Discriminant Analysis)

    是有监督的降维,通过最小化类内离散度与最大化类间离散度来获得最优特征子集。

    机器学习; 数据处理与特征工程; 特征变换; 降维–LDA; 8-57

    上图解读:LD1通过线性判定,可以很好的将呈正态分布的两个类分开。LD2的线性判定保持了数据集的较大方差,但LD2无法提供关于类别的信息,因此LD2不是一个好的线性判定。

    对应的降维参考实现代码如下:

    from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
    lda = LDA(n_components=2)
    iris_2d = lda.fit_transform(X, y)
    draw_result(iris_2d, y)
    

    机器学习; 数据处理与特征工程; 特征变换; 降维–LDA; 8-58

    LDA vs PCA

    PCA 试图寻找到方差最大的正交的主成分分量轴 LDA 发现可以最优化分类的特征子空间 LDA 和 PCA 都是可用于降低数据集维度的线性转换技巧 PCA 是无监督算法 LDA 是监督算法 LDA 是一种更优越的用于分类的特征提取技术

    (4) T-SNE

    T-SNE(t-distributed stochastic neighbor embedding)是一种非线性降维方法,参考的代码实现如下:

    from sklearn.manifold import TSNE
    tsne = TSNE(n_components=2)
    iris_2d = tsne.fit_transform(X)
    draw_result(iris_2d, y)
    

    机器学习; 数据处理与特征工程; 特征变换; 降维–T-SNE; 8-59

    5.特征选择

    特征选择是在建模过程中经常会用到的一个处理,也有重要意义:

    • 特征冗余,部分特征相关度太高,消耗计算资源
    • 存在噪声,对模型结果有负面影响
    • 部分特征容易引起过拟合

    机器学习; 数据处理与特征工程; 特征选择; 8-60

    总体来说,进行特征选择有2个主要考虑方向:

    • 特征发散程度:如果一个特征不发散,例如方差接近于 0 0 0,也就是说样本在这个特征上基本上没有差异,这个特征对于样本的区分并没有什么用。
    • 特征与目标的相关性:特征与目标相关性高,越应当被保留,这点大家也比较容易理解。

    对特征选择的方法进行归类,又大体可以归纳为下述3种:

    • Filter:过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数来选择特征。
    • Wrapper:包装法,根据目标函数(通常是预测效果评分),每次选择若干特征或者排除若干特征。
    • Embedded:嵌入法,先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。类似于Filter 方法,但是是通过训练来确定特征的优劣。我们使用 SKLearn 中的 feature_selection 库来进行特征选择。

    5.1 过滤式Filter

    (1) 方差过滤

    这是通过特征本身的方差来筛选特征的类。

    比如一个特征本身的方差很小,就表示样本在这个特征上基本没有差异,可能特征中的大多数值都一样,甚至整个特征的取值都相同,那这个特征对于样本区分没有什么作用。

    我们会剔除掉方差非常小的字段特征,参考代码实现如下:

    from sklearn.feature_selection import VarianceThreshold
    variancethreshold = VarianceThreshold() #实例化,默认方差为 0.方差<=0 的过滤掉
    df_titanic_numerical = df_titanic[['age','sibsp','parch','fare','family_size']]
    X_var = variancethreshold.fit_transform(df_titanic_numerical)    #获取删除不合格特征后的新特征矩阵
    del_list = df_titanic_numerical.columns[variancethreshold.get_support()==0].to_list()  #获得删除
    

    (2) 卡方过滤

    卡方检验,专用于分类算法,捕捉相关性,追求p小于显著性水平的特征。卡方过滤是专门针对离散型标签(即分类问题)的相关性过滤。

    机器学习; 数据处理与特征工程; 特征选择; 过滤式Filter; 8-61

    p值和取到这一个统计量的概率取值其实是正相关的: p p p 值越大,取到这个统计量的概率就越大,即越合理; p p p 值越小,取到这个统计量的概率就越小,即越不合理,此时应该拒绝原假设,接收备择假设。

    如下为卡方过滤的参考代码示例:

    df_titanic_categorical = df_titanic[['sex', 'class', 'embarked', 'who',  'age_bin','adult_male','alone','fare_bin']]
    df_titanic_numerical = df_titanic[['age','sibsp','parch','fare','family_size','pclass']]
    df_titanic_categorical_one_hot = pd.get_dummies(df_titanic_categorical, columns=['sex', 'class', 'embarked', 'who',  'age_bin','adult_male','alone','fare_bin'], drop_first=True)
    df_titanic_combined = pd.concat([df_titanic_numerical,df_titanic_categorical_one_hot],axis=1)
    
    y = df_titanic['survived']
    X = df_titanic_combined.iloc[:,1:]
    
    from sklearn.feature_selection import chi2
    from sklearn.feature_selection import SelectKBest
    chi_value, p_value = chi2(X,y)
    #根据 p 值,得出 k 值
    k = chi_value.shape[0] - (p_value > 0.05).sum()  #要保留的特征的数量 14
    #根据卡方值,选择前几特征,筛选后特征
    X_chi = SelectKBest(chi2, k=14).fit_transform(X, y)
    

    (3) F检验

    F F F 检验捕捉线性相关性,要求数据服从正态分布,追求 P P P 值小于显著性水平特征。

    其特征选择的参考代码如下:

    from sklearn.feature_selection import f_classif
    f_value, p_value = f_classif(X,y)
    #根据 p 值,得出 k 值
    k = f_value.shape[0] - (p_value > 0.05).sum()
    #筛选后特征
    X_classif = SelectKBest(f_classif, k=14).fit_transform(X, y)
    

    (4) 互信息法

    互信息法是用来捕捉每个特征与标签之间的任意关系(包括线性和非线性关系)的过滤方法。

    其特征选择的参考代码如下:

    from sklearn.feature_selection import mutual_info_classif as MIC
    #互信息法
    mic_result = MIC(X,y)   #互信息量估计
    k = mic_result.shape[0] - sum(mic_result <= 0)    #16
    X_mic = SelectKBest(MIC, k=16).fit_transform(X, y)
    

    5.2 包裹式Wrapper

    (1) 递归特征删除法

    递归消除删除法使用一个基模型来进行多轮训练,每轮训练后,消除若干权值系数的特征,再基于新的特征集进行下一轮训练。使用feature_selection 库的 RFE 类来选择特征的代码如下:

    from sklearn.feature_selection import RFE
    from sklearn.linear_model import LogisticRegression
    #递归特征消除法,返回特征选择后的数据
    #参数 estimator 为基模型
    #参数 n_features_to_select 为选择的特征个数
    X_ref = RFE(estimator=LogisticRegression(), n_features_to_select=10).fit_transform(X, y)
    

    (2) 特征重要性评估

    我们基于一些模型(如各类树模型)可以得到特征重要度,进而进行筛选

    from sklearn.ensemble import ExtraTreesClassifier
    # 建模与获取特征重要度
    model = ExtraTreesClassifier()
    model.fit(X, y)
    print(model.feature_importances_)
    
    # 特征重要度排序
    feature=list(zip(X.columns,model.feature_importances_))
    feature=pd.DataFrame(feature,columns=['feature','importances'])
    feature.sort_values(by='importances',ascending=False).head(20)
    

    (3) 排列重要性评估

    我们还有一类方法可以评估特征重要度,进而进行筛选,叫作排列重要度。

    原理:在训练机器学习模型之后计算置换重要性。这种方法在向模型提出假设,如果在保留目标和所有其他列的同时随机打乱一列验证集特征数据,对预测机器学习模型的准确性的影响程度。对于一个具有高度重要性的特征,random-reshuffle 会对机器学习模型预测的准确性造成更大的损害。

    优点:快速计算;易于使用和理解;特征重要性度量的属性;追求特征稳定性。

    参考代码实现如下:

    import numpy as np
    import pandas as pd
    from sklearn.model_selection import train_test_split
    from sklearn.ensemble import RandomForestClassifier
    import eli5
    from eli5.sklearn import PermutationImportance
    my_model = RandomForestClassifier(random_state=0).fit(train_X, train_y)
    perm = PermutationImportance(my_model, random_state=1).fit(val_X, val_y)
    eli5.show_weights(perm, feature_names = val_X.columns.tolist())
    

    机器学习; 数据处理与特征工程; 特征选择; 包裹式Wrapper; 8-62

    5.3 嵌入式Embedded

    (1) 基于惩罚项的特征选择法

    使用带惩罚项的基模型,除了筛选出特征外,同时也进行了降维。

    使用feature_selection库的SelectFromModel类结合带 L1 惩罚项的逻辑回归模型,来选择特征的代码如下:

    from sklearn.feature_selection import SelectFromModel
    from sklearn.linear_model import LogisticRegression
    #带 L1 和 L2 惩罚项的逻辑回归作为基模型的特征选择,这个设置带 L1 惩罚项的逻辑回归作为基模型的特征选择
    lr = LogisticRegression(solver='liblinear',penalty="l1", C=0.1)
    X_sfm = SelectFromModel(lr).fit_transform(X, y)
    X_sfm.shape
    (891, 7
    

    使用 feature_selection 库的 SelectFromModel 类结合 SVM 模型,来选择特征的代码如下:

    from sklearn.feature_selection import SelectFromModel
    from sklearn.svm import LinearSVC
    lsvc = LinearSVC(C=0.01,penalty='l1',dual=False).fit(X, y)
    model = SelectFromModel(lsvc,prefit=True)
    X_sfm_svm = model.transform(X)
    X_sfm_svm.shape
    (891, 7
    

    (2) 基于树模型

    树模型中 GBDT 也可用来作为基模型进行特征选择,使用 feature_selection 库的 SelectFromModel 类结合 GBDT 模型,来选择特征的代码如下:

    from sklearn.feature_selection import SelectFromModel
    from sklearn.ensemble import GradientBoostingClassifier
    #GBDT 作为基模型的特征选择
    gbdt = GradientBoostingClassifier()
    X_sfm_gbdt = SelectFromModel(gbdt).fit_transform(X, y)
    

    5.4 特征选择总结

    关于特征选择,做一个经验总结,如下:

    • ① 类别型特征变量,那么可以从SelectKBest开始,用卡方或者基于树的选择器来选择变量;
    • ② 定量特征变量,可以直接用线性模型和基于相关性的选择器来选择变量;
    • ③ 二分类问题,可以考虑使用SelectFromModel和SVC;
    • ④ 特征选择前,要充分了解数据,一般需要做探索性数据分析EDA。

    6.特征工程实战建议

    最后,ShowMeAI结合实际工业应用经验,总结一些特征工程要点,如下:

    机器学习; 数据处理与特征工程; 特征选择实战建议; 8-63

    6.1 数据理解

    构建特征的有效性,和业务及数据分布强相关,因此建议在此步骤之前做EDA探索性数据分析来充分理解数据(可以参考ShowMeAI文章 Python机器学习综合项目-电商销量预估Python机器学习综合项目-电商销量预估<进阶> 了解EDA的基本过程和方法)。

    6.2 数据预处理

    我们可能会做的一些数据预处理与特征处理如下:

    连续特征离散化

    • 本质是限制浮点数特征的精度,异常数据有很强的鲁棒性,模型也会更稳定。
    • 树模型不需要做

    数值截断

    • 把特征值的取值限制在一定范围内(对异常剔除有帮助)
    • 可以用 pandas dataframe 的 .clip(low,upper) 方法

    6.3 数据清洗

    结合业务场景和数据分布,进行合理的缺失值、异常值处理。

    6.4 特征构建与变换

    建议不要上来就做PCA或LDA降维,最好先构建特征并对特征做筛选。

    机器学习; 数据处理与特征工程; 特征选择实战建议; 8-64

    线性组合(linear combination)

    • 适用于决策树以及基于决策树的ensemble(如gradient boosting,random forest),因为常见的 axis-aligned split function 不擅长捕获不同特征之间的相关性;
    • 不适用于SVM、线性回归、神经网络等。

    类别特征与数值特征的组合

    • 用 N1 和 N2 表示数值特征,用 C1 和 C2 表示类别特征,利用 pandas 的 groupby 操作,可以创造出以下几种有意义的新特征:(其中,C2还可以是离散化了的 N1)
    median(N1)_by(C1)   中位数
    mean(N1)_by(C1)   算术平均数
    mode(N1)_by(C1)   众数
    min(N1)_by(C1)   最小值
    max(N1)_by(C1)   最大值
    std(N1)_by(C1)   标准差
    var(N1)_by(C1)   方差
    freq(C2)_by(C1)   频数
    

    统计特征+线性组合

    • 统计特征可以和线性组合等基础特征工程方法结合(仅用于决策树),可以得到更多有意义的特征,如:
    N1 - median(N1)_by(C1)
    N1 - mean(N1)_by(C1)
    

    基于树模型创造新特征

    • 在决策树系列算法中(例决策树、gbdt、随机森林,具体可以查看ShowMeAI教程 图解机器学习算法:从入门到精通系列教程 详细学习理解),每一个样本都会被映射到决策树的叶子上。
    • 我们可以把样本经过每一棵决策树映射后的 index(自然数)或 one-hot-encoding-vector (哑编码得到的稀疏矢量)作为一项新的特征,加入到模型中。

    在 Scikit-Learn 和 XGBoost 里,可以基于 apply() 以及 decision_path() 等方法实现。

    6.5 模型

    我们在不同类型的模型里,也会考虑不同的特征工程方法

    机器学习; 数据处理与特征工程; 特征选择实战建议; 8-65

    树模型

    • 对特征数值幅度不敏感,可以不进行无量纲化和统计变换处理;
    • 数模型特征依赖于样本距离来进行学习,可以不进行类别特征编码(但字符型特征不能直接作为输入,所以需要至少要进行标签编码)。
    • LightGBM 和 XGBoost 都能将缺失值作为数据的一部分进行学习,所以不需要处理缺失值。其他情况需要填充缺失。

    依赖样本距离的模型

    • 如线性回归、SVM、深度学习等属于这一类。
    • 对于数值型特征需要进行无量纲化处理。
    • 对于一些长尾分布的数据特征,可以做统计变换,使得模型能更好优化。
    • 对于线性模型,特征分箱可以提升模型表达能力。

    参考资料

    ShowMeAI系列教程推荐

    相关文章推荐

    展开全文
  • 机器学习入门讲解:什么是特征特征选择

    万次阅读 多人点赞 2017-10-30 14:00:27
    在machine learning (机器学习)中,特征工程是重中之重,我们今天就来简单介绍一下特征工程里面的feature(特征),以及feature selection (特征选择)。   首先我们来看看中文字典里是怎么解释特征的...


    2017-10-24  蒋竺波  随波竺流
    个人公众号:follow_bobo. 知乎号:波波。
    machine learning  (机器学习)中,特征工程是重中之重,我们今天就来简单介绍一下特征工程里面的 feature (特征),以及 feature selection ( 特征选择)。

     

    首先我们来看看中文字典里是怎么解释特征的:一事物异于其他事物的特点。

     

    那我们再来看看英文字典里是怎么解释feature的:A feature of something is an interesting or important part or characteristic of it.

     


    我们把这两个综合一下,特征就是,于己而言,特征是某些突出性质的表现,于他而言,特征是区分事物的关键,所以,当我们要对事物进行分类或者识别,我们实际上就是提取特征,通过特征的表现进行判断。好了,我们先来举个例子:

     

    Prof Fei-Fei Li 等人的论文里<CLEVR: A Diagnostic Dataset for Compositional Language and Elementary Visual Reasoning>, 他们为了更好的用Compositional Language(组合语言) 去描述一幅图,比如特点,数量,方位关系等,他们就会刻意去收集自己想要的feature,比如如下图所示,Cubes are gray, blue, brown, or yellowCylinders are red, green, purple,这些都是能突出自己性质的特征,浅绿色方体在最大红球的右边,这种也可以表征自己方位的特征。

     





    事物的特征非常多,但最终,提取的特征应该要服从我们的目的,还是拿上图举例子,假如我想知道有多少个立方体, 上来就把形状,颜色,大小等feature 全提了个遍是非常不明智的,这就是在浪费计算资源, 所以我们只需要选择形状这个feature就好啦。

    你可能会想,对啊,我一开始就只去提取形状这一个feature不就好了吗?这是因为你肉眼就可以做出判断了,但是,生活往往是艰难的,对于我们采集到的数据,很多情况下可能都不知道怎么去提取特征,或者我们需要去提取大量的feature来做分析。我再举个栗子,我曾经做过一个项目,是通过分析EEG (脑电波图)来查看病人是否得了癫痫,如果病人的癫痫发作,那么他的脑电波会出现一些不同寻常的变化,这些变化,我们称之为 ’spike’, 这个spike 就是癫痫病人的特征了,我们的目的,就是在EEG中把这些spike找出来。

     

    首先我们来看看病人EEG

     



    红色的波形就是spike,蓝色的波形就是正常的脑电波了,我们称之为‘background’,我们的目的就是要把backgroundspike分别出来。我们再来看几个spike的例子:

                

     



    以上是不同情况下病人突发癫痫症状的脑电波,可以看见spike变换无常,我们很难找到其中规律,因此我们只能尝试通过提取更高维的特征再让机器自己做分析。

     

    首先我提取了Peak,Nonlinear Energy Operator(NLEO), Discrete Wavelet Transform(DWT) 3类特征,每类6个特征(同种类特征参数不一样,提取的特征也不一样),共18个特征,得到的分类准确率只有76.25%,然后我又在原来的特征基础上做了一下尝试:

    • 特征类别不变,修改特征参数(比如修改特征频率),增加每种特征个数,共30种,测试的分类准确率为76.83%,这个情况提升只有0.6%

    •  增加特征类别,新增了如p2t, t2p等类别的特征,测试的分类准确率为72.3%,准确率不升反降。

    那么,我们就可以假设出一个结论:


    • 我们提取得特征中有冗余特征,对模型的性能几乎没有帮助。

    • 我们提取的特征中有些可以列为噪声(或者可以称为老鼠屎),对模型的性能不仅没有帮助,还会降低模型的性能。

    那么,我们很自然就会想到要进行feature selection(特征选择)。

     

    那么,我们接下来要讲的就是今天的主题啦,feature selection


     

    Q1: 我们为什么要进行feature selection?

    要是你从事过machine learning相关工作,肯定会发现一个问题,模型一样,算法一样,使用的机器,软件啊也一样,甚至连原始数据都一样,但最后训练得到的model效果还是有差别,这是为啥子咧?其中一个可能的原因,不同的model, 选取的特征不一样,效果也不一样。

     

    机器学习本质上就是针对一堆数据进行统计学的分析,最后得到的模型是根据分析的数据为基础的。所以,敲黑板!!feature selection 的本质就是对一个给定特征子集的优良性通过一个特定的评价标准(evaluation criterion)进行衡量.通过特征选择,原始特征集合中的冗余(redundant)特征和不相关(irrelevant)特征被除去。而有用特征得以保留。

     

    很多情况下,比如上面提到分析EEG来检测癫痫,我们并不知道要提取什么特征,所以我们会提取大量特征,少则几十,多则上亿,自己手中如果有上亿元那真是好东西,一分钱都不能扔,但是手上有上亿维的特征值,那就得先想办法把那些没用的垃圾特征统统扔掉,因为分析的是垃圾,结果也是垃圾。就像鲁迅所说:“sometimes, less is better.”



    好了,我们再来看看这个癫痫例子。我把所有的提取的特征数据都放进模型里进行训练(我这里用的是随机森林Random Forest,以后我会针对这些machine learning model做一个专门的解释和分析),testing 准确率为71%左右,下面是在同样的训练和测试数据情况下,针对某些特征进行单独训练和测试得到结果:


     

    可以明显的看到,不同的特征,结果还是差别很大的,如果我只用选取上图准确率最高的一类特征来训练模型,80.32%测试结果将比使用全部特征作为训练数据71%好不少,这个DWT-Approx(4-14Hz) db2,k=1 特征就相当于我们第一个例子中找正方体的‘形状’特征,即主要特征。那么针对未来的训练,我们可以尝试提取表现最好的几个特征就好了,这样我们就:


    • 降低了模型的复杂度,节省了大量计算资源以及计算时间。


    • 提高了模型的泛化能力。什么是泛化能力呢,我打个比方,一个模型是通过训 测,可是有些人长的就像噪声,对模型将会产生一定的影响,这样第一个模型的泛化能力就比第二个模型好不少,因为他不看脸,普适性更强。

     

    Q2: 有哪些feature selection的方法呢?

    通常来说,我们要从两个方面来考虑特征选择:

     

    •  特征是否发散:如果一个特征不发散,就是说这个特征大家都有或者非常相似,说明这个特征不需要。


    •  特征和目标是否相关:与目标的相关性越高,越应该优先选择。


    总得来说,特征选择有三种常用的思路:(以下的方法由于涉及到大量专业知识以及公式推演,全部说清楚篇幅较长,请读者们自己搜吧,网上都有)

     

    (1)特征过滤(Filter Methods:对各个特征按照发散性或者相关    性进行评分,对分数设定阈值或者选择靠前得分的特征。

      

      优点:简单,快。

     

      缺点:对于排序靠前的特征,如果他们相关性较强,则引入了冗   余特征,浪费了计算资源。 对于排序靠后的特征,虽然独立作   用不显著,但和其他特征想组合可能会对模型有很好的帮助,   这样就损失了有价值的特征。

     

      方法有:

    •   Pearson’s Correlation,:皮尔逊相关系数,是用来度量     两个变量相互关系(线性相关)的,不过更多反应两个服从     正态分布的随机变量的相关性,取值范围在 [-1,+1] 之       间。

    •   Linear Discriminant Analysis(LDA,线性判别分析):更     像一种特征抽取方式,基本思想是将高维的特征影到最佳鉴     别矢量空间,这样就可以抽取分类信息和达到压缩特征空     间维数的效果。投影后的样本在子空间有最大可分离性。

    •   Analysis of Variance:ANOVA,方差分析,通过分析研究不     同来源的变异对总变异的贡献大小,从而确定可控因素对研     究结果影响力的大小。

    •   Chi-Square:卡方检验,就是统计样本的实际观测值与理论     推断值之间的偏离程度,实际观测值与理论推断值之间的偏     离程 度就决定卡方值的大小,卡方值越大,越不符合;卡     方值越小,偏差越小,越趋于符合。


    (2)特征筛选(Wrapper Methods::通过不断排除特征或者不       断选择特征,并对训练得到的模型效果进行打分,通过预测       效果评 分来决定特征的去留。

     

       优点:能较好的保留有价值的特征。

     

       缺点:会消耗巨大的计算资源和计算时间。

     

      方法有:

    • 前向选择法:从0开始不断向模型加能最大限度提升模型效果的特征数据用以训练,直到任何训练数据都无法提升模型表现。





    • 后向剃除法:先用所有特征数据进行建模,再逐一丢弃贡献最低的特征来提升模型效果,直到模型效果收敛。



    • 迭代剃除法:反复训练模型并抛弃每次循环的最优或最劣特征,然后按照抛弃的顺序给特征种类的重要性评分。

     

    (3)嵌入法(Embedded Methods):有不少特征筛选和特征过滤的共性,主要的特点就是通过不同的方法去计算不同特征对于模型的贡献。

     

      方法:Lasso,Elastic Net,Ridge Regression,等。

      嵌入法需要涉及到大量的理论基础和公式,这里就不讨论了。

     

    实际上,特征工程实际上是一个非常大的概念,包括数据预处理,特征选择,降维等等。本篇文章仅做一个入门级的特征以及特征选取的讲解。后面我会对降维进行解析,因为降维在特征工程中也是重中之重。

     


    如要转载,请联系我。


     

     

     


    展开全文
  • 机器学习特征缩放、交叉验证)

    千次阅读 2021-11-12 21:40:38
    如果两个特征的量级相差非常大,一般会采取特征缩放,以缩短梯度下降训练模型改的时间,如下案例中的两个特征,最好采用特征缩放: 方式一:数据归一化 数据归一化就是把数据的取值范围处理为0~1或-1~1: ...

    特征缩放

            如果两个特征的量级相差非常大,一般会采取特征缩放,以缩短梯度下降训练模型改的时间,如下案例中的两个特征,最好采用特征缩放:

             方式一:数据归一化

            数据归一化就是把数据的取值范围处理为0~1或-1~1:

             方式二:均值标准化

     交叉验证

            这是一种测试方法,当数据的数据集比较小的时候,就不将数据单纯分为训练集和测试集,而是分成多份,比如切成10份,每次取9份作训练集,剩余一份作测试集,循环,可以得到10个误差,这十个误差的平均值作为输出:


              这是我学习 覃秉丰老师的《机器学习算法基础》的自学笔记,课程在B站中的地址为:机器学习算法基础-覃秉丰_哔哩哔哩_bilibili

    展开全文
  • 这里写目录标题数据的特征表示传统特征学习方法1.特征选择(Feature Selection)2.特征提取(Feature Extraction)3.优点深度特征学习方法 数据的特征表示 1.原始特征(Raw Feature)需要为向量形式。其存在以下不足...
  • 实时场景下的机器学习模型实时特征离线特征融合方案(踩坑指南)
  • 特征构建是指通过研究原始数据样本,结合机器学习实战经验和相关领域的专业知识,思考问题的潜在形式和数据结构,人工创造出新的特征,而这些特征对于模型训练又是有益的并且具有一定的工程意义。 特征构建的方式...
  • 机器学习特征工程

    千次阅读 2018-07-10 15:42:33
    1. 为什么做特征工程 我们学习编程语言时被告知程序=数据结构+算法,那么对于机器学习,我认为也可以类比为机器学习=大数据+机器学习算法+运行平台。面对一个机器学习问题,一般有两种解题思路:传统机器学习...
  • 作者:Eryk Lewinson 翻译:张睿毅 ...标签:数据帧,精选, 机器学习, Python, 技术演练设置和数据在本文中,我们主要使用非常知名的Python包,以及依赖于一个相对不为人知的scikit-lego包,这是一...
  • 机器学习-滑窗

    千次阅读 2022-03-18 16:26:26
    机器学习-滑窗
  • 回想一下,做机器学习我们的时间都花在了哪里?是训练模型。在训练模型阶段,有句话叫,模型训练好不好,数据大小很重要。在机器学习这里,数据经常就是这么神奇,模型预测效果不好,先别着急,没准多搞一点数据...
  • 机器学习中的特征工程总结!

    千次阅读 2020-10-17 20:13:44
    结构总览 特征工程 传统编程的关注点是代码。在机器学习项目中,关注点...许多机器学习模型都必须将特征表示为实数向量,因为特征值必须与模型权重相乘。 图 1. 特征工程将原始数据映射到机器学习特征 图 1 左..
  • 机器学习系列2 机器学习的公平性

    千次阅读 多人点赞 2022-04-15 19:23:43
    在本文中您将学习到 0 提高对机器学习中公平性重要性的认识。 1 了解与公平相关的危害 2 了解不公平评估和缓解措施。
  • 特征递归消除(RFE, recursive feature elimination)RFE 算法通过增加或移除特定特征变量获得能最大化模型性能的最优组合变量。RFE基本算法使用所有特征...
  • 转自寒老师的七月算法ML课程,加了一点自己理解# -*-...Created on Mon Oct 31 20:27:11 2016@author: Sirius特征工程之时间特征处理 """import pandas as pd data=pd.read_csv('kaggle_bike_competition_train.csv',
  • 距离上次介绍机器学习相关的内容,已经过了一年的时间了,而这篇博客目前的阅读量也将近3000k,这样数据看起来似乎也还算不错,可惜因为我当时没有足够的时间和精力去完整把这篇博客写完,只介绍了机器学习的基础...
  • 机器学习面试150题:不只是考SVM xgboost 特征工程

    万次阅读 多人点赞 2020-08-29 12:15:29
    本博客曾经在10~13年连续4年整理过各大公司数据结构和算法层面的笔试题、面试题,很快,2014年之后,机器学习大伙,很多公司开始招AI方面的人才,很多同学也会从网上找各种各样的机器学习笔试题、面试题,但和数据...
  • 特征工程是使用专业背景知识和技巧处理数据,使得特征能在机器学习算法上发挥更好的作用的过程。 更好的特征工程意味着更强的灵活度,更好的特征意味着只需用简单模型,更好的特征意味着更好的结果。 数据清洗 ...
  • 本篇讲解使用自动化特征工程工具Featuretools,对数据进行自动化特征工程的方法,并借助于BigMart Sales数据集来演示自动化特征工程的相关应用。
  • 机器学习建模流程

    千次阅读 2022-03-25 19:48:02
    机器学习实战 机器学习三把斧 1.数据清洗 1.1缺失值的处理 某一列的特征缺失值达到40%左右,删除这个特征值;或者某一个样本的缺失值过大,那么删除这个样本。 而当某个特征的缺失值较少的时候,不能删除这个特征...
  • 特征选择对于机器学习重要性

    千次阅读 2020-04-13 22:59:15
    特征选择对机器学习至关重要,个人认为在大部分机器学习任务中特征就决定了效果的上限,模型的选择与组合只是无限逼近于这个上限。 特征选择的主要作用包括:减少特征数量会防止维度灾难,减少训练时间;增强模型...
  • 机器学习期末考试

    万次阅读 多人点赞 2021-06-05 00:28:12
    机器学习期末考试 一、机器学习链接 1、机器学习期末复习试卷_zhouyan2000的博客-CSDN博客_机器学习期末考试} 2、[机器学习笔试题]((4条消息) 机器学习笔试题目_北冥有小鱼-CSDN博客_机器学习题目) 3、机器学习面试...
  • 时间复杂度o(n*k):n为样本数量,k为单个样本特征的维度。如果不考虑特征维度的粒度为o(n) 空间复杂度o(n*k):n为样本数量,k为单个样本特征的维度。如果不考虑特征维度的粒度为o(n) 参考: ...
  • 机器学习中的特征工程

    千次阅读 多人点赞 2018-12-06 20:26:04
    数据和特征决定了机器学习的上限,而模型和算法则是逼近这个上限。因此,特征工程就变得尤为重要了。特征工程的主要工作就是对特征的处理,包括数据的采集,数据预处理,特征选择,甚至降维技术等跟特征有关的工作。...
  • 机器学习入门——机器学习基础概念

    千次阅读 多人点赞 2020-03-15 17:02:02
    包括机器学习的主要任务,机器学习的分类等。 文章目录引言用到的数据机器学习的主要任务分类回归 用到的数据 鸢尾花(IRIS)是比较常见的在我们学习机器学习时用到的数据。数据来源: ...
  • 语音信号处理 语音特征提取 机器学习的语音处理
  • python 机器学习——特征筛选实现

    千次阅读 2020-08-22 09:43:07
    是指从已有的 M 个特征( Feature )中选择 N 个特征使得系统的特定指标最优化,是从原始特征中选择出一些最有效特征以降低数据集维度的过程,是提高学习算法性能的一个重要手段,也是模式识别中关键的数据预处理步骤。...
  • 本文种展示的特征传播是一种用于处理图机器学习应用程序中缺失的特征的有效且可扩展的方法。它很简单,但效果出奇地好。 图神经网络 (GNN) 模型通常假设每个节点都有一个完整的特征向量。以一个 2 层 GCN 模型 [1]...
  • 机器学习教程 - 分步指南

    千次阅读 2021-12-10 20:24:07
    机器学习 (ML)是技术领域最受关注的话题之一。如果你已经了解机器学习和相关技术的基础知识以及它的应用领域,本文将对这些知识进行补充。如果你还不熟悉机器学习,本教程中涵盖的基础知识会帮你快速上手。文章较长...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 181,273
精华内容 72,509
关键字:

时间特征 机器学习