机器学习-快速入门特征工程

736 阅读14分钟

目录

  • 数据集
    • 可用数据集

    • sklearn数据集

  • 特征提取
    • 字典

    • 文本

  • 特征预处理
    • 无量纲化
      • 归一化
      • 标准化
  • 特征降维
    • 特征选择

    • 主成分分析(PCA降维)

数据集

下面列举了一些示例来说明哪些内容能算作数据集:

  • 包含某些数据的表格或 CSV 文件

  • 组织有序的表格集合

  • 采用专有格式的文件,其中包含数据

  • 可共同构成某个有意义数据集的一组文件

  • 包含其他格式的数据的结构化对象,您可能希望将其加载到特殊工具中进行处理

  • 捕获数据的图像

  • 与机器学习相关的文件,如经过训练的参数或神经网络结构定义

  • 任何看来像数据集的内容

sklearn是一个Python第三方提供的非常强力的机器学习库,它包含了从数据预处理到训练模型的各个方面。在实战使用scikit-learn中可以极大的节省我们编写代码的时间以及减少我们的代码量,使我们有更多的精力去分析数据分布,调整模型和修改超参。(sklearn为包名)

特征提取

目标

  • 应用DictVectorizer实现对类别特征进行数值化、离散化

  • 应用CountVectorizer实现对文本特征进行数值化

  • 应用TfidfVectorizer实现对文本特征进行数值化

  • 说出两种文本特征提取的方式区别

定义

特征提取是将任意数据(如文本或图像)转换为可用于机器学习的数字特征

注:特征值化是为了计算机更好的去理解数据

  • 字典特征提取(特征离散化)

  • 文本特征提取

  • 图像特征提取(深度学习)

特征提取API

sklearn.feature_extraction

字典特征提取

作用:对字典数据进行特征值化

  • sklearn.feature_extraction.DictVectorizer(sparse=True,…)
    • DictVectorizer.fit_transform(X) X:字典或者包含字典的迭代器,返回值:返回sparse矩阵
    • DictVectorizer.inverse_transform(X) X:array数组或者sparse矩阵 返回值:转换之前数据格式
    • DictVectorizer.get_feature_names() 返回类别名称

应用

对以下数据进行特征提取

    data = [{'city': '北京', 'temperature': 100}, {'city': '上海', 'temperature': 60}, {'city': '深圳', 'temperature': 30}]

流程分析

  • 实例化类DictVectorizer

  • 调用fit_transform方法输入数据并转换(注意返回格式)

def dict_demo():
    """
    字典特征值提取
    :return:
    """
    data = [{'city': '北京', 'temperature': 100}, {'city': '上海', 'temperature': 60}, {'city': '深圳', 'temperature': 30}]
    # 1. 实例化一个转换器   默认返回 sparse矩阵  将非0值按位置表示出来 以节省内存 提高加载效率
    transfer = DictVectorizer(sparse=False)

    # 应用场景:数据集中类别特征值较多;将数据集的特征-》字典类型;DictVectorizer转换;本身拿到的就是字典

    # 2. 调用fit_transform()
    data_new = transfer.fit_transform(data)
    print("data_new:\n", data_new)
    print("特征名字:\n", transfer.get_feature_names())
    return None

注意观察没有加上sparse=False参数的结果

这个结果并不是想要看到的,所以加上参数,得到想要的结果,在这里把这个处理数据的技巧用专业的称呼"one-hot"编码。

总结

对于特征当中存在类别信息的都会做one-hot编码处理

文本特征提取

作用:对文本数据进行特征值化

  • sklearn.feature_extraction.text.CountVectorizer(stop_words=[])

    • 返回词频矩阵
  • CountVectorizer.fit_transform(X) X:文本或者包含文本字符串的可迭代对象 返回值:返回sparse矩阵

  • CountVectorizer.inverse_transform(X) X:array数组或者sparse矩阵 返回值:转换之前数据格

  • CountVectorizer.get_feature_names() 返回值:单词列表

  • sklearn.feature_extraction.text.TfidfVectorizer

应用

对以下数据进行特征提取

data = ["life is short, i like python", "life is too long i dislike python"]

流程分析

  • 实例化类CountVectorizer

  • 调用fit_transform方法输入数据并转换 (注意返回格式,利用toarray()进行sparse矩阵转换array数组)

def count_demo():
    """
    文本特征值抽取
    :return:
    """
    data = ["life is short, i like python", "life is too long i dislike python"]
    # 1、实例化一个转换器类
    transfer = CountVectorizer()
    # 演示停用词
    # transfer = CountVectorizer(stop_words=["is", "too"])
    data_new = transfer.fit_transform(data)

    print("data_new:\n", data_new.toarray())
    print("特征名字:\n", transfer.get_feature_names())
    # 2、调用fit_transform

    return None

问题:如果我们将数据替换成中文?

发现英文默认是以空格分开的。其实就达到了一个分词的效果,所以我们要对中文进行分词处理

下面代码需要提前把文本做好空格间隙

def count_chinese_demo():
    """
    中文文本特征值抽取
    :return:
    """
    data = ["我 爱 北京 天安门", "天安门 上 太阳 升"]
    data2 = ["我爱北京天安门", "天安门上太阳升"]
    # 1、实例化一个转换器类
    transfer = CountVectorizer()
    data_new = transfer.fit_transform(data)

    print("data_new:\n", data_new.toarray())
    print("特征名字:\n", transfer.get_feature_names())
    # 2、调用fit_transform

    return None

更好的处理方式见下方案

jieba分词处理

  • jieba.cut()
    • 返回词语组成的生成器

需要安装下jieba库

pip install jieba

案例分析

    data = ["在过去两个月里,我和60多位小伙伴进行了1对1的一小时沟通;",
            "TA绝大多数是想要尝试副业变现的朋友。",
            "从一线城市到三线城市,从宝妈到职场人,从职场到体制内。"]

分析

  • 准备句子,利用jieba.cut进行分词

  • 实例化CountVectorizer

  • 将分词结果变成字符串当作fit_transform的输入值

def count_word(text):
    """
    进行中文分词 我爱北京天安门-》我 爱 北京 天安门
    :param text:
    :return:
    """
    a = " ".join(list(jieba.cut(text)))
    print(a)
    return a


def count_chinese_demo2():
    """
    中文文本特征值抽取 自动分词
    :return:
    """
    data = ["在过去两个月里,我和60多位小伙伴进行了1对1的一小时沟通;",
            "TA绝大多数是想要尝试副业变现的朋友。",
            "从一线城市到三线城市,从宝妈到职场人,从职场到体制内。"]
    # 1、实例化一个转换器类
    transfer = CountVectorizer(stop_words=["从宝妈"])
    data_new = transfer.fit_transform(count_word(item) for item in data)

    print("data_new:\n", data_new.toarray())
    print("特征名字:\n", transfer.get_feature_names())
    # 2、调用fit_transform

    return None

问题:该如何处理某个词或短语在多篇文章中出现的次数高这种情况?

Tf-idf文本特征提取

TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。

TF-IDF作用:用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。

公式

词频(term frequency,tf)指的是某一个给定的词语在该文件中出现的频率

逆向文档频率(inverse document frequency,idf)是一个词语普遍重要性的度量。某一特定词语的idf,可以由总文件数目除以包含该词语之 文件的数目,再将得到的商取以10为底的对数得到

最终得出结果可以理解为重要程度。

注:假如一篇文件的总词语数是100个,而词语"非常"出现了5次,那么"非常"一词在该文件中的词频就是5/100=0.05。而计算文件频率(IDF)的方法是以文件集的文件总数,除以出现"非常"一词的文件数。所以,如果"非常"一词在1,000份文件出现过,而文件总数是10,000,000份的话,其逆向文件频率就是lg(10,000,000 / 1,0000)=3。最后"非常"对于这篇文档的tf-idf的分数为0.05 * 3=0.15

案例

def tfidf_demo():
    """
    用TF-IDF方法进行文本特征值抽取
    :return:
    """
    data = ["在过去两个月里,我和60多位小伙伴进行了1对1的一小时沟通;",
            "TA绝大多数是想要尝试副业变现的朋友。",
            "从一线城市到三线城市,从宝妈到职场人,从职场到体制内。"]
    transfer = TfidfVectorizer(stop_words=["从宝妈"])
    data_new = transfer.fit_transform(count_word(item) for item in data)

    print("data_new:\n", data_new.toarray())
    print("特征名字:\n", transfer.get_feature_names())
    return None

Tf-idf的重要性

分类机器学习算法进行文章分类中前期数据处理方式

特征预处理

目标

  • 了解数值型数据、类别型数据特点

  • 应用MinMaxScaler实现对特征数据进行归一化

  • 应用StandardScaler实现对特征数据进行标准化

什么是特征预处理

特征预处理:通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程

在这里插入图片描述 可以通过上面那张图来理解

包含内容

数值型数据的无量纲化:

  • 归一化

  • 标准化

特征预处理API

sklearn.preprocessing

为什么我们要进行归一化/标准化?

特征的单位或者大小相差较大,或者某特征的方差相比其他的特征要大出几个数量级,容易影响(支配)目标结果,使得一些算法无法学习到其它的特征

我们需要用到一些方法进行无量纲化,使不同规格的数据转换到同一规格

归一化

定义

通过对原始数据进行变换把数据映射到(默认为[0,1])之间

公式

作用于每一列,max为一列的最大值,min为一列的最小值,那么X’’为最终结果,mx,mi分别为指定区间值默认mx为1、mi为0

API

  • sklearn.preprocessing.MinMaxScaler (feature_range=(0,1)… )
    • MinMaxScalar.fit_transform(X)

      • X:numpy array格式的数据[n_samples,n_features]
    • 返回值:转换后的形状相同的array

数据计算

我们对以下数据进行运算,在dating.txt中。保存的就是之前的约会对象数据

milage,Liters,Consumtime,target
40920,8.326976,0.953952,3
14488,7.153469,1.673904,2
26052,1.441871,0.805124,1
75136,13.147394,0.428964,1
38344,1.669788,0.134296,1

分析

  • 实例化MinMaxScalar

  • 通过fit_transform转换

def minmax_demo():
    """
    归一化
    :return:
    """
    # 1、获取数据
    data = pd.read_csv("dating.txt")
    data = data.iloc[:, :3]
    print(data)

    # 2、实例化一个转换器类
    transform = MinMaxScaler()
    # transform = MinMaxScaler(feature_range=[2, 3])

    # 3、调用fit_transform
    data_new = transform.fit_transform(data)
    print("data_new:\n", data_new)
    return None

归一化总结

注意最大值最小值是变化的,另外,最大值与最小值非常容易受异常点影响,所以这种方法鲁棒性较差,只适合传统精确小数据场景。

标准化

定义

通过对原始数据进行变换把数据变换到均值为0,标准差为1范围内

公式

作用于每一列,mean为平均值,σ为标准差

所以回到刚才异常点的地方,我们再来看看标准化

  • 对于归一化来说:如果出现异常点,影响了最大值和最小值,那么结果显然会发生改变

  • 对于标准化来说:如果出现异常点,由于具有一定数据量,少量的异常点

  • 对于平均值的影响并不大,从而方差改变较小。

API

  • sklearn.preprocessing.StandardScaler( )
    • 处理之后每列来说所有数据都聚集在均值0附近标准差差为1
    • StandardScaler.fit_transform(X)
      • X:numpy array格式的数据[n_samples,n_features]
    • 返回值:转换后的形状相同的array

数据计算

同样对上面的数据进行处理

[[90,2,10,40],
[60,4,15,45],
[75,3,13,46]]

分析

  • 实例化StandardScaler

  • 通过fit_transform转换

def stand_demo():
    """
    进行标准化
    在已有样本足够多的情况下,适合现在嘈杂大数据场景
    :return:
    """
    # 1、获取数据
    data = pd.read_csv("dating.txt")
    data = data.iloc[:, :3]
    print(data)

    # 2、实例化一个转换器类
    transform = StandardScaler()

    # 3、调用fit_transform
    data_new = transform.fit_transform(data)
    print("data_new:\n", data_new)
    return None

标准化总结

在已有样本足够多的情况下比较稳定,适合现代嘈杂大数据场景。

特征降维

目标

  • 知道特征选择的嵌入式、过滤式以及包裹氏三种方式

  • 应用VarianceThreshold实现删除低方差特征

  • 了解相关系数的特点和计算

  • 应用相关性系数实现特征选择

降维

降维是指在某些限定条件下,降低随机变量(特征)个数,得到一组“不相关”主变量的过程

  • 降低随机变量的个数

  • 相关特征(correlated feature):相对湿度与降雨量之间的相关等等

正是因为在进行训练的时候,我们都是使用特征进行学习。如果特征本身存在问题或者特征之间相关性较强,对于算法学习预测会影响较大

降维的两种方式

  • 特征选择

  • 主成分分析(可以理解一种特征提取的方式)

特征选择

什么是特征选择

定义: 数据中包含冗余或无关变量(或称特征、属性、指标等),旨在从原有特征中找出主要特征。

方法:

  • Filter(过滤式):主要探究特征本身特点、特征与特征和目标值之间关联

    • 方差选择法:低方差特征过滤
    • 相关系数
  • Embedded (嵌入式):算法自动选择特征(特征与目标值之间的关联)

    • 决策树:信息熵、信息增益
    • 正则化:L1、L2
    • 深度学习:卷积等
  • Wrapper (包裹式)

模块

sklearn.feature_selection

过滤式

低方差特征过滤

删除低方差的一些特征,前面讲过方差的意义。再结合方差的大小来考虑这个方式的角度。

  • 特征方差小:某个特征大多样本的值比较相近

  • 特征方差大:某个特征很多样本的值都有差别

API

  • sklearn.feature_selection.VarianceThreshold(threshold = 0.0)
    • 删除所有低方差特征
    • Variance.fit_transform(X)
      • X:numpy array格式的数据[n_samples,n_features]
      • 返回值:训练集差异低于threshold的特征将被删除。默认值是保留所有非零方差特征,即删除所有样本中具有相同值的特征。

数据计算

我们对某些股票的指标特征之间进行一个筛选

一共这些特征

pe_ratio,pb_ratio,market_cap,return_on_asset_net_profit,du_return_on_equity,ev,earnings_per_share,revenue,total_expense
index,pe_ratio,pb_ratio,market_cap,return_on_asset_net_profit,du_return_on_equity,ev,earnings_per_share,revenue,total_expense,date,return
0,000001.XSHE,5.9572,1.1818,85252550922.0,0.8008,14.9403,1211444855670.0,2.01,20701401000.0,10882540000.0,2012-01-31,0.027657228229937388
1,000002.XSHE,7.0289,1.588,84113358168.0,1.6463,7.8656,300252061695.0,0.326,29308369223.2,23783476901.2,2012-01-31,0.08235182370820669
2,000008.XSHE,-262.7461,7.0003,517045520.0,-0.5678,-0.5943,770517752.56,-0.006,11679829.03,12030080.04,2012-01-31,0.09978900335112327
3,000060.XSHE,16.476,3.7146,19680455995.0,5.6036,14.617,28009159184.6,0.35,9189386877.65,7935542726.05,2012-01-31,0.12159482758620697
4,000069.XSHE,12.5878,2.5616,41727214853.0,2.8729,10.9097,81247380359.0,0.271,8951453490.28,7091397989.13,2012-01-31,-0.0026808154146886697
def variance_demo():
    """
    过滤低方差特征
    :return:
    """
    # 1、获取数据
    data = pd.read_csv("factor_returns.csv")
    data = data.iloc[:, 1: -2]
    print(data)

    # 2、实例化一个转换器
    transfer = VarianceThreshold(threshold=5)

    # 3、调用fit_transform
    data_new = transfer.fit_transform(data)
    print("data_new", data_new, data_new.shape)
    return None


if __name__ == '__main__':
    # 低方差特征过滤
    variance_demo()

相关系数

皮尔逊相关系数(Pearson Correlation Coefficient): 反映变量之间相关关系密切程度的统计指标

公式计算案例(了解,不用记忆)

公式:

比如说我们计算年广告费投入与月均销售额

= 0.9942

所以我们最终得出结论是广告投入费与月平均销售额之间有高度的正相关关系。   

特点

相关系数的值介于–1与+1之间,即–1≤ r ≤+1。其性质如下:

  • 当r>0时,表示两变量正相关,r<0时,两变量为负相关

  • 当|r|=1时,表示两变量为完全相关,当r=0时,表示两变量间无相关关系

  • 当0<|r|<1时,表示两变量存在一定程度的相关。且|r|越接近1,两变量间线性关系越密切;|r|越接近于0,表示两变量的线性相关越弱

一般可按三级划分:|r|<0.4为低度相关;0.4≤|r|<0.7为显著性相关;0.7≤|r|<1为高度线性相关

这个符号:|r|为r的绝对值, |-5| = 5

API

from scipy.stats import pearsonr
x : (N,) array_like
y : (N,) array_like Returns: (Pearson’s correlation coefficient, p-value)

主成分分析

目标

  • 应用PCA实现特征的降维

  • 应用:用户与物品类别之间主成分分析

什么是主成分分析(PCA)

定义:高维数据转化为低维数据的过程,在此过程中可能会舍弃原有数据、创造新的变量

作用:是数据维数压缩,尽可能降低原数据的维数(复杂度),损失少量信息。

应用:回归分析或者聚类分析当中

那么更好的理解这个过程呢?我们来看一张图

API

  • sklearn.decomposition.PCA(n_components=None)
    • 将数据分解为较低维数空间
    • n_components:
      • 小数:表示保留百分之多少的信息
      • 整数:减少到多少特征
    • PCA.fit_transform(X) X:numpy array格式的数据[n_samples,n_features]
    • 返回值:转换后指定维度的array

数据计算

[[2,8,4,5],
[6,3,0,8],
[5,4,9,1]]
def pca():
    """
    主成分分析进行降维
    :return:
    """
    # 信息保留70%
    pca = PCA(n_components=0.7)
    data = pca.fit_transform([[2, 8, 4, 5], [6, 3, 0, 8], [5, 4, 9, 1]])
    print(data)

    return None

案例:探究用户对物品类别的喜好细分降维

数据

  • order_products__prior.csv:订单与商品信息

    • 字段:order_id, product_id, add_to_cart_order, reordered
  • products.csv:商品信息

    • 字段:product_id, product_name, aisle_id, department_id
  • orders.csv:用户的订单信息

    • 字段:order_id,user_id,eval_set,order_number,….
  • aisles.csv:商品所属具体物品类别

    • 字段: aisle_id, aisle

分析

  • 合并表,使得user_id与aisle在一张表当中

  • 进行交叉表变换

  • 进行降维

def pca_case_study():
    """
    主成分分析案例
    :return: 
    """
    # 去读四张表的数据
    prior = pd.read_csv("./instacart/order_products__prior.csv")
    products = pd.read_csv("./instacart/products.csv")
    orders = pd.read_csv("./instacart/orders.csv")
    aisles = pd.read_csv("./instacart/aisles.csv")

    print(prior)

    # 合并四张表
    mt = pd.merge(prior, products, on=['product_id', 'product_id'])
    mt1 = pd.merge(mt, orders, on=['order_id', 'order_id'])
    mt2 = pd.merge(mt1, aisles, on=['aisle_id', 'aisle_id'])
    
    # pd.crosstab 统计用户与物品之间的次数关系(统计次数)
    cross = pd.crosstab(mt2['user_id'], mt2['aisle'])

    # PCA进行主成分分析
    pc = PCA(n_components=0.95)
    data_new = pc.fit_transform(cross)
    print("data_new:\n", data_new.shape)

    return None