数据清洗和特征工程


“让模型变得更好”得数据处理方式,都可以认为是做特征工程
是否需要做特征工程,需要在开发中不断地尝试还是经验性积累吧,此篇文本了解一下就可以

什么是特征工程

使用专业的背景知识合技巧,使得特征能在机器学习算法上发挥更好的作用过程
会直接影响机器学习的效果

常规的特征工程需要处理的内容

  • 异常数据处理
    • 出现异常数据,不如大部分数据在1~10之间,个别数据远远超过这个区域,是不是要考虑数据错误?可以尝试摘除这样的离群数据
    • 统计缺失值方法,是按行统计,还是按列统计?
    • 比如数据缺失,但是对于缺失值解决方式还是要具体问题具体分析是删去,还是填充,填充的话怎么填充,均值?平均值?中值?
    • 如果在数据的Y值(目标值)出现缺失怎么办?直接删除(大部分情况)?重新人工标注?
    • 数据特征一模一样,但是标签不一样,就要考录是不是标注错误?收集错误?
  • 数据不平衡处理(多出现在分类算法)
    • 上采样(数据增强):实质是采用:数据增强的方式,将数据变多
    • 下采样(会损失数据):从多类别的数据中采样一部分出来用于训练
  • 文本处理
    • 文本向量化:词袋法,TF-IDF,w2v(词向量化),DOC2V(文本向量化)
  • 多项式拓展,哑编码,标准化,归一化,区间缩放,PAC,特征选择….
    • 多项式拓展:解决欠拟合,增加特征,增加特征维度,注意并不是说维度越高越好
  • 将均值、方差、协方差等信息作为特征属性,对特征属性进行对数转换,质数转换
  • 结合业务衍生出一些新的特征属性
    • 比如知道房子的长宽,可以增加面积特征属性
    • 比如对出生年月日转换成年龄等

数据清洗

  • 工具:关系型数据库,python
  • 数据预处理
    • 查看数据元素以及数据特征,计算方差,均值等了解数据等
  • 格式内容错误清洗
    • 格式内容不一致,对格式与内容进行清洗操作
  • 逻辑错误清洗
    • 数据去重
    • 去除/替换不合理的值
    • 去除/重构不可靠的字段(修改矛盾内容)
  • 去除不需要的数据
    • 冗余,不必要特征去除
  • 数据关联性
    • 例如通过手机号和省份证号匹配的车辆信息是一样的

数据清洗实例——数据缺失值填充(sklearn调包实现)

  • 工具
    • python科学计算库:pandas
    • form sklearn.preprocessing import Inputer(低版本:可以设置行,列填参数充)
    • from sklearn.impute import SimpleImputer(高版本,不可设置,自动默认按行填充)
  • sklearn提供的填充方式
    • 均值填充 mean
    • 中值填充 median
    • 众数填充 most_frequent

填充时注意fit,和transform,fit_transform的用法

import numpy as np
#from sklearn.preprocessing import Imputer (低版本) 如果这个到不进来修改成下面的
from sklearn.impute import SimpleImputer
'''
preprocessing 预处理
Imputer 对数据进行填充
'''
X1 = [
    [2,2,4,1],
    [np.nan,3,4,4],
    [1,1,1,np.nan],
    [2,2,np.nan,3]
]
X1 = np.array(X1)
X2 = [
    [2,6,np.nan,1],
    [np.nan,5,np.nan,1],
    [4,1,np.nan,5],
    [np.nan,np.nan,np.nan,1]
]
X2 = np.array(X2)
#自动按照列进行填充值的计算(计算每个特征属性的填充值)(一般使用这种填充方式)
imp = SimpleImputer(missing_values=np.nan,strategy='mean',copy=False)#这里设置填充值strategy = mean均值
imp2 = SimpleImputer(missing_values=np.nan,strategy='median',copy=False)#这里设置填充值strategy = median中位数
imp3 = SimpleImputer(missing_values=np.nan,strategy='most_frequent',copy=False)#这里设置填充值strategy = most_frequent众数

#先对训练数据fit,得到针对训练集获得的填充值(均值,中值,众数)调用不同的对象传入参数
imp.fit(X1)
print('每列填充值',imp.statistics_)#查看计算出来的每一列的填充值,也可以记录
#然后,当有新数据进来时,transform,按照训练集计算的数据进行填充(比如说上面fit后,计算出填充的数据是10,那么新数据进来时,需要填充的地方依然填充10)
print('X1填充后\n',imp.transform(X1))
#用X1的计算结果对X2进行填充
print('X2填充后\n',imp.transform(X2))

输出:
在这里插入图片描述


归一化和标准化

最终目的——>去量纲
什么时候要进行归一化/标准化

  • 特征的单位挥着大小相差较大,或者某特征的方差比其他特征要大出几个数量级,容易影响目标结果,使得一些算法,无法学习到其他特征。
  • 用一些方法对数据特征进行 “无量纲化”,使不同规格的数据装换到同一规格。

归一化(区间缩放)

  • 通过对原始数据进行压缩变换,映射到[mi ~ mx](默认[0~1])之间

在这里插入图片描述
实质上是对数据进行了一点的压缩

注意:数据中异常点多,进行归一化,会影响整体数据,目标结果会受影响
在进行归一化压缩数据的过程中,是受特征最大值与最小值的影响的,然而最大值与最小值又很容易受到异常点的影响(异常值很可能就称为最大最小值),所以这种数据预处理方法鲁棒性差适合传统精确、小数据场景
归一化不是任何场景都适用

  • 对训练数据做归一化时,实际上也有两种操作
    • fit()
      • 作用是:找到训练数据中的max,min
    • transform()

当有一条新的数据X进来以后,做transform(X)用的依然是训练数据中的max,min(同上边的异常值处理fit,transform一样)
所以,要求做归一化的训练数据要尽可能的多,尽可能对数据的整体有一个代表

所以我们也不知道训练数据有没有代表性,是否有异常值(可以做异常值的清洗),具体情况还是要具体分析,归一化试试效果咋样。

标准化

对原始数据进行变换,把数据转换成均值为0,标准差为1(方差为1) 的数据
即:数据满足正太分布
在这里插入图片描述
通过上的公式可见,对数据进行标准化方式对数据进行压缩,而标准化的值由所有数据决定,受所有数据的影响,因为数据具有一定的数量,少量的异常值对均值和方差的改变较小,故:
标准化一定程度上可以解决归一化中对异常值敏感的问题

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


归一化标准化实例(sklearn调包实现)

归一化

import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler
X = np.array([[1,-1,2,3],[2,0,0,3],[0,1,-10,3]],dtype=np.float64)

#实例化对象
scaler = MinMaxScaler(feature_range=(0,1))#映射到0~1区间上
#对训练数据fit(),求出每一列特征中的Max,Min
scaler.fit(X)
#原始特征属性的最大值
print('原始特征属性的最大值\n',scaler.data_max_)
#原始数据特征的最小值
print('原始数据特征的最小值\n',scaler.data_min_)
#原始数据特征的最大值减最小值
print('原始数据特征的最大值-最小值\n',scaler.data_range_)
#查看归一化前统计性描述数据的信息
print('归一化前统计性描述数据的信息\n',pd.DataFrame(X).describe())
#根据训练数据得到的max,min对数据进行transform归一化
print('数据归一化\n',scaler.transform(X))
#可以发现如果在收集一列特征的时候,他的方差为0,那么做归一化后,这一列特征都为0,说明这一列特征的数据都一样,则这一列特征没什么用,或者说,有一列特征的方差非常的接近,波动性小,说明这一列数据几乎一样,那么,这样的特征就要考虑是否要舍弃
#查看归一化后统计性描述数据的信息
print('归一化后统计性描述数据的信息\n',pd.DataFrame(scaler.transform(X)).describe())
#可以发现归一化后更容易看见数据的特征关系

可以发现如果在收集一列特征的时候,他的方差为0,那么做归一化后,这一列特征都为0,说明这一列特征的数据都一样,则这一列特征没什么用,或者说,有一列特征的方差非常的接近,波动性小,说明这一列数据几乎一样,那么,这样的特征就要考虑是否要舍弃。

输出:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

标准化

import numpy as np
from sklearn.preprocessing import StandardScaler
X = np.array([[1,2,3,2],[7,8,9,2.01],[4,8,2,2.01],[9,5,2,1.99],[7,5,3,1.99],[1,4,9,2]],dtype=np.float64)
x_test = np.array([[12,11,13,12],[5,6,7,9]],dtype=np.float64)#测试数据集
#实例化对象
ss = StandardScaler(with_mean=True,with_std=True)
#训练数据X,得到训练数据集的均值和方差
ss.fit(X)
#查看训练集的均值和方差
print('X的每列特征的均值',ss.mean_)
print('X的每列特征的标准差',ss.scale_)
print('样本数量',ss.n_samples_seen_)

#用训练集得到的均值和方差对X做transform标准化
print('对X做transform标准化\n',ss.transform(X))
#用训练集得到的均值和方差对x_test做transform标准化
print('对x_test做transform标准化\n',ss.transform(x_test))

输出:
在这里插入图片描述


特征提取

  • 将任意数据(文本,图像)转换成可用于机器学习的数字特征
    • 字典特征提取(特征离散化)
    • 文本特征提取
    • 图像特征提取(一般图片本身就是一个数组)
    • 音频特征提取

字典数据特征提取(sklearn)

如果收集的数据是一个字典的形式,可以直接用sklearn对字典数据特征进行的提取

  • fit_transform对所有数据进行fit,在进行tranform
  • 对字典中的字符型特征进行类似onehot,对数值型特征保留
from sklearn.feature_extraction import DictVectorizer
data = [{'city':'北京','气温':10},{'city':'上海','气温':20},{'city':'深圳','气温':30}]

#实例化一个转换器
transfer = DictVectorizer(sparse=False)
#调用fit_transform()
data = transfer.fit_transform(data)
#打印返回结果
print('打印返回结果\n',data)
print('特征名字\n',transfer.get_feature_names())

在这里插入图片描述

One-Hot

一般,对离散特征数据(类别型)——有可能是字符串,也有可能是数值型
工具:

from sklearn.preprocessing import OneHotEncode#只能做数值型类别亚编码
pd.get_dummies(object)#可以做数值型类别,也可以做字符型类别亚编码

注意:

  • OneHotEncode 要求数据类别必须是数值型
    • categorical_features :给定对那些列进行亚编码操作,默认是对所有数据
enc = OneHotEncode(categorical_features=[1,2])#对索引1,2列特征进行亚编码
* n_valuse :明确给定各个特征属性的类别数目,因为是数值型,其实就是(最大值-最小值+1)
enc = OneHotEncode(n_valuse=[3,3,4])#第一个编码特征属性为3个类,第二个编码特征属性为3个类,第三个编码特征属性为4个类,
import numpy as np
import pandas as pd
from sklearn.preprocessing import OneHotEncoder
#实例化对象
enc = OneHotEncoder(categories=[3,3,3])#定义各个列的类别数量
a = np.array([[0,0,3],[2,1,0],[0,2,1],[1,0,1],[1,1,1]])

enc.fit(a)
print(a)
print('编码结果:\n',enc.categories_)
enc.transform([[1,2,2],[2,2,2]]).toarray()

print(enc.transform(a).toarray())


'''如果类别数据时字符串类型的,可以使用pandas的API进行亚编码转化'''

a = pd.DataFrame([
    ['a', 1, 2],
    ['b', 1, 1],
    ['a', 2, 1],
    ['c', 1, 2],
    ['c', 1, 2]
], columns=['c1', 'c2', 'c3'])
#对字符串类别数据进行亚编码
a = pd.get_dummies(a)
print(a)

分词,TF-IDF,关键词提取

结巴分词

#引入模块
#这里分词我们运用结巴分词
import jieba
#初始化结巴模型,初始化以后,即加载了结巴模型,之后再利用结巴进行分词的时候,就不用加载,会提高分词速度
words_a='上海自来水来自海上,所以吃葡萄不吐葡萄皮'
'''全模式分词,只要是词,就分出来,字词可以多次使用'''
seg_a = jieba.cut(words_a,cut_all=True)#全模式分词,返回值是一个对象的名字和地址
print("全模式:","/".join(seg_a))
'''精确模式'''
seg_b=jieba.cut(words_a)
print("精确模式:")
print(list(seg_b))
'''搜索引擎模式'''
seg_c = jieba.cut_for_search(words_a)
print("搜索引擎模式","/".join(seg_c))

seg_l = jieba.lcut(words_a)
print(seg_l)

输出:

在这里插入图片描述

  • 添加和删除自定义词汇和隐马尔可夫模型的运用
words_a1='我为机器学习疯狂打call,大(家好)吗'
jieba.del_word("打call") # 删除单词,在后续的分词的时候,被删除的不会认为是一个单词
print("自定义前:","/".join(jieba.cut(words_a1)))
jieba.add_word("打call") # 添加单词,在后续的分词中,遇到到的时候,会认为是属于同一个单词
print("加入‘打call’后:","/".join(jieba.cut(words_a1)))
jieba.add_word("机器学习")
print(jieba.lcut(words_a1))
jieba.del_word("打call")
print(jieba.lcut(words_a1))
jieba.add_word("大(家好)吗") # 失效
print(jieba.lcut(words_a1))

  • 调整词典,关闭HMM发现新词功能(主要在开发过程中使用)
#调整词典,关闭HMM发现新词功能(主要在开发过程中使用)
print('/'.join(jieba.cut('如果放到post中将出错。', HMM=False)))
print('/'.join(jieba.cut('如果放到post中将出错。', HMM=True)))
jieba.suggest_freq(('中', '将'), True)
print("--------------------------")
print('/'.join(jieba.cut('如果放到post中将出错。', HMM=False)))
print('/'.join(jieba.cut('如果放到post中将出错。', HMM=True)))
print('/'.join(jieba.cut('「台中」正确应该不会被切开', HMM=False)))
jieba.suggest_freq('台中', True)
print('/'.join(jieba.cut('「台中」正确应该不会被切开', HMM=False)))

关键词获取

TF-IDF越大的词越有可能称为关键词

# 获取TF-IDF最大的5个单词   textrank 提取关键词
import jieba.analyse
words_a2='在正义者联盟的电影里,嘻哈侠和蝙蝠侠联手打败了大boss,我高喊666,为他们疯狂打call'
jieba.analyse.extract_tags(words_a2,topK=5,withWeight=True)

停用词的过滤

有时候在构建词袋的时候,要先对分词以后的文本进行停用词guolv,已达到降低特征维度的目的

# 先分词,再过滤
stop_words = ["的","了",","]
words_a2='在正义者联盟的电影里,嘻哈侠和蝙蝠侠联手打败了大boss,我高喊666,为他们疯狂打call'
result_l = jieba.lcut(words_a2)
print(result_l)
result_f = [word for word in result_l if word not in stop_words]
print(result_f)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

企鹅家的北极熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值