AI学习---特征工程【特征抽取、特征预处理、特征降维】

学习框架

image

特征工程(Feature Engineering)

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

image

什么是特征工程:

帮助我们使得算法性能更好发挥性能而已

image

sklearn主要用于特征工程
pandas主要用于数据清洗、数据处理

image

特征工程包含如下3个内容:

      1、特征抽取/特征提取

             |__>字典特征抽取,应用DiceVectorizer实现对类别特征进行数值化、离散化

             |__>文本特征抽取,应用CounterVertorize/TfIdfVectorize实现对文本特征数值化

             |__>图像特征抽取(深度学习)

      2、特征预处理

              |_>归一化,应用MaxmixScaler,根据最小最大值进行放缩,默认范围0-1,容易受到异常值的影响,稳定性差,适合小规模

              |_>标准化,应用StandardScaler, 数据处理到指定的范围内,默认0~1

      3、特征降维

               |_>特征选择

               |_>PCI(主要内容分析)

 

1、特征抽取/特征提取

        我们常说的机器学习算法实际上就是我们统计学上的统计方法也就是我们数学上的数学公式

                           即 机器学习算法--》统计方法--》数学公式

        字典特征抽取的应用场景:
            1)pclass, sex 数据集当中类别特征比较多
                    1、将数据集的特征 转换为字典类型
                    2、利用DictVectorizer转换为二维数组
            2)本身拿到的数据就是字典类型

image

1- 字典特征提取:

      当我们调用sklearn.feature_extraction.DictVectorizer(sparse=True,…)的时候,实际上就是初始化了一个父类的转换器对象,然后调用实例进行fit_transform(X),进行字典和数值的转换。

image

      (下图)有多少行数据就有多少个向量(有方向和大小),向量在计算机中以矩阵存储(二维数组),而矩阵的行和列都可以看做一个一维数组。下图中一行数据可以看做一个向量,n个样本有n个向量,即将字典转换为了计算机识别的二维数组。每一个样本有2个特征(城市+temperature),正常应该返回一个3行2列的矩阵,但是字典特征抽取后,样本量没有变(3个样本),但是特征量变成了4个(当特征中有类别的时候,要想表示成数值,又想要公平的表示数据,我们采用one-hot编码,有3个类别,就占用3列,如果是北京,则第二列的特征值就是1,最后添加上temperature就是4个特征了)。

image

字典特征抽取DEMO:

from sklearn.feature_extraction.dict_vectorizer import DictVectorizer

# 字典特征提取
def dic_demo():
    data = [{'city': '北京', 'temperature': 100},
            {'city': '上海', 'temperature': 60},
            {'city': '深圳', 'temperature': 30}]
    # 1、实例化一个转换器对象
    # transform = DictVectorizer(sparse=True)  # 默认开启稀疏矩阵
    transform = DictVectorizer(sparse=False)   # 默认sparse=True,
    # 2、调用fit_transform()
    new_data = transform.fit_transform(data)
    # 3、获取特征名称
    print("特征名字:\n", transform.get_feature_names()) # 特征名字:['city=上海', 'city=北京', 'city=深圳', 'temperature']

    print('转换后的结果:\n', new_data)

    '''
     # sparse=True时候的new_data的值:返回的new_data是一个sparse的稀疏矩阵
      (0, 1)	1.0
      (0, 3)	100.0
      (1, 0)	1.0
      (1, 3)	60.0
      (2, 2)	1.0
      (2, 3)	30.0


     # sparse=True时候的new_data的值,返回的是一个二维数组

      [[  0.   1.   0. 100.]
       [  1.   0.   0.  60.]
       [  0.   0.   1.  30.]]

      # 总结:
           稀疏矩阵将非零值按位置表示出来,这样做可以节省内存 - 提高加载效率
    '''

if __name__ == '__main__':
    dic_demo()

结果截图:

image

附:  one-hot编码:

      对特征中的类别信息,为了公平的表示每一组样本数据,我们处理的时候,就是根据类别进行划分,样本中几个类别就有几列,是这个数据则置该列的数值为1,否则为0

image

  2- 文本特征提取:

  文本特征提取就是将单词、字母、短语作为主要的特征词进行特征提取

  可以利用如下方法统计:

       1. from sklearn.feature_extraction.text import CountVectorizer  ==》 根据分词进行数量统计继续文本分类

       2. from sklearn.feature_extraction.text import TfidfVectorizer    ==》 根据文章出现的词的占比(重要程度)进行文本分类

image

CountVectorizer:统计的是文本中出现的特征词次数,stop_words停用的停词表,toarray()可以转换为二维数组
image
 
文本特征提取—>英文的测试DEMO
from sklearn.feature_extraction.text import CountVectorizer

# 文本特征提取
def text_count_demo():
    data = ["life is short,i like like python", "life is too long, i dislike python"]
    # 1、实例化一个转换器类
    transfer = CountVectorizer()
    # transfer = CountVectorizer(stop_words=["is", "too"])
    '''
    不添加stop_words的效果:transfer = CountVectorizer()
        data_new:
         [[0 1 1 2 0 1 1 0]
         [1 1 1 0 1 1 0 1]]
        特征名字:
         ['dislike', 'is', 'life', 'like', 'long', 'python', 'short', 'too']
    
    
    添加stop_words的效果: transfer = CountVectorizer(stop_words=["is", "too"])
        data_new:
         [[0 1 2 0 1 1]
         [1 1 0 1 1 0]]
        特征名字:
         ['dislike', 'life', 'like', 'long', 'python', 'short']
            
    '''

    # 2、调用fit_transform
    data_new = transfer.fit_transform(data)
    # data_new返回的是一个sparse矩阵,
    print("矩阵_data_new:\n", data_new)
    # data_new.toarray()返回的是一个二维数组
    print("数组_data_new:\n", data_new.toarray())
    '''
        矩阵_data_new:
              (0, 5)	1
              (0, 3)	2
              (0, 6)	1
              (0, 1)	1
              (0, 2)	1
              (1, 0)	1
              (1, 4)	1
              (1, 7)	1
              (1, 5)	1
              (1, 1)	1
          (1, 2)	1
          
        数组_data_new.toarray():
             [[0 1 1 2 0 1 1 0]
             [1 1 1 0 1 1 0 1]]
    '''
    print("特征名字:\n", transfer.get_feature_names())

    return None


if __name__ =='__main__':
    text_count_demo()

文本特征提取—>中文的手动分词DEMO效果(这里是手动用空格进行的中文分词,麻烦):

from sklearn.feature_extraction.text import CountVectorizer
# 中文的需要进行分词,否则是以整句作为分词的
def chinese_text_count_demo():
    data = ["我爱北京天安门", "天安门上太阳升"]
    # data = ["我 爱 北京 天安门", "天安门 上 太阳 升"]  # 添加了空格的中文分词
    '''
    未添加空格的中文分词:
        data_new:
         [[0 1]
         [1 0]]
        特征名字:
         ['天安门上太阳升', '我爱北京天安门'] 
         
    添加了空格的中文分词:
         [[1 1 0]
         [0 1 1]]
        特征名字:
         ['北京', '天安门', '太阳']
    
    '''
    # 1、实例化一个转换器类
    transfer = CountVectorizer()

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

    return None

if __name__ =='__main__':
    chinese_text_count_demo()

文本特征提取—>中文的自动分词统计的DEMO效果

from sklearn.feature_extraction.text import CountVectorizer
import jieba

# pip3 install jieba
# 利用jieba可以进行jieba分词
def cut_word(text):
    """
    进行中文分词:"我爱北京天安门" --> "我 爱 北京 天安门"
    :param text:
    :return:
    """
    return " ".join(list(jieba.cut(text))) # jieba.cut(text)返回的是一个生成器对象,需要转换为迭代器


def auto_chinese_text_count_demo():
    data = ["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
            "我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
            "如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]

    data_new = []
    for sent in data:
        data_new.append(cut_word(sent))
    # print(data_new)
    # 1、实例化一个转换器类
    transfer = CountVectorizer(stop_words=["一种", "所以"])

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

    return None


if __name__ =='__main__':
    auto_chinese_text_count_demo()

image

附:”了解”在第三个数据中出现了4次。

CountVectorizer仅仅是根据特征名字出现的次数进行的文本分类,如果一个文本中的语气词出现了很多次,那最终统计的结果也不是很合适

2-文本特征抽取--TfidfVevtorizer

      写在前面:TfidfVevtorizer对分类机器学习算法进行文章分类中前期数据处理很重要

    在某一个类别的文章中,某些词出现的次数很多,但是在其他类别的文章当中出现很少,我们利用他们的重要程度进行分类,如下图我们就能看他们介绍的内容分别是共享车和经济证券。

image

TfidfVevtorizer衡量的就是一个词在文章中的重要程度

TfidfVevtorizer = TF + IDF

      --> TF   - 词频(term frequency,tf)
      --> IDF - 逆向文档频率(inverse document frequency, idf)

TF-IDF文本特征提取:

image

举个例子:

背景:
    假设现有两个关键词 “经济”,“非常”。
    现在我们的基础数据是1000篇文章的语料库。其中100篇文章"非常"一词出现的频率很高,10篇文章“经济”一词出现的频率很高。
计算公式
    TF(词频)  = 出现的频率/总词数
    IDF(逆向文档频率)= log 10 文件总数目/包含该词语的文件数目
    TF-IDF = TF * IDF
要求计算:
    现有两篇文章
    文章A(100词) : 10次“经济”   TF-IDF:0.2
        tf: 10/100 = 0.1
        idf:lg 1000/10 = 2  
    文章B(100词) : 10次“非常”   TF-IDF:0.1
        tf:10/100 = 0.1
        idf: log 10 1000/100 = 1

TF-IDF处理的API

image

TF-IDF处理的文本数据DEMO

from sklearn.feature_extraction.text import TfidfVectorizer
import jieba

# pip3 install jieba
# 利用jieba可以进行jieba分词
def cut_word(text):
    """
    进行中文分词:"我爱北京天安门" --> "我 爱 北京 天安门"
    :param text:
    :return:
    """
    return " ".join(list(jieba.cut(text))) # jieba.cut(text)返回的是一个生成器对象,需要转换为迭代器


def tf_idf_demo():
    data = ["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
            "我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
            "如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]

    data_new = []
    for sent in data:
        data_new.append(cut_word(sent))
    # print(data_new)
    # 1、实例化一个转换器类
    transfer = TfidfVectorizer(stop_words=["一种", "所以"])

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

    return None

if __name__ =='__main__':
    tf_idf_demo()

image

2、特征预处理

image

特征预处理:

    通过一些转换函数将特征数据转换为更适合算法模型的特征数据过程。

image

数值型数据的无量纲化(无量纲化,数学名词,是不同规格的数据转换到同一规格)

      --》 归一化: 根据最小最大值进行放缩,默认范围0-1,容易受到异常值的影响,稳定性差,只适合小规模的数据场景

      --》 标准化:  原始数据变化到0-1直接

特征预处理API:

      sklearn.preprocessing

image

image

1. 归一化

image

举个例子:

image

image

image

image

归一化的Demo

from sklearn.preprocessing import MinMaxScaler
import pandas as pd   # pandas是用于读取文本文件


# 归一化
def minmax_demo():
    """
    pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
    Pandas 纳入了大量库和一些标准的数据模型,
    提供了高效地操作大型数据集所需的工具。
    pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
    """
    # 1、获取数据
    data = pd.read_csv("dating.txt")
    data = data.iloc[:, :3]  # 目的是进行归一化,不需要目标值,txt文件第四列值是target
    print("data:\n", data)   # 读取的csv文件

    # 2、实例化一个转换器类
    transfer = MinMaxScaler(feature_range=[2, 3]) # 默认的feature_range是[0, 1]

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

    return None


if __name__ == '__main__':
    minmax_demo()

image

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
72993,10.141740,1.032955,1
35948,6.830792,1.213192,3
42666,13.276369,0.543880,3
67497,8.631577,0.749278,1
35483,12.273169,1.508053,3
50242,3.723498,0.831917,1
63275,8.385879,1.669485,1
5569,4.875435,0.728658,2
51052,4.680098,0.625224,1
77372,15.299570,0.331351,1
43673,1.889461,0.191283,1
61364,7.516754,1.269164,1
69673,14.239195,0.261333,1
15669,0.000000,1.250185,2
28488,10.528555,1.304844,3
6487,3.540265,0.822483,2
37708,2.991551,0.833920,1
22620,5.297865,0.638306,2
28782,6.593803,0.187108,3
19739,2.816760,1.686209,2
36788,12.458258,0.649617,3
5741,0.000000,1.656418,2
28567,9.968648,0.731232,3
2、标准化

image

image

image

标准化的测试Demo

from sklearn.preprocessing import StandardScaler
import pandas as pd   # pandas是用于读取文本文件


# 标准化
def standard_mode():
    """
    pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
    Pandas 纳入了大量库和一些标准的数据模型,
    提供了高效地操作大型数据集所需的工具。
    pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
    """
    # 1、获取数据
    data = pd.read_csv("dating.txt")
    data = data.iloc[:, :3]  # 目的是进行归一化,不需要目标值,txt文件第四列值是target
    print("data:\n", data)   # 读取的csv文件

    # 2、实例化一个转换器类
    transfer = StandardScaler()  # 默认的feature_range是[0, 1]

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

    return None


if __name__ == '__main__':
    standard_mode()
另: dating.txt详见附件

image

 

3、特征降维

      降维实际上就是降低特征的个数,最终的结果就是特征和特征之间不相关。

image

降维的2种方法

image

什么是特征选择

image

特征选择的2种方法(过滤式 + 嵌入式)

image

特征选择的2种方式:

过滤式:

    方差选择法: 可以过滤掉低方差的数据,例如用鸟类是否可以飞作为特征值是不合适的,此时的方差为0。

    相关系数法:目标是去除冗余,确定特征与特征之间的相关性。

嵌入式:

    决策树:

    正则化:

    深度学习:

降维方式一:特征选择--过滤式 --低方差过滤

image

删除低方差特征Demo

from sklearn.feature_selection import VarianceThreshold
from scipy.stats import pearsonr
import pandas as pd


def variance_demo():
    """
        过滤低方差特征
        :return:
        """
    # 1、获取数据
    data = pd.read_csv("factor_returns.csv")
    data = data.iloc[:, 1:-2]  # 所有行都要,列不显示最后2行
    print("data:\n", data)

    # 2、实例化一个转换器类
    transfer = VarianceThreshold(threshold=10)  # threshold代表临界值为10,默认为0

    # 3、调用fit_transform
    data_new = transfer.fit_transform(data)
    print("data_new:\n", data_new, data_new.shape)

    return None

if __name__ == '__main__':
    variance_demo()

image

factor_returns.csv  ==> 详见附件

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
5,000100.XSHE,10.796,1.5219999999999998,17206724233.0,2.245,7.7394,66034033386.1,0.0974,43883757748.0,43092263405.0,2012-01-31,0.13795588072275808
6,000402.XSHE,8.1032,1.0078,18253291248.0,3.2233,10.3965,56511787330.1,0.6,7303544153.27,5440677926.67,2012-01-31,0.08457869004968227
7,000413.XSHE,192.5234,18.3692,4270450000.0,-0.6423,-1.0375,4363236328.83,-0.0059,62630800.67,64784767.7,2012-01-31,0.11926833305744075

降维方式一:1、特征选择--过滤式--相关系数

image

image

image

image

过滤低方差特征 + 计算相关系数DEMO      

from sklearn.feature_selection import VarianceThreshold
from scipy.stats import pearsonr
import pandas as pd


def variance_demo():
    """
        过滤低方差特征 + 计算相关系数
        :return:
        """
    # 1、获取数据
    data = pd.read_csv("factor_returns.csv")
    data = data.iloc[:, 1:-2]  # 所有行都要,列不显示最后2行
    print("data:\n", data)

    # 2、实例化一个转换器类
    transfer = VarianceThreshold(threshold=10)  # threshold代表临界值为10,默认为0

    # 3、调用fit_transform
    data_new = transfer.fit_transform(data)
    print("data_new:\n", data_new, data_new.shape)

    # 计算某两个变量之间的相关系数
    r1 = pearsonr(data["pe_ratio"], data["pb_ratio"])
    print("相关系数:\n", r1)
    r2 = pearsonr(data['revenue'], data['total_expense'])
    print("revenue与total_expense之间的相关性:\n", r2)

    return None


if __name__ == '__main__':
    variance_demo()

image

image

 

过滤低方差特征 + 计算相关系数 + 画图DEMO

from sklearn.feature_selection import VarianceThreshold
from scipy.stats import pearsonr
import pandas as pd
import matplotlib.pyplot as plt

def variance_demo():
    """
        过滤低方差特征 + 计算相关系数
        :return:
        """
    # 1、获取数据
    data = pd.read_csv("factor_returns.csv")
    data = data.iloc[:, 1:-2]  # 所有行都要,列不显示最后2行
    print("data:\n", data)

    # 2、实例化一个转换器类
    transfer = VarianceThreshold(threshold=10)  # threshold代表临界值为10,默认为0

    # 3、调用fit_transform
    data_new = transfer.fit_transform(data)
    print("data_new:\n", data_new, data_new.shape)

    # 计算某两个变量之间的相关系数
    r1 = pearsonr(data["pe_ratio"], data["pb_ratio"])
    print("相关系数:\n", r1)
    r2 = pearsonr(data['revenue'], data['total_expense'])
    print("revenue与total_expense之间的相关性:\n", r2)

    # 离散图
    plt.figure(figsize=(20, 9), dpi=100)
    plt.scatter(data['revenue'], data['total_expense'])
    plt.show()
    return None


if __name__ == '__main__':
    variance_demo()

 

特征与特征之间相关性很高,可以采取:
            1)选取其中一个
            2)加权求和
            3)主成分分析

降维方式二:主成分分析(PCA)

image

image

imageimage

PCI用到的主要方法

image

PCA降维DEMO

from sklearn.decomposition import PCA

def pca_demo():
    """
    PCA降维
    :return:
    """
    data = [[2,8,4,5], [6,3,0,8], [5,4,9,1]]

    #  1、实例化一个转换器类
    #  transfer = PCA(n_components=2)   # 整数:将3维转换为2维
    transfer = PCA(n_components=0.95)   # 小数:保留95%的信息

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

image

 

案例:探究用户对物品分类的喜好 --instacart市场篮子分析案例

image

案例分析:探究用户对物品类别的喜好细分:
    首先我们需要【用户,user_id】和【物品类别, aisle】2个关键参数
    1)需要将user_id和aisle放在同一个表中 –> 合并
    2)找到user_id和aisle关系                 -->  交叉表和透视表
    3)特征冗余过多                              --> PCA降维

image

安装Anaconda3,点击下载

       安装可参考:https://www.jianshu.com/p/026a2c43b081

点击运行:

image

此时会帮我们打开一个浏览器界面:点击new->Python3,然后就可以进行编程了(Ctrl + Enter,进行文件变异)

image

image

 

案例DEMO

import pandas as pd
from sklearn.decomposition import PCA

def demo():
    '''
    分析:
         1、 获取数据
         2、 合并表
         3、 找到UserId和Iias之间的关系
         4、 进行PCA降唯

    :return:
    '''

    # 1. 获取数据
    aisles = pd.read_csv("F:\instacart\\aisles.csv")
    orders = pd.read_csv("F:\instacart\\orders.csv")
    order_products__prior = pd.read_csv("F:\instacart\\order_products__prior.csv")
    products = pd.read_csv("F:\instacart\\products.csv")

    '''
     2 合并表(目标是UserID和Iisas进行机器学习)

     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
    '''
    # 合并aisles和products aisle的aisle_id
    tab1 = pd.merge(aisles, products, on=["aisle_id", "aisle_id"])

    # 合并tab1和order_products__prior的product_id
    tab2 = pd.merge(tab1, order_products__prior, on=['product_id', 'product_id'])

    # 合并tab2和orders的order_id
    tab3 = pd.merge(tab2, orders, on=['order_id', 'order_id'])

    # 3、 找到UseID和aisle直接的关系(交叉表)
    table = pd.crosstab(tab3['user_id'], tab3['aisle'])

    data = table[:100]

    # 4、 降低维度
    # 4-1:实例化一个转换器对象,保留95%的信息
    transfer = PCA(n_components=0.95)
    # 4-2: 调用fit_transform()
    data_new = transfer.fit_transform(data)

    # 5、结果

    print('data_new', data_new)   # 100个样本数据降低维度后的特征值
    print('data_new.shape', data_new.shape)  # 100个数据有100多个特征,降维后剩余19个

 

表合并过程:

image

结果:

image

其他

代码和资料下载:

链接:https://pan.baidu.com/s/14vBcB3o5wjef_7lYb7WrSQ
提取码:td8n

posted @ 2019-03-08 21:49  小a玖拾柒  阅读(5154)  评论(0编辑  收藏  举报