[深度学习]Part2 数据清洗和特征工程Ch06——【DeepBlue学习笔记】

2023-11-03

本文仅供学习使用

数据清洗和特征工程Ch06


1. 特征工程

所有一切为了让模型效果变的更好的数据处理方式都可以认为属于特征工程这个范畴中的一个操作;
至于需求做不做这个特征工程,需要我们在开发过程中不断的进行尝试。

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

  • 异常数据的处理 (行/列删除) —— 见1.2.1.3
  • 数据不平衡处理(上/下采样——改变少数样本的占比、特征增强)
  • 文本处理:词袋法、TF-IDF (文本向量化、W2V、D2V、Emdding)
  • 视频/图片数据:本身为一组数组、即数值特征
  • 语音:信号处理(滤波、梅尔倒谱、傅里叶变换)
  • 多项式扩展、哑编码、标准化、归一化、区间缩放法、PCA、特征选择…
  • 将均值、方差、协方差等信息作为特征属性,对特征属性进行对数转换、指数转换…
  • 结合业务衍生出一些新的特征属性…(出生日期衍生出年龄/年代)

1.1 特征工程介绍

为什么需要特征工程(Feature Engineering)
机器学习领域的大神Andrew Ng(吴恩达)老师说“Coming up with features is difficult, time-consuming, requires expert knowledge. ‘Applied machine learning’ is basically feature engineering. ”
业界广泛流传:数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。

什么是特征工程
特征工程是使用专业背景知识和技巧处理数据,使得特征能在机器学习算法上发挥更好的作用的过程。 意义:会直接影响机器学习的效果

1.2 特征预处理

1.2.1 数据清洗

数据清洗(data cleaning)是在机器学习过程中一个不可缺少的环节,其数据的清洗结果直接关系到模型效果以及最终的结论。在实际的工作中,数据清洗通常占开发过程的30%-50%左右的时间

1.2.1.1 数据清洗—预处理

在数据预处理过程主要考虑两个方面,如下:

  1. 选择数据处理工具:关系型数据库或者Python
  2. 查看数据的元数据以及数据特征:一是查看元数据,包括字段解释、数据来源等一切可以描述数据的信息;另外是抽取一部分数据,通过人工查看的方式,对数据本身做一个比较直观的了解,并且初步发现一些问题,为之后的数据处理做准备。

1.2.1.2 数据清洗—格式内容错误数据清洗

一般情况下,数据是由用户/访客产生的,也就有很大的可能性存在格式和内容上不一致的情况,所以在进行模型构建之前需要先进行数据的格式内容清洗操作。格式内容问题主要有以下几类:

  1. 时间、日期、数值、半全角等显示格式不一致:直接将数据转换为一类格式即可,该问题一般出现在多个数据源整合的情况下。
  2. 内容中有不该存在的字符:最典型的就是在头部、中间、尾部的空格等问题,这种情况下,需要以半自动校验加半人工方式来找出问题,并去除不需要的字符。
  3. 内容与该字段应有的内容不符:比如姓名写成了性别、身份证号写成手机号等问题。(正则表达式re/长度验证len)(注意脱敏问题)

1.2.1.3 数据清洗—逻辑错误清洗

主要是通过简单的逻辑推理发现数据中的问题数据,防止分析结果走偏,主要包含以下几个步骤:

  1. 数据去重
  2. 去除/替换不合理的值
  3. 去除/重构不可靠的字段值(修改矛盾的内容)

1.2.1.4 数据清洗—去除不需要的数据

一般情况下,我们会尽可能多的收集数据,但是不是所有的字段数据都是可以应用到模型构建过程的,也不是说将所有的字段属性都放到构建模型中,最终模型的效果就一定会好,实际上来讲,字段属性越多,模型的构建就会越慢,所以有时候可以考虑将不要的字段进行删除操作。在进行该过程的时候,要注意备份原始数据。

若增加数据,则对过拟合/欠拟合都有一定的改善作用

1.2.1.5 数据清洗—关联性验证

如果数据有多个来源,那么有必要进行关联性验证,该过程常应用到多数据源合并的过程中,通过验证数据之间的关联性来选择比较正确的特征属性,比如:汽车的线下购买信息和电话客服问卷信息,两者之间可以通过姓名和手机号进行关联操作,匹配两者之间的车辆信息是否是同一辆,如果不是,那么就需要进行数据调整。

1.2.1.5 数据清洗—案例:数据缺省值填充

python科学计算库 from sklearn.impute import SimpleImputer
所填充的值并非真实值,但所训练的模型并非一定缺失真实性——好的模型具有鲁棒性
• 均值填充
• 中值填充
• 众数填充
• 0填充
• 常数填充(与具体情况相关)

class sklearn.impute.SimpleImputer(*, missing_values=nan, strategy=‘mean’, fill_value=None, verbose=0, copy=True, add_indicator=False)
missing_values: int, float, str, (默认)np.nan或是None, 即缺失值是什么。
strategy: 空值填充的策略,共四种选择(默认)mean、median、most_frequent、constant。mean表示该列的缺失值由该列的均值填充。median为中位数,most_frequent为众数。constant表示将空值填充为自定义的值,但这个自定义的值要通过fill_value来定义。
fill_value: str或数值,默认为Zone。当strategy == “constant"时,fill_value被用来替换所有出现的缺失值(missing_values)。fill_value为Zone,当处理的是数值数据时,缺失值(missing_values)会替换为0,对于字符串或对象数据类型则替换为"missing_value” 这一字符串。
verbose: int,(默认)0,控制imputer的冗长。
copy: boolean,(默认)True,表示对数据的副本进行处理,False对数据原地修改。
add_indicator: boolean,(默认)False,True则会在数据后面加入n列由0和1构成的同样大小的数据,0表示所在位置非缺失值,1表示所在位置为缺失值。

import numpy as np
# from sklearn.preprocessing import Imputer  # 旧版本
from sklearn.impute import SimpleImputer  # 新版本
X = [
    [2, 2, 4, 1],
    [np.nan, 3, 4, 4],
    [1, 1, 1, np.nan],
    [2, 2, np.nan, 3]
]
X2 = [
    [2, 6, np.nan, 1],
    [np.nan, 5, np.nan, 1],
    [4, 1, np.nan, 5],
    [np.nan, np.nan, np.nan, 1]
]
# 按照列进行填充值的计算(计算每个特征属性的填充值)(一般使用这种填充方式)
imp1 = SimpleImputer(missing_values=np.nan, strategy='mean')

# 如果以列进行数据填充的时候,是计算每个特征属性的填充值分别是什么
imp1.fit(X)  # 返回值为SimpleImputer()类

# 当axis=0的时候,获取每个特征的计算出来的填充值
print(imp1.statistics_)
print('\n')
print(imp1.transform(X))
print('\n')
print(imp1.fit_transform(X))  # 相当于fit() + transform()


imp1 = SimpleImputer(missing_values=np.nan, strategy='mean')  # 均值
imp2 = SimpleImputer(missing_values=np.nan, strategy='median')  # 中位数
imp3 = SimpleImputer(missing_values=np.nan, strategy='most_frequent')  # 众数
imp1.fit(X)
imp2.fit(X)
imp3.fit(X)
print(imp1.transform(X))
print(imp2.transform(X))
print(imp3.transform(X))

imp4 = SimpleImputer(missing_values=np.nan, strategy='constant',fill_value=1)  # 常数
print(imp4.fit_transform(X))

fit:针对训练集(model)
transform:训练+测试
fit_transform:训练集

1.2.2 归一化和标准化

特征的单位或者大小相差较大,或者某特征的方差相比其他的特征要大出几个数量级, 容易影响(支配)目标结果,使得一些算法无法学习到其它的特征
我们需要用到一些方法进行无量纲化,使不同规格的数据转换到同一规格

1.2.2.1 归一化

from sklearn.preprocessing import MinMaxScaler
通过对原始数据进行变换把数据映射到(默认为[0,1])之间:

X ′ = x − x min ⁡ x max ⁡ − x min ⁡ {X}'=\frac{x-{{x}_{\min }}}{{{x}_{\max }}-{{x}_{\min }}} X=xmaxxminxxmin

X ′ ′ = X ′ ⋅ ( max ⁡ − min ⁡ ) + min ⁡ X''=X'\cdot (\max -\min )+\min X′′=X(maxmin)+min (其中,max与min为映射区间的上界和下界)

若最大值等于最小值——该特征数据一致,无意义

思考:如果数据中异常点较多(离群),会有什么影响?
注意最大值最小值是变化的,另外,最大值与最小值非常容易受异常点影响,所以这种方法鲁棒性较差,只适合传统精确小数据场景。

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))
scaler.fit(X)

# 原始特征属性的最大值
print(scaler.data_max_)
# 原始特征属性的最小值
print(scaler.data_min_)
# 原始特征属性的取值范围大小(最大值-最小值)
print(scaler.data_range_)

print(scaler.transform(X))


import pandas as pd
print(pd.DataFrame(X).describe())
print(pd.DataFrame(scaler.transform(X)).describe())

1.2.2.2 标准化

from sklearn.preprocessing import StandardScaler
通过对原始数据进行变换把数据变换到均值为0,标准差为1范围内:

X ′ = x − m e a n σ {X}'=\frac{x-mean}{\sigma } X=σxmean

对于归一化来说:如果出现异常点,影响了最大值和最小值,那么结果显然会发生改变对于标准化来说:如果出现异常点,由于具有一定数据量,少量的异常点对于平均值的影响并不大,从而方差改变较小。
在已有样本足够多的情况下比较稳定,适合现代嘈杂大数据场景

同样,若标准差/方差为零,其数据也无意义。

from sklearn.preprocessing import StandardScaler
X = [
    [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]
]
x_test = [
    [12,11,13,12],
    [5,6,7,9]
]

ss = StandardScaler(with_mean=True, with_std=True)
ss.fit(X)
# 计算每个特征属性的均值
print(ss.mean_)
print(ss.n_samples_seen_)
# 输出每个特征属性的方差
print(ss.scale_)
# 相当于对训练集做一个数据转换
print(ss.transform(X))
# 相当于对测试集做一个数据转换
print(ss.transform(x_test))

import pandas as pd
print(pd.DataFrame(X).describe())
print(pd.DataFrame(ss.transform(X)).describe())

1.3 特征提取

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

  1. 字典特征提取(特征离散化) :from sklearn.feature_extraction import DictVectorizer(onehot)
from sklearn.feature_extraction import DictVectorizer

data = [{'city': '北京','temperature':10}, {'city': '上海','temperature':20}, {'city': '深圳','temperature':30}]
# 1、实例化一个转换器类
transfer = DictVectorizer(sparse=False)
# 2、调用fit_transform
data = transfer.fit_transform(data)
print("返回的结果:\n", data)
# 打印特征名字
print("特征名字:\n", transfer.get_feature_names())

onehotfrom sklearn.preprocessing import OneHotEncoder

class sklearn.preprocessing.OneHotEncoder(*, categories='auto', drop=None, sparse=True, dtype=<class 'numpy.float64'>, handle_unknown='error')
handle_unknown: {‘error’, ‘ignore’}, default=’error’ 在转换过程中遇到未知分类特征时,是引发错误还是忽略(默认为引发)。当此参数设置为“ignore”并且在转换过程中遇到未知类别时,这一特征的 one-hot 编码列将全置为 0。在逆变换中,未知类别将表示为 None

import numpy as np
from sklearn.preprocessing import OneHotEncoder
# OneHotEncoder要求数据类别必须是数值的
# class sklearn.preprocessing.OneHotEncoder(*, categories='auto', drop=None, sparse=True, dtype=<class 'numpy.float64'>, handle_unknown='error')
## -- categorical_features:给定对那些列的数据进行哑编码操作,默认是对所有类数据做
## -- n_values:明确给定各个特征属性的类别数目,其实是最大值-最小值+1
### ---- enc = OneHotEncoder(categorical_features=[1,2])
### ---- enc = OneHotEncoder(n_values=[3, 3, 4])
# -- handle_unknown='error' / 'ignore'
# -- drop:编码方式 'first'  'if_binary'

enc = OneHotEncoder(drop='first')
a=np.array([[0, 0, 3], 
            [2, 1, 0], 
            [0, 2, 1], 
            [1, 0, 1],
            [1, 1, 1]])
enc.fit(a) 
print(a)
print("编码类别",enc.categories_)
print(enc.transform(a).toarray())


enc2 = OneHotEncoder(drop='if_binary')
a=np.array([[0, 0, 3], 
            [2, 1, 0], 
            [0, 2, 1], 
            [1, 0, 1],
            [1, 1, 1]])
enc2.fit(a) 
print("编码类别",enc2.categories_)
print(enc2.transform(a).toarray())

enc3 = OneHotEncoder()
a=np.array([[0, 0, 3], 
            [2, 1, 0], 
            [0, 2, 1], 
            [1, 0, 1],
            [1, 1, 1]])
enc3.fit(a) 
print("编码类别",enc3.categories_)
print(enc3.transform(a).toarray())
# 如果类别数据是字符串类型的,可以使用pandas的API进行哑编码转换
import pandas as pd

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)
  1. 文本特征提取 :
    pip3 install jieba
    中文jieba分词处理——马尔可夫模型

集成百度LAC:python -m pip install --user paddlepaddle -i https://pypi.tuna.tsinghua.edu.cn/simple

import jieba
# 集成百度LAC
# jieba.enable_paddle()
jieba.initialize() # 初始化分词模型

words_a='上海自来水来自海上,所以吃葡萄不吐葡萄皮'
seg_a=jieba.cut(words_a,cut_all=True)
print("全模式:","/".join(seg_a))
seg_b=jieba.cut(words_a)
print(seg_b)  # 可迭代对象
print("精确模式:","/".join(seg_b))
seg_c=jieba.cut_for_search(words_a)
print("搜索引擎模式","/".join(seg_c))

seg_l = jieba.lcut(words_a)
print(seg_l)  # 以列表形式输出
seg_l = jieba.lcut(words_a,use_paddle=True)  #  python -m pip install --user paddlepaddle -i https://pypi.tuna.tsinghua.edu.cn/simple 
print(seg_l)  # 以列表形式输出
seg_b=jieba.cut(words_a)
for w in seg_b:
    print(w)

#添加和删除自定义词汇
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))

# #导入自定义词典
# jieba.del_word("打call")#删除之前添加的词汇
words_a2='在正义者联盟的电影里,嘻哈侠和蝙蝠侠联手打败了大boss,我高喊666,为他们疯狂打call'
# print("加载自定义词库前:","/".join(jieba.cut(words_a2)))
# jieba.load_userdict("./datas/01mydict.txt")
# print("--------VS--------")
# print("加载自定义词库后:","/".join(jieba.cut(words_a2)))

#获得切词后的数据
ls1=[]
for item in jieba.cut(words_a2):
    ls1.append(item)
print(ls1)
##用lcut直接获得切词后的list列表数据
ls2=jieba.lcut(words_a2)
print(ls2)

# 调整词典,关闭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最大的5个单词
import jieba.analyse
words_a2='在正义者联盟的电影里,嘻哈侠和蝙蝠侠联手打败了大boss,我高喊666,为他们疯狂打call'
ansy = jieba.analyse.extract_tags(words_a2,topK=5,withWeight=True)
print(ansy)


##  停用词过滤
# 先分词,再过滤
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)

词袋法 、TF-IDF:from sklearn.feature_extraction.text import TfidfVectorizer,CountVectorizer,TfidfTransformer(Gension)

import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer,CountVectorizer,TfidfTransformer

arr1 = [
    "This is spark, spark sql a every good",
    "Spark Hadoop Hbase",
    "This is sample",
    "This is anthor example anthor example",
    "spark hbase hadoop spark hive hbase hue oozie",
    "hue oozie spark"
]
arr2 = [
    "this is a sample a example",
    "this c c cd is another another sample example example",
    "spark Hbase hadoop Spark hive hbase"
]
df = arr2

# 相当于词袋法
count = CountVectorizer(min_df=0.1, dtype=np.float64, ngram_range=(0,1))
# CountVectorizer 的作用是将文本文档转换为计数的稀疏矩阵
df1 = count.fit_transform(df)
print (df1.toarray())
print (count.get_stop_words())
print (count.get_feature_names())  # 哪些单词进行了统计
print ("转换另外的文档数据")
print (count.transform(arr1).toarray())
print(df1)  # 稀疏矩阵形式

# 基于TF的值(词袋法),做一个IDF的转换
tfidf_t = TfidfTransformer()
df2 = tfidf_t.fit_transform(df1)
print (df2.toarray())
print ("转换另外的文档数据")
print (tfidf_t.transform(count.transform(arr1)).toarray())

## 相当TF+IDF(先做词袋法再做IDF转换)
tfidf_v = TfidfVectorizer(min_df=0, dtype=np.float64)
df3 = tfidf_v.fit_transform(df)
print (df3.toarray())
print (tfidf_v.get_feature_names())
print (tfidf_v.get_stop_words())
print ("转换另外的文档数据")
print (tfidf_v.transform(arr1).toarray())
  1. 图像特征提取(一般图片本身就是个数组数据)

1.4 特征降维

降维是指在某些限定条件下,降低随机变量(特征)个数,得到一组“不相关”主变量的过程
正是因为在进行训练的时候,我们都是使用特征进行学习。如果特征本身存在问题或者特征之间相关性较强,对于算法学习预测会影响较大。通过特征提取(feature extraction)进行降维的目的就是对原特征集 P original {{P}_{\text{original}}} Poriginal进行变换,变换后的新特征集记为 P new {{P}_{\text{new}}} Pnew,这里 P original > P new {{P}_{\text{original}}}>{{P}_{\text{new}}} Poriginal>Pnew,但是 P new {{P}_{\text{new}}} Pnew保留了原特征集的大部分信息。换句话说,就是通过牺牲一小部分数据信息来减少特征的数量,并且保证还能作出准确的预测。
降维的两种方式: 特征选择 、主成分分析(可以理解一种特征提取的方式)

1.4.1 特征选择

数据中包含冗余或无关变量(或称特征、属性、指标等),旨在从原有特征中找出主要特征。
抽取——减少列数

特征选择的方法主要有以下三种:(人工取值除外)
Filter: 过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,从而选择特征;常用方法包括方差选择法相关系数法卡方检验互信息法等。
Wrapper: 包装法,根据目标函数(通常是预测效果评分),每次选择若干特征或者排除若干特征;常用方法主要是递归特征消除法
Embedded: 嵌入法,先使用某些机器学习的算法和模型进行训练,得到各个特征的权重系数,根据系数从大到小选择特征;常用方法主要是基于惩罚项的特征选择法。

1.4.1.1 特征选择-方差选择法

from sklearn.feature_selection import VarianceThreshold

创建VarianceThreshold对象:thresholder = VarianceThreshold(threshold=0.1)
创建大方差特征矩阵:features_high_variance = thresholder.fit_transform(features)
显示大方差特征矩阵:features_high_variance
可以通过参数variances_来查看每个特征的方差:eatures_high_variance.variances_
方差选择法: 亦称方差阈值化(Variance Thresholding,VT)先计算各个特征属性的方差值,然后根据阈值,获取方差大于阈值的特征

import numpy as np
import warnings

from sklearn.feature_selection import VarianceThreshold

X = np.array([
    [0, 2, 0, 3],
    [0, 1, 4, 3],
    [0.1, 1, 1, 3]
], dtype=np.float32)
Y = np.array([1,2,1])

# 基于方差选择最优的特征属性
variance = VarianceThreshold(threshold=0.1)
print(variance)
variance.fit(X)
print("各个特征属性的方差为:")
print(variance.variances_)
print('-----------------')
print(variance.transform(X))

采用VT方法使需要注意两点:

  • 方差不是中心化的(它的单位是特征单位的平方),因此,如果特征数据集中特征的单位不同,那么VT法就无法起作用。
  • 方差的阈值是手动选择的,所以必须依靠人工来选择一个合适的阈值

1.4.1.2 特征选择-相关系数法

from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_regression
相关系数法:先计算各个特征属性对于目标值的相关系数以及阈值K,然后获取 K 个相关系数最大的特征属性。(备注:根据目标属性y的类别选择不同的方式)

import numpy as np
import warnings

from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_regression

X = np.array([
    [0, 2, 0, 3],
    [0, 1, 4, 3],
    [0.1, 1, 1, 3]
], dtype=np.float32)
Y = np.array([1,2,1])
## 相关系数法
sk1 = SelectKBest(f_regression, k=2)
sk1.fit(X, Y)
print(sk1)
print('------------')
print(sk1.scores_)
print('------------')
print(sk1.transform(X))

1.4.1.3 特征选择-卡方检验

from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
卡方检验:检查定性自变量对定性因变量的相关性 χ 2 = ∑ ( A − E ) 2 E {{\chi }^{2}}=\sum{\frac{{{(A-E)}^{2}}}{E}} χ2=E(AE)2

import numpy as np
import warnings

from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
X = np.array([
    [0, 2, 0, 3],
    [0, 1, 4, 3],
    [0.1, 1, 1, 3]
], dtype=np.float32)
Y = np.array([1,2,1])
## 卡方检验
# 使用chi2的时候要求特征属性的取值为非负数
sk2 = SelectKBest(chi2, k=2)
sk2.fit(X, Y)
print(sk2)
print(sk2.scores_)
print(sk2.transform(X))

卡方统计可以检查两个分类向量的相互独立性,也就是说,卡方统计量代表了观察到的样本数量和期望的样本数量(假设特征与目标向量无关)之间的差异;卡方统计的结果是一个数值,通过计算特征和目标向量的卡方统计量,可以得到对两者之间独立性的度量值。SelectKBest方法来选择最好的特征,其中参数k决定了要保留的特征数量。

卡方统计量只能在两个分类数据之间进行计算,所以使用卡方统计进行特征选择时,目标向量和特征都必须时分类数据。对于数值型特征,可以将其转换为分类特征后再使用卡方统计,且所有值必须时非负的。

根据分类的目标向量,删除信息量较低的特征。

前三者为过滤法(1.4.1.1~1.4.1.3)

1.4.1.4 特征选择-递归特征消除法

from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
递归特征消除法:使用一个基模型来进行多轮训练,每轮训练后,消除若干权值系数的特征,再基于新的特征集进行下一轮训练。
自动选择需要保留的最有特征
Wrapper-递归特征消除法

import numpy as np
import warnings
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
X = np.array([
    [0, 2, 0, 3],
    [0, 1, 4, 3],
    [0.1, 1, 1, 3]
], dtype=np.float32)
Y = np.array([1,2,1])
# 基于特征消去法做的特征选择
estimator = LogisticRegression()
selector = RFE(estimator, 2, step=5)
selector = selector.fit(X, Y)
print(selector.support_)
print(selector.n_features_)
print(selector.ranking_)
print(selector.transform(X))

from sklearn.feature_selection import RFECV
REFCV类通过交叉验证(Crossing Validation,CV) 进行 递归式特征消除(Recursive Feature Elimination,REF)。该方法会重复训练模型,每一次训练一处一个特征,直到模型性能(精度)变差,剩余的特征就是最优特征。REF背后的思想是重复训练一个包含若干参数(也称为权重或系数)的模型,在该方法中假设特征已经进行过标准化处理。

1.4.1.5 特征选择 嵌入法-基于惩罚项的特征选择法

from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
使用基于惩罚项的基模型,进行特征选择操作。

import numpy as np
import warnings
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
## Embedded【嵌入法】-基于惩罚项的特征选择法
X2 = np.array([
    [ 5.1,  3.5,  1.4,  0.2],
    [ 4.9,  3. ,  1.4,  0.2],
    [ -6.2,  0.4,  5.4,  2.3],
    [ -5.9,  0. ,  5.1,  1.8]
], dtype=np.float64)
Y2 = np.array([0, 0, 2, 2])
estimator = LogisticRegression(penalty='l2', C=0.1)
# estimator = LogisticRegression(penalty='l2', C=0.1,solver = 'liblinear')
sfm = SelectFromModel(estimator,threshold=0.1)
sfm.fit(X2, Y2)
print(sfm.transform(X2))
print("系数:")
print(sfm.estimator_.coef_)

1.4.2 训练模型(PCA 与 LDA)

对于KNN算法而言,需要假设任意测试样本x附近任意小的δ距离范围内总能找到一个训练样本,即训练样本的采样密度足够大,或称为密采样(dense sample)。——当属性维度增大时,若样本满足密采样条件,所需的样本数目是无法达到的天文数字(δ=0.001),并且计算内积/距离也会带来很大的麻烦——高维数据样本稀疏——维度灾难(curse of dimensionality)——降维(dimension reduction),亦称维度简约

通过某种数学变换将原始高维属性空间转变为一个低维子空间(subspace)——高维空间中的一个低维嵌入(embedding)

多维缩放(Multiple Dimensional Scaling,简称MDS)——某种特征值分解

基于线性变换来进行降维的方法称为线性降维方法,若要求低维子空间对样本具有最大可分性,则将得到一种极为常用的线性降维方法;

对降维效果的评估通常是比较降维前后学习器的性能,若性能有所提高则认为降维起到了作用,若将维数降至二维/三维,则可通过可视化技术来直观地判断降维效果

当特征选择完成后,可以直接可以进行训练模型了,但是可能由于特征矩阵过大,导致计算量比较大,训练时间长的问题,因此降低特征矩阵维度也是必不可少的(牺牲了一些评估指标与特征描述)。常见的降维方法除了基于L1的惩罚模型外,还有主成分析法(PCA)线性判别分析法(LDA),这两种方法的本质都是将原始数据映射到维度更低的样本空间中(矩阵变化);但是采用的方式不同,PCA是为了让映射后的样本具有更大的发散性,PCA是无监督的学习算法,LDA是为了让映射后的样本有最好的分类性能,LDA是有监督学习算法。

  • 其他方法

对非负矩阵进行降维:非负矩阵分解法(Non-Negative Matrix Factorization,NMF),是一种无监督的线性降维方法,特征矩阵就不能包含负数值,而且不会告诉我们输出特征中保留了原始数据的信息量,因此需要不断尝试一系列可能的值;
对稀疏特征矩阵进行特征降维操作:截断奇异值分解(Truncated Singular Value Decomposition,TSVD),与PCA相比TSVD的优势在于适用于稀疏矩阵,但是其输出值的符号会在多次拟合中不断变换;

1.4.2.1 PCA原理

PCA(Principal Component Analysis)是常用的线性降维方法,是一种无监督的降维算法。算法目标是通过某种线性投影,将高维的数据映射到低维的空间中表示,并且期望在所投影的维度上数据的方差最大(最大方差理论),以此使用较少的数据维度,同时保留较多的原数据点的特性。

通俗来讲的话,如果将所有点映射到一起,那么维度一定降低下去了,但是同时也会将几乎所有的信息(包括点点之间的距离等)都丢失了,而如果映射之后的数据具有比较大的方差,那么可以认为数据点则会比较分散,这样的话,就可以保留更多的信息。从而我们可以看到PCA是一种丢失原始数据信息最少的无监督线性降维方式

在这里插入图片描述
在这里插入图片描述
在PCA降维中,数据从原来的坐标系转换为新的坐标系,新坐标系的选择由 数据本身的特性决定。第一个坐标轴选择原始数据中方差最大的方向,从统计角度来讲,这个方向是最重要的方向;第二个坐标轴选择和第一个坐标轴垂直或者正交的方向;第三个坐标轴选择和第一个、第二个坐标轴都垂直或者正交的方向;该过程一直重复,直到新坐标系的维度和原始坐标系维度数 目一致的时候结束计算。而这些方向所表示的数据特征就被称为“主成分”

用一个超平面(直线的高维推广)对所有样本进行恰当的表达:

  • 最近重构性:样本点到这个超平面的距离都足够近
  • 最大可分性:样本点在这个超平面上的投影尽可能分开

1.4.2.2 特征选取/降维-PCA

from sklearn.decomposition import PCA

创建可以保留99%信息量(用方差表示)的PCA:pca = PCA(n_components=0.99,whiten=True)
执行PCA:features_pca = pca.fit_transform(feature)
显示结果:
print('Original number of features:',features.shape[1])
print(Reduced number of features:',features_pca.shape[1])

主成分析(PCA): 是一种流行的线性降维方法。将高纬的特征向量合并称为低纬度的特征属性,将雅本数据映射到特征矩阵的主成分空间,只考虑特征矩阵而不需要目标向量的信息,是一种无监督的降维方法
降维后低维空间的维度d’通常是有用户事先指定,或通过在d’值不同的低维空间中对k近邻分类器(或其他开销较小的分类器)进行交叉验证来选取较好的d‘值。

## PCA降维
from sklearn.decomposition import PCA
X2 = np.array([
    [ 5.1,  3.5,  1.4,  0.2, 1, 23],
    [ 4.9,  3. ,  1.4,  0.2, 2.3, 2.1],
    [ -6.2,  0.4,  5.4,  2.3, 2, 23],
    [ -5.9,  0. ,  5.1,  1.8, 2, 3]
], dtype=np.float64)
# n_components: 给定降低到多少维度,但是要求该值必须小于等于样本数目/特征数目,如果给定的值大于,那么会选择样本数目/特征数目中最小的那个作为最终的特征数目(小数为奇异值的和的占比)
# whiten:是否做一个白化的操作,在PCA的基础上,对于特征属性是否做一个标准化——对每一个主成分都进行转换以保证它们的平均值为0、方差为1
# svd_solver = 'randomized',代表使用随机方法找到第一个主成分(这种方法通常速度很快)
pca = PCA(n_components=0.8,whiten=True)
pca.fit(X2)
print(pca.mean_)
print(pca.components_)
print(pca.transform(X2))

PCA仅需保留W*与样本的均值向量即可通过简单的向量减法和矩阵-向量乘法将新样本投影至低维空间中,显然,低维空间与原始高维空间必有不同,因为对应于最小的 d-d’ 个特征值的特征向量被舍弃了,这是降维导致的结果,但舍弃这部分信息往往是必要的:一方面,舍弃这些部分信息之后能使样本的采样密度增大,这正是降维的重要动机;另一方面,当数据收到噪声影响时,最小的特征值所对应的特征向量往往与噪声有关,将它们舍弃能在一定程度起到去噪的效果

对于线性不可分数据进行降维——Kernel PCA(核主成分分析)
from sklearn.decomposition import PCA,KernelPCA
应用基于径向基函数(Radius Basis Function,RBF)核的Kernel PCA方法:
kpca = KernelPCA(kerbek='rbf', gamma=15, n_components=1)
features_kpca = kpca.fit_transform(features)

标准PCA使用线性映射减少特征的数量。如果数据是线性可分的(也就是说可以用一条直线或者超平面将两类数据分开),那么PCA处理的效果就会很好。然而,如果数据不是线性可分的,那么线性变换的效果就不会很好。如果使用线性PCA对数据进行降维,则两类数据会被线性映射到第一个主成分上,因而会交织在一起;理想情况下,我们希望维度变换既能降低数据的维度,又可以使数据变得线性可分Kernel PCA 可以做到这两点。

核(kernel,也叫核函数)能够将线性不可分数据映射到更高的维度,数据在这个维度是线性可分的,我们把这种方式叫做核机制(kernel trick)。常用的核函数是高斯径向基函数(rbf),其他核函数还有多项式核(poly)sigmoid核(sigmoid),或者一个线性(linear) 映射

Kernel PCA的一个缺点是需要指定很多参数,且必须指定参数的数量(n_components),且每个核都有自己的超参数需要设置(如径向基函数需要设置gamma)

1.4.2.3 LDA原理

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

创建并运行LDA,然后用它对特征做变换:
lda = LinearDiscriminantAnalysis(n_components=1)
feature_lda = lda.fit(features, target).transfprm(features)
可以使用参数 explained_variance_ratio_来查看每个成分保留的信息量(即数据的差异)的情况:lda.explained_variance_ratio_,该排序数组表示每个输出的特征所保留的信息量(用方差表示)

LDA的全称是Linear Discriminant Analysis(线性判别分析),是一种有监督学习算法。
在这里插入图片描述

LDA的原理是,将带上标签的数据(点),通过投影的方法,投影到维度更低的空间中,使得投影后的点,会形成按类别区分,一簇一簇的情况,相同类别的点,将会在投影后的空间中更接近。用一句话概括就是:“投影后类内方差最小,类间方差最大”

## LDA降维
import numpy as np
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
X = np.array([
    [-1, -1, 3, 1], 
    [-2, -1, 2, 4], 
    [-3, -2, 4, 5], 
    [1, 1, 5, 4], 
    [2, 1, 6, -5], 
    [3, 2, 1, 5]])
y = np.array([1, 1, 2, 2, 0, 1])
# n_components:给定降低到多少维度,要求给定的这个值和y的取值数量有关,不能超过n_class-1
clf = LinearDiscriminantAnalysis(n_components=3)
clf.fit(X, y)
print(clf.transform(X))

1.4.2.4 PCA和LDA

相同点:
• 两者均可以对数据完成降维操作
• 两者在降维时候均使用矩阵分解的思想
• 两者都假设数据符合高斯分布
不同点:
• LDA是监督降维算法,PCA是无监督降维算法
• LDA降维最多降到类别数目 k-1 的维数,而PCA没有限制
• LDA除了降维外,还可以应用于分类
• LDA选择的是分类性能最好的投影,而PCA选择样本点投影具有最大方差的方向
在这里插入图片描述
在PCA中,只需关注使数据差异最大化的成分轴;LDA中,找到使得类间差异最大的成分轴

1.4.3 特征选择/降维

在实际的机器学习项目中,特征选择/降维是必须进行的,因为在数据中存在以下几个方面的问题:

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

通过降维的目的是:

  1. 减少特征属性的个数
  2. 确保特征属性之间是相互独立的
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[深度学习]Part2 数据清洗和特征工程Ch06——【DeepBlue学习笔记】 的相关文章

  • 是否可以模拟 Python 3.6 中的内置 len() 函数?

    是否可以模拟内置len Python 3 6 中的函数 我有一个类定义了一个简单的方法 该方法依赖于len 函数如下 class MyLenFunc object def is longer than three characters se
  • PyList_SetItem 与 PyList_SETITEM

    据我所知 PyList SetItem 和 PyList SETITEM 之间的区别在于 PyList SetItem 会降低它覆盖的列表项的引用计数 而 PyList SETITEM 不会 我有什么理由不应该一直使用 PyList Set
  • 具有多处理功能的 Python 代码无法在 Windows 上运行

    以下简单的绝对初学者代码在 Ubuntu 14 04 Python 2 7 6 和 Cygwin Python 2 7 8 上运行 100 但在 Windows 64 位 Python 2 7 8 上挂起 我使用另一个片段观察到了同样的情况
  • 为什么我不能使用“exclude”从 python 轮子中排除“tests”目录?

    考虑以下包结构 与以下setup py内容 from setuptools import setup find packages setup name dfl client packages find packages exclude te
  • 底图上的子图

    我有一张英国地图和 121 个地点 每个地点有 3 个值 我想绘制 121 个位置中每个位置的三个值的小条形图 目前 这些值绘制为markersize属性 看起来像这样 密集恐惧症情节 https i stack imgur com 5fv
  • 为什么 tkinter / window.update 在我的程序中随着时间的推移变得更慢?

    我发现当我调用 window update 时 当向窗口写入的内容较少时 它的运行速度会更快 但后来 当我向窗口写入更多元素时 window update 需要更长的时间 请参阅下面的我的代码 您可以看到它在更新窗口之前一次向屏幕 100
  • Python,将迭代函数变成递归函数

    我创建了一个输出 4 3 2 1 0 1 2 3 4 的迭代函数 def bounce2 n s n for i in range n print n n n 1 if n lt 0 for i in range s 1 print n n
  • 将 API 数据存储到 DataFrame 中

    我正在运行 Python 脚本来从 Interactive Brokers API 收集金融市场数据 连接到API后 终端打印出请求的历史数据 如何将数据保存到数据帧中而不是在终端中流式传输 from ibapi wrapper impor
  • 如何使用循环将十进制转换为二进制?

    我想编写一个程序 将十进制数 0 到 9 转换为二进制数 我可以编写如何使用重复除法将十进制数转换为二进制数的代码 但是 我在创建一个以二进制格式打印十进制数字 0 到 9 的循环时遇到了麻烦 这是我的代码 number 0 remaind
  • 用Python中的嵌套for循环替换重复的if语句?

    在我编写的下面的代码中 n 4 所以有五个 if 语句 所以如果我想将 n 增加到 比如说 10 那么就会有很多 if 语句 因此我的问题是 如何用更优雅的东西替换所有 if 语句 n p 4 5 number of trials prob
  • 网页抓取 - 前往第 2 页

    如何访问数据集的第二页 无论我做什么 它都只返回第 1 页 import bs4 from urllib request import urlopen as uReq from bs4 import BeautifulSoup as sou
  • 如何对这个 Flask 应用程序进行单元测试?

    我有一个 Flask 应用程序 它使用 Flask Restless 来提供 API 我刚刚写了一些身份验证来检查 如果消费者主机被识别 该请求包含一个哈希值 通过加密 POST 的请求内容和 GET 的 URL 以及秘密 API 密钥来计
  • Python 视频框架

    我正在寻找一个 Python 框架 它将使我能够播放视频并在该视频上绘图 用于标记目的 我尝试过 Pyglet 但这似乎效果不是特别好 在现有视频上绘图时 会出现闪烁 即使使用双缓冲和所有这些好东西 而且似乎没有办法在每帧回调期间获取视频中
  • Spark中的count和collect函数抛出IllegalArgumentException

    当我使用时抛出此异常时 我尝试在本地 Spark 上加载一个小数据集count 在 PySpark 中 take 似乎有效 我试图搜索这个问题 但没有找到原因 看来RDD的分区有问题 有任何想法吗 先感谢您 sc stop sc Spark
  • Django 接受 AM/PM 作为表单输入

    我试图弄清楚如何使用 DateTime 字段在 Django 中接受 am pm 作为时间格式 但我遇到了一些麻烦 我尝试在 forms py 文件中这样设置 pickup date time from DateTimeField inpu
  • 如何向 SCons 构建添加预处理和后处理操作?

    我正在尝试在使用 SCons 构建项目时添加预处理和后处理操作 SConstruct 和 SConscript 文件位于项目的顶部 预处理动作 生成代码 通过调用不同的工具 gt 不知道在此预处理之后将生成的确切文件 可以创建用于决定生成哪
  • Spyder 如何在同一线程的后台运行 asyncio 事件循环(或者确实如此?)

    我已经研究 asyncio 模块 功能几天了 因为我想将它用于我的应用程序的 IO 绑定部分 并且我认为我现在对它的工作原理有一个合理的理解 或者在至少我认为我已经理解了以下内容 任一时刻 任一线程中只能运行一个异步事件循环 一旦一切都设置
  • 如何设置 matplotlib 表中列的背景颜色

    我在一个目录中有多个 txt 文件 例如 d memdump 0 txt 1 txt 10 txt 示例文本文件如下 Applications Memory Usage kB Uptime 7857410 Realtime 7857410
  • 最小硬币找零问题——回溯

    我正在尝试用最少数量的硬币解决硬币找零问题 采用回溯法 我实际上已经完成了它 但我想添加一些选项 按其单位打印硬币数量 而不仅仅是总数 这是我下面的Python代码 def minimum coins coin list change mi
  • 为什么用字符串和时间增量转置 DataFrame 会转换数据类型?

    这种行为对我来说似乎很奇怪 id列 字符串 在转置后转换为时间戳df如果另一列是时间增量 import pandas as pd df pd DataFrame id 00115 01222 32333 val 12 14 170 df v

随机推荐

  • 使用腾讯云轻量服务器Matomo应用模板建网站流量统计系统

    腾讯云百科分享使用腾讯云轻量应用服务器Matomo应用模板搭建网站流量统计系统 Matomo 是一款开源的网站数据统计软件 可以用于跟踪 分析您的网站的流量 同时充分保障数据安全性 隐私性 该镜像基于 CentOS 7 6 64位操作系统
  • 【性能】Android中的内存溢出(Out Of Memory,OOM)

    性能 Android中的内存溢出 Out Of Memory OOM 1 JVM内存区域介绍 2 OOM形成的原因 3 造成OOM的有哪些 3 1 从JVM的角度 3 2 从具体使用角度 3 2 1 内存泄漏导致的内存溢出 3 2 2 资源
  • 【设计】低压差稳压器(LDO)的设计分析

    本简短教程介绍了一些常用的LDO 相关术语 以及一些基本概念 如压差 裕量电压 静态电流 接地电流 关断电流 效率 直流输入电压和负载调整率 输入电压和负载瞬态响应 电源抑制比 PSRR 输出噪声和精度 同时 为了方便理解 文中采用了示例和
  • WebStorm 初步使用 & HTML5 学习报告

    WebStorm 初步使用 WebStorm介绍 WebStorm是Jetbrains公司旗下的一款JavaScript开发工具 因其界面简洁 操作方便 被广大国内JS开发者誉为 Web前端开发神器 WebStorm具有智能代码补全 代码格
  • 宝塔面板部署Java项目

    宝塔面板部署Java项目 使用宝塔面板里面的 Java 项目管理器来进行部署 首先注意 1 tomcat7 8 9使用的端口依次是8081 8082 8083 安装的那个版本Tomcat就 开启对应的端口 2 该管理器项目不是部署在tomc
  • 【JMeter】RSA加密传参处理方法

    问题 登录请求参数中输入了正确的账号密码 响应结果报错 用户名或密码错误 原因分析 密码需要以RSA加密的方式传参 不能明文 解决方法 在该登录接口下新增一个 B e a n
  • UDP的抓包和网络协议

    背景 一直都在wireshar抓包 但是经常看的都是应用的报文 没有关注到udp的本身传输协议 所以花了一点时间查看了一下UDP的传输协议是什么样的 报文 这个是之前抓包的udp 的协议报文然后对应协议的字段进行协议 目前查看的话还是比较清
  • [编程题] 等差数列

    如果一个数列S满足对于所有的合法的i 都有S i 1 S i d 这里的d也可以是负数和零 我们就称数列S为等差数列 小易现在有一个长度为n的数列x 小易想把x变为一个等差数列 小易允许在数列上做交换任意两个位置的数值的操作 并且交换操作允
  • linux下使用socat

    其实网络协议比较简单 一般都是一个固定的套路 传 输 包 传 输 的 数
  • MES系统各部门评估建议

    生产部 如果期望通过项目推动来解决库存和交期的问题 需要首先针对我们最大的短板和痛点 供应商交期和品质 有针对性的改善 否则系统上了后也会因短板没有解决 无法实现最终目的 如果是为了解决目前制造部各单元计划协同性及准确性问题 以及针对急单插
  • Linux网络文件共享服务(一)存储类型和文件传输协议FTP

    成功不易 加倍努力 网络文件共享服务 本章总目录 1 存储类型 1 1 DAS存储 1 2 NAS存储 1 3 SAN存储 1 4 三种存储比较 2 文件传输协议 FTP 2 1 FTP工作原理介绍 2 2 常见 FTP 相关软件 2 3
  • 谈谈To B业务的难点

    最近有个说法 中国互联网的新增长点是 To B业务 而一个经常被提及的事实是 中美互联网巨头对比 在To C业务上的收益和市值近乎并驾齐驱 虽有差距 但至少是可以相提并论的 而在To B业务上 美国巨头的市场规模 比起中国的同类公司 高两个
  • STM32CubeMX之emWin移植

    前面两章介绍了SDRAM和LTDC的使用 本篇文章将介绍emWin移植到STM32 硬件环境 STM32F429IGT6 软件环境 STM32CubeMX v5 5 0 HAL库版本 STM32CubeF4 Firmware Package
  • 什么叫泛型?有什么作用?

    作者 Java3y 链接 https www zhihu com question 272185241 answer 366129174 来源 知乎 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 一 什么是泛型 Jav
  • MySQL的B+树索引和hash索引的区别

    简述一下索引 索引是数据库表中一列或多列的值进行排序的一种数据结构 索引分为聚集索引和非聚集索引 聚集索引查询类似书的目录 快速定位查找的数据 非聚集索引查询一般需要再次回表查询一次 如果不使用索引就会进行全表扫描 还有可以进行多字段组成联
  • svn历史版本操作说明

    svn历史操作简写说明 操作的字母缩写为R 一般我们常见的操作为 A D M R A add 新增 C conflict 冲突 D delete 删除 M modify 本地已经修改 G modify and merGed 本地文件修改并且
  • centos安装gcc时出现问题:Delta RPMs disabled because /usr/bin/applydeltarpm not installed.

    解决办法 此问题安装Deltarpm包 增量 RPM 套件 即可解决 当然您也可以先使用一下命令 查看是哪个包提供applydeltarpm yum provides applydeltarpm yum install deltarpm y
  • 我见过的最糟糕代码

    作者 Mehdi Zed 在本文 将向读者展示一些作者见过的一些最糟糕的代码 除非你希望被同事和用户讨厌 否则这些 魔鬼 永远都不应该被放到人间 我们会发现 通过一些好的实践 其实很容易避免它们 01 魔鬼代码 需要改进的代码与所谓的 魔鬼
  • 2023年Node.js全网详细下载安装的最新教程

    文章目录 1 文章引言 2 下载安装 3 检查是否安装成功 4 补充说明 1 文章引言 今天准备写下载和安装vue js的博文 但安装vue js的前提是要安装node和npm 我们在安装node js时 会自动安装的npm包管理器 接下来
  • [深度学习]Part2 数据清洗和特征工程Ch06——【DeepBlue学习笔记】

    本文仅供学习使用 数据清洗和特征工程Ch06 1 特征工程 1 1 特征工程介绍 1 2 特征预处理 1 2 1 数据清洗 1 2 1 1 数据清洗 预处理 1 2 1 2 数据清洗 格式内容错误数据清洗 1 2 1 3 数据清洗 逻辑错误