机器学习之特征工程
常用的机器学习框架
系统掌握的理论知识
快速掌握的理论书籍
机器学习进阶书籍
机器学习概述
什么是机器学习
- 机器学习是从数据中自动分析获得规律(模型),并利用规律对未知数据进行预测
分辨啤酒还是红酒过程
-
搜集数据
-
装备数据
数据处理:
首先将所有数据放在一起,然后将其顺序打乱。由于顺序不是判断酒水的依据,我们并不期望顺序影响到模型学习到的内容。换言之,我们判断一种酒是红的还是啤的,并不需要知道前一种或是接下来有什么酒出现。
这时,可以着手绘出可视化的数据分析结果,这些分析图将有助于你发现不同变量之间的潜在相关性,并且能帮你发现是否有数据失衡。比如,假若我们的数据中大量结果都表现出啤酒的特征,那么模型大多数时
候都遇到了啤酒,所以它的推测也将倾向于啤酒。但是真实世界中,模型需要判断的啤酒和红酒的量很有可能是相同的,假若它按照训练的结果得出的大部分都是啤酒,那么它有不少时候都得出了错误的结论。
我们还需要将数据分成两部分。第一部分用于训练模型,它们将占全部数据中的绝大多数。另一部分则是用于评估模型的判断能力的。显然我们不希望用于训练的数据被拿来检测模型,因为这些数据很可能被模型给直接记住了,答案脱口而出。这就好像你在考试里总不会出现平时的作业原题那样。
有时我们得到的数据需要一些其他形式的调整和操作,比如去重、规范化和纠错等等,这些都需要在数据准备的过程当中完成。 而我们的这个问答系统训练用的数据并不需要进一步操作,所以现在进入下一环节。
选择模型:
机器学习中,有多少特征就有多少个 m ,而 m 的值通常都用一个矩阵来表达,
我们用「W」标记以表示「weight」(权重)。类似的,我们将 b 也用矩阵表示,简记为「b」,
也就是「biases」(偏差)。
通过测试数据评估模型
一旦训练完毕,我们就要对得到的模型进行评估。此时,早前我们留下的那一小部分数据就派上用场了。在评估中,我们使用之前从未使用过的数据来测试模型,
得到输出并与正确的判定结果对比。
这种方法能够让我们知道模型在遇到未接触的数据时的表现情况,同时也展示了模型在现实世界的表现。推荐训练和评估所用的数据比例是 4:1 或 7:3 。选取何种比例取决于原始数据集的规模。
如果你的数据非常多,那么用于验证的数据可能就不需要那么多了。
模型应用: 预测
机器学习的强大之处在于它使得我们可以判断出酒的品类,而不需经过亲自品尝和人为判断。你可以将今天案例中的中心思想举一反三到其他的预测中,它们都遵循如下准则:
-
搜集数据
-
准备数据
-
选择模型
-
训练模型
-
评估模型
-
预测
数据来源于类型
数据来源
-
企业日益积累的大量数据(互联网公司更为显著)
-
政府掌握的各种数据
-
科研机构的实验数据
数据类型
离散型数据:
- 由记录不同类别个体的数目所得到的数据,又称计数数据,所有这些数据全部都是整数,而且不能再细分,也不能进一步提高他们的精确度。
连续型数据:
- 变量可以在某个范围内取任一数,即变量的取值可以是连续的,如,长度、时间、质量值等,这类整数通常是非整数,含有小数部分。
数值的类型如果是离散型(区间内不可分), 分类问题, 适合通过分类算法来解决这类问题
连续型(居间内可分), 小数类型, 回归类的问题, 适合通过回归类的算法类解决
y = kx + b y就是预测值 和真实值来比较,通过测试数据来评估模型
注:只要记住一点,离散型是区间内不可分,连续型是区间内可分
看看下面两组数据,说说它们的区别?
特定范围内的汽车数量、人口数量、班级数 特定范围内的票房数、长度、重量
数据类型的不同应用
- 数据的类型是将机器学习模型,不同问题不同处理的依据
可用数据集
常用数据集数据的结构组成
结构:特征值+目标值
注:有些数据集可以没有目标值适合用于聚类操作
特征工程是什么
- 特征工程是将原始数据转换为更好地代表预测模型的潜在问题的特征的过程,从而提高了对未知数据的模型准确性
- 直接影响模型的预测结果
Scikit-learn库介绍
安装
pip install Scikit-learn
sklearn特征抽取API
- sklearn.feature_extraction
字典特征抽取
-
作用:对字典数据进行特征值化
-
类:sklearn.feature_extraction.DictVectorizer
DictVectorizer语法
-
DictVectorizer(sparse=True,…)
-
DictVectorizer.fit_transform(X)
-
X:字典或者包含字典的迭代器
-
返回值:返回sparse矩阵
DictVectorizer.inverse_transform(X)
-
X:array数组或者sparse矩阵
-
返回值:转换之前数据格式
DictVectorizer.get_feature_names()
-
返回类别名称
-
DictVectorizer.transform(X)
-
按照原先的标准转换
字典特征抽取简单案例
from sklearn.feature_extraction import DictVectorizer def dictvec(): """ 对字典数据进行特征提取 :return: None """ # 创建字典向量话的对象 data = [{'city': '北京','temperature':100},{'city': '上海','temperature':60},{'city': '深圳','temperature':30}] dict_vec = DictVectorizer() # 调用fit_transform方法 来转换数据 data = dict_vec.fit_transform(data) # get_feature_names 获取特征 print(dict_vec.get_feature_names()) # 还原数据 data = dict_vec.inverse_transform(data) print(data) # 验证数据 # print(data.toarray()) return None if __name__ == '__main__': dictvec()
文本特征抽取
-
作用:对文本数据进行特征值化
-
类:sklearn.feature_extraction.text.CountVectorizer
CountVectorizer语法
-
CountVectorizer(max_df=1.0,min_df=1,…)
-
返回词频矩阵
CountVectorizer.fit_transform(X,y)
-
X:文本或者包含文本字符串的可迭代对象
-
返回值:返回sparse矩阵
CountVectorizer.inverse_transform(X)
-
X:array数组或者sparse矩阵
-
返回值:转换之前数据格式
CountVectorizer.get_feature_names()
- 返回值:单词列表
流程
-
实例化类CountVectorizer
-
调用fit_transform方法输入数据并转换
-
注意返回格式,利用toarray()进行sparse矩阵转换array数组
文本特征抽取简单案例
from sklearn.feature_extraction.text import CountVectorizer def countvec(): """ 对文档中词出现频率特征进行提取操作 1. 单个字母单词不会进入词频统计 :return: None """ # 创建对象 count_vec = CountVectorizer() # 调用fit_transform方法 data = ["life is short,i like is python", "life is too long,i dislike python"] data = count_vec.fit_transform(data) # print(data) print(data.toarray()) # 获取特征 print(count_vec.get_feature_names()) # inverse_transform 转换回去 data = count_vec.inverse_transform(data) print(data) # 验证数据 return None if __name__ == '__main__': countvec()
TF-IDF
TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的概率高,
并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分
能力,适合用来分类。
TF-IDF作用:用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。
TfidfVectorizer语法
-
TfidfVectorizer(stop_words=None,…)
-
返回词的权重矩阵
TfidfVectorizer.fit_transform(X,y)
-
X:文本或者包含文本字符串的可迭代对象
-
返回值:返回sparse矩阵
TfidfVectorizer.inverse_transform(X)
-
X:array数组或者sparse矩阵
-
返回值:转换之前数据格式
TfidfVectorizer.get_feature_names()
- 返回值:单词列表
from sklearn.feature_extraction.text import TfidfVectorizer def countvec(): # 创建对象 count_vec = TfidfVectorizer() # 调用fit_transform方法 data = ["life is short,i like is python", "life is too long,i dislike python"] # stop_words 对某些词不统计 tfidf = TfidfVectorizer(stop_words=["is"]) data = tfidf.fit_transform(data) # 提取特征值 print(tfidf.get_feature_names()) print(data) return None if __name__ == '__main__': countvec()
如何去对中文文本特征值化
jieba 分词
pip install jieba
import jieba
jieba.cut(“我是一个好程序员”)
返回值:词语生成器
from sklearn.feature_extraction.text import TfidfVectorizer import jieba def cutword(): """ 通过jieba 分词模块来完成对中文的分词处理 :return: """ con1 = jieba.cut("马云说今天很残酷,马云又说明天更残酷,但是后天很美好,马云还说但是绝对大部分是死在明天晚上,所以每个人不要放弃今天。") con2 = jieba.cut("我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。") con3 = jieba.cut("如果只用一种方式了解某样事物,你就不会真正了解它。但是了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。") content1 = [] content2 = [] content3 = [] for w in con1: content1.append(w) for w in con2: content2.append(w) for w in con3: content3.append(w) con1 = ' '.join(content1) con2 = ' '.join(content2) con3 = ' '.join(content3) return con1, con2, con3 def tfidfvec(): """ tfidf的使用 如果一个词在一篇文档中出现的次数比较多, 但是在其他的文档中出现的次数比较少 此时这个词的tfidf值就会比较高, 此时这个词的分类能力就会比较好 tf: term frequency 指的是一个词在某一篇文档中出现的频率 idf: inverse document frequency 逆文档词频 tfidf 对于中文的处理不是特别好 就需要通过一个业界使用非常广泛的jieba库, 对中文做分词处理 :return: None """ tfidf = TfidfVectorizer(stop_words=["所以"]) c1, c2, c3= cutword() data = tfidf.fit_transform([c1, c2, c3]) print(tfidf.get_feature_names()) print(data.toarray()) return None return None if __name__ == '__main__': tfidfvec()
数据的特征处理
特征处理是什么
-
通过特定的统计方法(数学方法)将数据转换成算法要求的数据
第一组
特征1 特征2 特征3 特征4
第二组
特征1 特征2 特征3 特征4
数值型数据:标准缩放:
-
1、归一化
-
2、标准化
-
3、缺失值
类别型数据:one - hot编码
时间类型:时间的切分
sklearn特征处理API
- sklearn. preprocessing
归一化
- 特点:通过对原始数据进行变换把数据映射到(默认为[0,1])之间
归一化公式计算过程
(1)归一化
归一化首先在特征(维度)非常多的时候,可以防止某一维或某几维对数据影响过大,也是为了把不同来源的数据统一到一个参考区间下,这样比较起来才有意义,其次可以程序可以运行更快。 例如:一个人的身高和体重两个特征,假如体重50kg,身高175cm,由于两个单位不一样,数值大小不一样。如果比较两个人的体型差距时,那么身高的影响结果会比较大,k-临近算法会有这个距离公式。
min-max方法
常用的方法是通过对原始数据进行线性变换把数据映射到[0,1]之间,变换的函数为:
$$X^{'}{=}\frac{x-min}{max-min}$$
其中min是样本中最小值,max是样本中最大值,注意在数据流场景下最大值最小值是变化的,另外,最大值与最小值非常容易受异常点影响,所以这种方法鲁棒性较差,只适合传统精确小数据场景。
- min-max自定义处理
这里我们使用相亲约会对象数据在MatchData.txt,这个样本时男士的数据,三个特征,玩游戏所消耗时间的百分比、每年获得的飞行常客里程数、每周消费的冰淇淋公升数。然后有一个 所属类别,被女士评价的三个类别,不喜欢、魅力一般、极具魅力。 首先导入数据进行矩阵转换处理
sklearn归一化 API
- sklearn.preprocessing.MinMaxScaler
MinMaxScaler语法
MinMaxScalar(feature_range=(0,1)…)
- 每个特征缩放到给定范围(默认[0,1])
- MinMaxScalar.fit_transform(X)
X:numpy array格式的数据[n_samples,n_features]
- 返回值:转换后的形状相同的array
from sklearn.preprocessing import MinMaxScaler def minmax(): """ 归一化将数据处理到某一个指定的范围 同等重要的特征数据, 如果某一个数据特别大 有可能会对结果的分析造成的影响比较大,此时就需要将处理的数据重要性平等的对待 此时需要讲数据进行归一化的处理 :return: """ # 创建对象 min_max = MinMaxScaler(feature_range=(2,5)) data = [[90,2,10,40],[60,4,15,45],[75,3,13,46]] # 转换数据 data = min_max.fit_transform(data) print(data) return None if __name__ == '__main__': minmax()
标准化
- 特点:通过对原始数据进行变换把数据变换到均值为0,方差为1范围内
常用的方法是z-score标准化,经过处理后的数据均值为0,标准差为1,处理方法是:
$$X^{'}{=}\frac{x-\mu}{\sigma}$$
其中$$\mu$$是样本的均值,$$\sigma$$是样本的标准差,它们可以通过现有的样本进行估计,在已有的样本足够多的情况下比较稳定,适合嘈杂的数据场景
sklearn中提供了StandardScalar类实现列标准化:
sklearn特征化API
- sklearn特征化API: scikit-learn.preprocessing.StandardScaler
StandardScaler语法
StandardScaler(…)
- 处理之后每列来说所有数据都聚集在均值0附近方差为1
StandardScaler.fit_transform(X,y)
-
X:numpy array格式的数据[n_samples,n_features]
-
返回值:转换后的形状相同的array
StandardScaler.mean_
-
原始数据中每列特征的平均值
StandardScaler.std_
-
原始数据每列特征的方差
from sklearn.preprocessing import MinMaxScaler, StandardScaler def stand(): """ 将数据处理成一种比较稳定的正太分布数据 :return: """ std = StandardScaler() data = [[ 1., -1., 3.],[ 2., 4., 2.],[ 4., 6., -1.]] data = std.fit_transform(data) print(std.mean_) # print(std.std_) print(data) return None if __name__ == '__main__': stand()
缺失值
由于各种原因,许多现实世界的数据集包含缺少的值,通常编码为空白,NaN或其他占位符。然而,这样的数据集与scikit的分类器不兼容,它们假设数组中的所有值都是数字,并且都具有和保持含义。使用不完整数据集的基本策略是丢弃包含缺失值的整个行和/或列。然而,这是以丢失可能是有价值的数据(即使不完整)的代价。更好的策略是估算缺失值,即从已知部分的数据中推断它们。
缺失值处理方法
sklearn缺失值API:
- sklearn.Imputer.SimpleImputer
Imputer语法
SimpleImputer(missing_values='NaN', strategy='mean')
- 完成缺失值插补
SimpleImputer.fit_transform(X,y)
-
X:numpy array格式的数据[n_samples,n_features]
-
返回值:转换后的形状相同的array
from sklearn.impute import SimpleImputer import numpy as np import pandas as pd def imputer(): """ 缺失值的处理 通过列的平均值来填充 :return: None """ im = SimpleImputer(strategy="mean") data = [[1, 2], [np.nan, 3], [7, 6]] data = im.fit_transform(data) print(data) return None if __name__ == '__main__': imputer()
关于np.nan(np.NaN)
-
1、 numpy 的数组中可以使用 np.nan/np.NaN 来代替缺失值,属于float类型
-
2、如果是文件中的一些缺失值,可以替换成 nan,通过 np.array 转化成 float 型的数组即可
特征选择
特征选择原因
-
冗余:部分特征的相关度高,容易消耗计算性能
-
噪声:部分特征对预测结果有负影响
特征
-
1、羽毛颜色
-
2、眼睛宽度
-
3、是否有爪子
-
4、爪子长度
特征选择是什么
特征选择就是单纯地从提取到的所有特征中选择部分特征作为训练集特征,
特征在选择前和选择后可以改变值、也不改变值,但是选择后的特征维数肯
定比选择前小,毕竟我们只选择了其中的一部分特征。
降维本质上是从一个维度空间映射到另一个维度空间,特征的多少别没有减少,当然在映射的过程中特征值也会相应的变化。举个例子,现在的特征是1000维,我们想要把它降到500维。降维的过程就是找个一个从1000维映射到500维的映射关系。原始数据中的1000个特征,每一个都对应着降维后的500维空间中的一个值。假设原始特征中有个特征的值是9,那么降维后对应的值可能是3。而对于特征选择来说,有很多方法:
主要方法(三大武器):
- Filter(过滤式):VarianceThreshold
- Embedded(嵌入式):正则化、决策树
- Wrapper(包裹式)
VarianceThreshold语法
- VarianceThreshold(threshold = 0.0)
删除所有低方差特征
Variance.fit_transform(X,y)
-
X:numpy array格式的数据[n_samples,n_features]
-
返回值:训练集差异低于threshold的特征将被删除。
默认值是保留所有非零方差特征,即删除所有样本中具有相同值的特征。
from sklearn.feature_selection import VarianceThreshold def van(): """ 删除低方差的数据 :return: None """ v = VarianceThreshold(threshold=0) data = [[0, 2, 0, 3], [0, 1, 4, 3], [0, 1, 1, 3]] data = v.fit_transform(data) print(data) return None if __name__ == '__main__': van()
sklearn降维API
- sklearn. decomposition
PCA是什么
-
本质:PCA是一种分析、简化数据集的技术
-
目的:是数据维数压缩,尽可能降低原数据的维数(复杂度),损失少量信息。
-
作用:可以削减回归分析或者聚类分析中特征的数量
高维度数据容易出现的问题
- 特征之间通常是线性相关的
转换后
-------------------》
PCA语法
PCA(n_components=None)
- 将数据分解为较低维数空间
PCA.fit_transform(X)
-
X:numpy array格式的数据[n_samples,n_features]
-
返回值:转换后指定维度的array
from sklearn.decomposition import PCA def pca(): """ pca给数据降维 如果没有指定降低维度的数量, 会在原有的维度-1 :return: None """ p = PCA(n_components=2) data = [[0, 2, 0, 3], [0, 1, 4, 3], [0, 1, 1, 3]] data = p.fit_transform(data) print(data) if __name__ == '__main__': pca()
降维案例
from sklearn.decomposition import PCA import pandas as pd def pcaexample(): """ 通过PCAde方式给用户购买商品类型的偏好进行数据降维 orders --> order_products_prior --> products --> aisles :return: None """ orders = pd.read_csv("./data/instacart/orders.csv") aisles = pd.read_csv("./data/instacart/aisles.csv") order_products_prior = pd.read_csv("./data/instacart/order_products_prior.csv") products = pd.read_csv("./data/instacart/products.csv") me = pd.merge(orders, order_products_prior, on=['order_id','order_id']) me = pd.merge(me, products, on=['product_id', 'product_id']) me = pd.merge(me, aisles, on=['aisle_id','aisle_id']) # 用户和商品类别的关系 me = pd.crosstab(me['user_id'],aisles['aisle']) #创建pca降维对象 pca = PCA(n_components=100) # fit_transform me = pca.fit_transform(me) print(me) return None if __name__ == '__main__': pcaexample()