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