小赵讲堂系列1-特征工程这件小事

   日期:2020-11-08     浏览:152    评论:0    
核心提示:我们做算法的,一定不能成为调包侠,我们每做一个操作,每写一段代码都要知道为什么要写这段代码,最终要使模型的预测效果可解释,故有此篇。刷了三遍百面机器学习的总结和日常见到的一些小问题,加入了自己的理解,不足之处请见谅。为什么我们要使用数据归一化及其适用范围在学习速率相同的情况下,范围大的特征更新速度会大于范围小的特征,这样会导致找到最优解迭代次数增加。适用范围:包括线性回归,逻辑回归,支持向量机、神经网络,但并不适用于决策树,为什么呢?因为决策树每次选择特征只考虑一个变量,不考虑变量之间的相关性。

前言

我们做算法的,一定不能成为调包侠,我们每做一个操作,每写一段代码都要知道为什么要写这段代码,最终要使模型的预测效果可解释,以前的我年少无知,现已悔改,故有此系类文章,绝不断更。刷了几遍面试题的总结和日常见到的一些小问题,加入了自己的理解,不足之处请见谅。

1. 为什么我们要使用数据归一化及其适用范围


在学习速率相同的情况下,范围大的特征更新速度会大于范围小的特征,这样会导致找到最优解迭代次数增加。
适用范围:包括线性回归,逻辑回归,支持向量机、神经网络,但并不适用于决策树,为什么呢?因为决策树每次选择特征只考虑一个变量,不考虑变量之间的相关性。
注:很多学生搞不清楚正则化,标准化和归一化的区别,简单说一下:
归一化:将数据都缩放到[0-1]区间内,防止量纲不同导致部分特征起主导作用,如上文解释,加快模型收敛速度。但是归一化对异常点较为敏感,适用于小样本,大样本上效果不如标准化。
标准化:最常见的是Z-Score标准化。标准化也可以做成归一化,但其不是为了方便与其他数据进行比较,它是为了方便下一步处理,比如使用标准化将数据化为标准正态分布进行处理,这样同样可以加快模型收敛速度。举个栗子,BN就是通过一定的规范化手段,把每层神经网络任意神经元这个输入值的分布强行拉回到均值为0方差为1的标准正态分布,从而加快神经网络的训练速度。

正则化:加入正则项防止模型过拟合,常见的有正则项有 L1 正则 和 L2 正则 以及 Dropout ,其中 L2 正则 的控制过拟合的效果比 L1 正则 的好。

###################归一化
data = np.random.uniform(0, 100, 10)[:, np.newaxis]
mm = MinMaxScaler()
mm_data = mm.fit_transform(data)
origin_data = mm.inverse_transform(mm_data)
print('data is ',data)
print('after Min Max ',mm_data)
print('origin data is ',origin_data)
###################标准化
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
iris = datasets.load_iris()
x = iris.data
y = iris.target
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state=666)
#sklearn处理归一化的模块
from sklearn.preprocessing import StandardScaler
stand = StandardScaler()
stand.fit(x_train)
# 注意使用train的均值和方差进行test的标准化
x_train = stand.transform(x_train)
x_test = stand.transform(x_test)
#现在就是处理好的数据,可以拿来直接用
###################正则化
#注意以下的操作不是很多,大多都是在模型训练时候添加penalty参数。
x = np.array([[1.,-1.,2.],
            [2.,0.,0.],
            [0.,1.,-1.]])
x_normalized = preprocessing.normalize(x,norm='l2')
print(x_normalized)
 
# 可以使用processing.Normalizer()类实现对训练集和测试集的拟合和转换
normalizer = preprocessing.Normalizer().fit(x)
print(normalizer)
normalizer.transform(x)

推荐阅读:一些其他的标准化和正则化的手段。模型中的正则化。

2. 如何处理类别特征

序号编码、独热编码、二进制编码(维数大大少于独热编码)
##############序号编码
import numpy as np
import sklearn.preprocessing as sp
# 准备数据
raw_samples = np.array(["audi", "ford", "audi", "toyota",
                        "ford", "bmw", "ford", "redflag", "audi"])
print(raw_samples)
# 训练之前 需要标签编码
lbe = sp.LabelEncoder()
result = lbe.fit_transform(raw_samples)
print("-----编码后\n", result)
# 编码 反向推导
test = [0, 0, 1, 1, 4]
print("-----编码反推\n", lbe.inverse_transform(test))
##############OneHot编码
import numpy as np
import sklearn.preprocessing as sp
samples = np.array([
    [1, 3, 2],
    [7, 5, 4],
    [1, 8, 6],
    [7, 3, 9]
])
# 独热编码 sparse 是否采用稀疏矩阵
ohe = sp.OneHotEncoder(sparse=False, dtype="int32")
result = ohe.fit_transform(samples)
# 00列对1和7进行独热编码 2位,01列 3位,02列4位
print(result)

3. 如何寻找组合特征

使用决策树进行特征组合,每一条从根节点到叶子节点的路径都可以看作一种特征组合的方式,决策树如何构建呢,常见的梯度决策树的办法都可以。例如

1-4就是特征,我们给定一条样本,就可以产生一个组合特征表示[1,1,1,0]表示符合1,2,3条件。

#coding:utf-8
############ 组合特征实战小栗子
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from sklearn.tree import DecisionTreeClassifier
def iris_type(s):
    it={ 'Iris-setosa': 0, 'Iris-versicolor': 1, 'Iris-virginica': 2}
    return it[s] 
iris_feature = u'花萼长度', u'花萼宽度', u'花瓣长度', u'花瓣宽度'
if __name__ == "__main__":
    mpl.rcParams['font.sans-serif']=[u'SimHei'] #黑体 FangSong/KaiTi
    mpl.rcParams['axes.unicode_minus']=False
    path = '10.iris.data'
    #加载数据 converters={4:iris_type} 将第四列数据替换成iris_type函数返回的值
    data=np.loadtxt(path,dtype=float,delimiter=',',converters={ 4:iris_type})
    #前4列是特征向量 赋给x_prime,最后一列标签列赋给y
    x_prime,y=np.split(data,(4,),axis=1)
    #(0,1)表示取第0列和第1列,以此类推,交叉抽取特征列
    # 这是组合特征的重点!!!!!!
    feature_pairs=[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
    plt.figure(figsize=(10,9),facecolor='#FFFFFF')
    for i,pair in enumerate(feature_pairs):
        #准备数据
        x=x_prime[:,pair]
        #决策树学习 criterion表示特征选择标准,可以是gini,entropy 即gini系数,信息增益
        #min_samples_leaf 叶子节点最少样本数
        clf=DecisionTreeClassifier(criterion='entropy',min_samples_leaf=3)
        #根据 feature_pairs中不同列的组合来训练模型
        dt_clf=clf.fit(x,y)
        #画图
        N,M=500,500 #纵横各采样多少个值
        x1_min,x1_max=x[:,0].min(),x[:,0].max() #第0列的范围
        x2_min,x2_max=x[:,1].min(),x[:,1].max() #第1列的范围
        t1=np.linspace(x1_min,x1_max,N) #构造500 个从x1_min到x1_max之间的等差数列
        t2=np.linspace(x2_min,x2_max,M)
        x1,x2=np.meshgrid(t1,t2)#生成网格采样点
        x_test=np.stack((x1.flat,x2.flat),axis=1) #测试点
        #训练集上的预测结果
        y_hat=dt_clf.predict(x)
        y=y.reshape(-1)
        c=np.count_nonzero(y_hat==y)#统计预测正确的个数
        print '特征: ', iris_feature[pair[0]], ' + ', iris_feature[pair[1]],
        print '\t预测正确数目:', c,
        print '\t准确率: %.2f%%' % (100 * float(c) / float(len(y)))
        #显示
        cm_light=mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
        cm_dark=mpl.colors.ListedColormap(['g','r','b'])
        y_hat=dt_clf.predict(x_test) #预测值
        y_hat=y_hat.reshape(x1.shape)#使之与输入的形状相同
        plt.subplot(2, 3, i + 1)
        plt.pcolormesh(x1, x2, y_hat, cmap=cm_light)  # 预测值
        plt.scatter(x[:, 0], x[:, 1], c=y, edgecolors='k', cmap=cm_dark)  # 样本
        plt.xlabel(iris_feature[pair[0]], fontsize=14)
        plt.ylabel(iris_feature[pair[1]], fontsize=14)
        plt.xlim(x1_min, x1_max)
        plt.ylim(x2_min, x2_max)
        plt.grid()
    plt.suptitle(u'决策树对鸢尾花数据的两特征组合的分类结果', fontsize=18)
    plt.tight_layout(2)
    plt.subplots_adjust(top=0.92)
    plt.show()

4. 有哪些文本表示模型,各有什么优缺点。

TF-IDF:没有考虑语义,单纯的将文本进行split
主题模型:例如LDA,主流前沿的LDA都在实行大规模并行化。LDA的一些发展
Embedding:将稀疏向量映射到一个Dense Vector中。(包括Word2Vec和LDA)

###########TF-IDF实现
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
 
x_train = ['TF-IDF 主要 思想 是','算法 一个 重要 特点 可以 脱离 语料库 背景',
           '如果 一个 网页 被 很多 其他 网页 链接 说明 网页 重要']
x_test=['原始 文本 进行 标记','主要 思想']
 
#该类会将文本中的词语转换为词频矩阵,矩阵元素a[i][j] 表示j词在i类文本下的词频
vectorizer = CountVectorizer(max_features=10)
#该类会统计每个词语的tf-idf权值
tf_idf_transformer = TfidfTransformer()
#将文本转为词频矩阵并计算tf-idf
tf_idf = tf_idf_transformer.fit_transform(vectorizer.fit_transform(x_train))
#将tf-idf矩阵抽取出来,元素a[i][j]表示j词在i类文本中的tf-idf权重
x_train_weight = tf_idf.toarray()
 
#对测试集进行tf-idf权重计算
tf_idf = tf_idf_transformer.transform(vectorizer.transform(x_test))
x_test_weight = tf_idf.toarray()  # 测试集TF-IDF权重矩阵
 
print('输出x_train文本向量:')
print(x_train_weight)
print('输出x_test文本向量:')
print(x_test_weight)

推荐阅读::TF-IDF的实现;

5. 常见的Word2Vec及其与LDA的联系


CBOW和Skip-Gram是常见的Word2Vec的两种结构,简单来说前者是根据上下文预测单词,后者是根据单词预测上下文,大家有没有发现这玩意和神经网络特别像,输入的都是Embedding后的单词,前者取argmax,后者取SoftMax。
LDA和Word2Vec的联系和区别:前者是根据文档-单词矩阵进行分解,得到文档-主题矩阵和主题-单词矩阵,后者是根据上下文的单词进行学习。前者是基于概率图模型的生成模型,后者是基于神经网络学习权重得到单词的稠密向量表示。(其实Embedding层现在已经封装好了,但还是建议看一下。)
推荐学习:Word2Vec实现;Word2Vec数学推导;LDA实战

6. 如何缓解数据训练样本不足的问题

问题:过拟合问题
解决办法:基于模型的就是简化模型,例如非线性转换成线性,添加约束项,集成学习,Dropout。基于数据的就是数据扩充(旋转,平移,缩放,裁剪,填充,左右翻转,这玩意已经被封装在Tensorflow的ImageDataGenerator中了,注意只对训练数据实行数据扩充哈),加入噪声,颜色变化,改变图像亮度和对比度。最新的数据扩充目前看到一个WSDAN。还有基于迁移学习的方法,具体有王大佬的知乎可以参考。王大佬。
当然了,这里要注意ImageDataGenerator,每次输入的都是一个iter,当数据循环完毕后,迭代下一个iter的时候会进行数据转换/增强。

from keras.preprocessing.image import ImageDataGenerator
import numpy as np
import matplotlib.pyplot as plt
#第一步:对测试数据和训练数据分别构造一个ImageDataGenerator对象
train_datagen = ImageDataGenerator(
        rescale=1./255,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True)
test_datagen = ImageDataGenerator(rescale=1./255)

推荐学习:CNN分类实战;实战Tensorflow; 斯嘉丽数据增强

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服