Python for ML 笔记

1. 正则化

正则化是解决特征共线性、过滤数据中噪音和防止过拟合的有效手段。正则化背后的原理是引入额外的信息(偏差)老惩罚过大的权重,起到偏差-方差平衡。

2.逻辑斯蒂回归 VS SVM

在解决现实的分类问题时,线性逻辑斯蒂回归和线性SVM通常效果近似。逻辑回归目标是最大化训练集的条件似然,使得她更易受奇异值影响。SVM只关心那些离决策界最近的点(即,支持向量)。另一方面,逻辑斯蒂回归的优点是易于实现,特别是并行化实现。此外,面对流式数据,逻辑斯蒂回归的易于更新的特点也很明显。

3.scikit-learn中SGDClassifier

sklearn中的Perceptron和LogisticRegression类的实现都使用了LIBLINEAR库,sklearn中的SVC类利用了LIBSVM库。
可是,有时候数据集很大,不能一次读入内存,针对这个问题,sklearn也实现了SGDClassifier类,使用提供的partial_fit方法能够支持在线学习。

#一次读入
from sklearn.linear_model import Perceptron
ppn=Perceptron()
#可以处理流数据
from sklearn.linear_model  import SGDClassifier
ppn=SGDClassifier(loss='perceptron')

loss='log'/'hinge'

3.决策树

对于决策树来说,特征的缩放不是必须的。sklearn可以将训练好的模型输出,保存在.dot文件,我们可以利用GraphViz 可视化

from sklearn.tree import export_graphviz
export_graphviz(tree,out_file='tree.dot',feature_names=['petal length','petal width'])

4. 随机森林

随机森林中构建决策树的做法和原始决策树的区别是,在每次分割节点时,不是从所有特征中选择而是在一个小特征集中选择特征。
缺点:模型的可解释性不如决策树
优点:

  • 是受超参数的影响波动不是很大(几个主要参数还是需要好好调参的))
  • 鲁棒性很强,不会过多受单棵决策树噪音的影响,不需要进行剪枝

树的数目k:k越大,随机森林的性能越好,当然计算成本也越高。
样本大小n:原始数据集重复抽样选择n个训练样例,能够控制bias-variance平衡,如果n很大,我们就减小了随机性,就容易过拟合。,如果n很小,模型的性能会降低。大多数随机森林的实现,包括sklearn中RandomForestClassifier,n的大小等于原始训练集的大小。
每一次分割时特征集的大小d:小于原始特征集大小,sklearn中的默认值原始特征数开根号

5. 参数模型和变参模型

机器学习算法可以被分为两大类:参数模型和变参模型。对于参数模型,在训练过程中我们要学习一个函数,重点是估计函数的参数,然后对于新数据集,我们直接用学习到的函数对齐分类。典型的参数模型包括感知机、逻辑斯蒂回归和线性SVM。与之相对的,变参模型中的参数个数不是固定的,它的参数个数随着训练集增大而增多!很多书中变参(nonparametric)被翻译为无参模型,一定要记住,不是没有参数,而是参数个数是变量!变参模型的两个典型示例是决策树/随机森林和核SVM。KNN属于变参模型的一个子类:基于实例的学习。

6.KNN

  • k的选择对于KNN模型来说至关重要,除此之外,距离度量也是很有用的。通常,欧氏距离用于实数域的数据集,此时一定要对特征进行标准化,这样每一维度特征的重要性等同。
  • 如果特征维度过大,KNN算法很容易过拟合。我们可以想象,对于一个固定大小的训练集,如果特征空间维度非常高,空间中最相似的两个点也可能距离很远(差别很大)。正则项不适用于KNN和决策树模型,我们只能通过特征选择和降维手段来避免维度诅咒。

7.预处理

虽然scikit-learn和NumPy数组结合的很方便,但是预处理时还是推荐使用pandas的DataFrame格式而非NumPy数组。

  • 由DataFrame对象预处理,通过values属性得到numpy数组,然后用sklearn中的算法了

8.缺失值处理

  • 消除带有缺失值的行
    df.dropna()
  • 消除带有缺失值的列
    df.dropna(axis=1)
  • 只去掉所有值都为nan的行
    df.dropna(how='all')
  • 只去掉非缺失值少于4个的行
    df.dropna(how='all')
  • 只去掉在特定列出现nan的行
    df.dropna(subset=['A','B'])

  • 插入法填充

from sklearn.preprocessing import Imputer
#以所在列的平均值填充,还有median和most_frequent
imr=Imputer(missing_values='NaN',strategy='mean',axis=0)
imr=imr.fit(df)
imputed_data=imr.transform(df.values)

9.estimator

estimator的两个必不可少的方法是fit和transform。
fit方法用于从训练集中学习模型参数,transform用学习到的参数转换数据.
任何要进行转换的数据的特征维度必须和fit时的数据特征维度相同

est.fit(train)
est.transform(train)
est.transform(test)

est.fit(X_train,y_train)
est.predict(X_test)

10.categorical value

  • 有序类别特征
    我们需要将分类型字符串转为整型数值。没有能够直接调用的方法来自动得到正确顺序的size特征。因要自己定义映射函数
size_mapping={'XL':3,'L':2,'M':1}
df['size']=df['size'].map(size_mapping)

如果我们还想将整型变量转换回原来的字符串表示,我们还可以定义一个反映射字典

inv_size_mapping={v:k for k,v in size_mapping.items())}。
  • 无序类别特征
    许多机器学习库要求类别是整型数值。虽然sklearn中大部分Estimator都能自动将类别转为整型,建议手动将类别进行转换
class_mapping={label:idx for idx,label in enumerate(np.unique(df['classlabel']))}

inv_class_mapping={v,k for k,v in class_mapping.items()}

sklearn中提供了LabelEncoder类来实现类别的转换:

from sklearn.preprocessing import LabelEncoder
class_le=LabelEncoder()
y=class_le.fit_transform(df['classlabel'].values)

class_le.inverse_transform(y)

转换为数字之后,因为无序,所以0123..等代表的意义是错的还需要转换为dummy 特征

  • 无序离散特征

(1)使用sklearn

from sklearn.preprocessing import OneHotEncoder
#categorical_features参数设置要进行独热编码的列
ohe=OneHotEncoder(categorical_features=[0])
ohe.fit_transform(X).toarray()

注意的是OneHotEncoder的transform方法默认返回稀疏矩阵,所以我们调用toarray()方法将稀疏矩阵转为一般矩阵。我们还可以在初始化OneHotEncoder时通过参数sparse=False来设置返回一般矩阵。

(2)使用pandas
get_dummies默认会对DataFrame中所有字符串类型的列
进行独热编码

pd.get_dummies(df[['A','B']])

10.划分训练集和测试集

from sklearn.cross_validation import train_test_split
X,y=df.iloc[:,1:].values,df.iloc[:,0].values
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.3,random_state=0)

通过本地验证得到最优模型和参数时,还要在整个数据集(训练集+验证集+测试集)上训练一次,得到最终的模型。

11.特征缩放

  • 归一化
from sklearn.preprocessing import MinMaxScaler
mms=MinMaxScaler()
X_train_norm=mms.fit_transform(X_train)
X_test_norm=mms.transform(X_test)

虽然归一化方法简单,但相对来说,标准化对于大部分机器学习算法更实用。
原因是大部分线性模型在初始化权重参数时,要么选择0要么选择一个接近0的随机数。标准化将特征值缩放到以0为中心,标准差为1,服从正态分布,这样学习权重参数更容易

  • 标准化
from sklearn.preprocessing import StandardScaler
stdsc=StandardScaler()
X_train_std=stdsc.fit_transform(X_train)
X_test_std=stdsc.transform(X_test)

12.选择有意义的特征

常用的减小泛化误差的做法包括:
收集更多的训练集数据
正则化,即引入模型复杂度的惩罚项
选择一个简单点的模型,参数少一点的
降低数据的维度

  • L1正则化起到特征稀疏的作用
    对于sklearn中那些支持L1正则的模型,我们只需要在初始化时用penalty参数设置为L1正则

  • 维度降低

    (1)特征选择feature selection
    从原始特征集合中选取一个子集合,子集中的特征都是和问题最相关的特征,这样能够提高计算效率并且由于溢出了不相干特征和噪音也降低了模型的泛化误差

    序列特征选择算法:序列后向选择
    SBS算法有以下4个步骤:

    1. 初始化k=d,其中d是原始特征维度。
    2. 确定那个评价函数最大的特征
    3. 从中移除特征。,k=k-1。
    4. 如果k等于事先确定的阈值则终止;否则回到步骤2。 sklearn目前并没有实现SBS算法.

    sklearn中提供了很多特征选择算法。包括基于特征参数的递归后向消除法,基于树方法提供的特征重要性的特征选择法和单变量统计检验。

    (2)特征抽取feature extraction
    从原始特征空间抽取信息,从而构成一个新的特征子空间.将原始的特征空间压缩到低纬度的特征子空间.

    主成分分析(principal component analysis, PCA), 用于无监督数据压缩
    线性判别分析(linear discriminant analysis, LDA), 用于监督降维作为一种监督降维
    通过核PCA进行非线性降维

  • 随机森林评估特征重要性

    sklearn中已经实现了用随机森林评估特征重要性,在训练好随机森林模型后,直接调用feature_importances_属性就能得到每个特征的重要性

    feat_labels=df.wine.columns[1:]
    forest=RandomForestClassifier(n_estimators=1000,random_state=0,n_jobs=1)
    forest.fit(X_train,y_train)
    importances=forest.feature_importances_
    indices=np.argsort(importance)[::-1]
    plt.title('feature importance')
    plt.bar(range(X_train.shape[1],importances[indices],color='lightblue',align='center')
    plt.xticks(range(X_train.shape[1],feat_labels,rotation=90)
    plt.xlim([-1,X_train,shape[1]])
    plt.tight_layout()
    plt.show()

    sklearn的随机森林实现,包括一个transform方法能够基于用户给定的阈值进行特征选择,使用RandomFroestClassifier作为特征选择器

    X_selected=forest.transform(X_train,threshold=0.15

13.PCA:无监督

from sklearn.decomposition import PCA

映射后的子空间,第一主成分包含最大的方差,第二主成分包含次大的方差,以此类推,并
且各个主成分方向是正交的(不相关)。

PCA方向极其容易受到数据中特征范围影响,所以在运用PCA前一定要做特征标准化

PCA的步骤:
1 将d维度原始数据标准化(StandardScaler)。
2 构建协方差矩阵(np.cov)。
3 求解协方差矩阵的特征向量和特征值(np.linalg.eig)。
4 选择值最大的k个特征值对应的特征向量,k就是新特征空间的维度。
5 利用k特征向量构建映射矩阵.
6 将原始d维度的数据集X,通过映射矩阵W转换到k维度的特征子空间.

方差解释率(variance explained ration)。一个特征值的方差解释率就是此特征值在特征值总和的占比。

#得到所有特征成分的方差解释率
pca=PCA(n_components=None)
X_train_pca=pca.fit_transform(X_train_std)
pca.explained_variance_ratio_

方差解释率和用随机森林评估特征重要性二者还是有很大区别的,PCA是一种无监督方法,在整个计算过程中没有用到类别信息!随机森林是监督模型,建模时用到了类别信息

14.LDA:有监督

PCA目标是找到正交的主成分同时保持数据集的最大方差,LDA的目标是为每个类单独优化,得到各个类的最优特征子集。PCA和LDA都是线性转换技术,用于数据压缩,前者是无监算法,后者是监督算法。


LDA步骤:
1. 将d维度原始数据进行标准化.
2. 对每一个类,计算d维度的平均向量.
3. 构建类间(between-class)散点矩阵 SB 和类内(within-class)散点矩阵 SW
4. 计算矩阵 SW1SB 的特征向量和特征值.
5. 选择值最大的前k个特征值对应的特征向量,构建d*d维度的转换矩阵W
6. 将原始数据集映射到新的特征子空间.

15. PCA核进行非线性映射

现实生活中的非线性数据,此时用于降维的线性转换手段(WX)比如PCA和LDA效果就不会太好运用核PCA,我们能将非线性可分的数据转换到新的、低维度的特征子空间,然后运用线性分类器解决。

核PCA的工作机制:通过核PCA的非线性映射,将数据转换到一个高维度空间,然后在这个高维度空间运用标准PCA重新将数据映射到一个比原来还低的空间,最后就可以用线性分类器解决问题了。不过,这种方法涉及到两次映射转换,计算成本非常高,由此引出了核技巧(kernel trick)。使用核技巧,我们能在原始特征空间直接计算两个高维特征向量的相似性(不需要先特征映射,再计算相似性)。

from sklearn.decomposition import KernelPCA

16.pipeline

对于管道来说,中间有多少个transformer都可以。管道中间每一步由sklearn中的transformer构成,最后一步是一个Estimator。(一定要注意管道执行fit方法,而transformer要执行fit_transform)

17 交叉验证

  • holdout交叉验证
    方法:将原始训练集分为训练集、验证集和测试集。训练机用于训练不同的模型,验证集用于模型选择。而测试集由于在训练模型和模型选择这两步都没有用到,对于模型来说是未知数据,因此可以用于评估模型的泛化能力
    缺点:对数据分割的方式很敏感,如果原始数据集分割不当,这包括训练集、验证集和测试集的样本数比例,以及分割后数据的分布情况是否和原始数据集分布情况相同等等。所以,不同的分割方式可能得到不同的最优模型参数。
  • k折交叉验证
    方法:第一步我们使用不重复抽样将原始数据随机分为k份,第二步 k-1份数据用于模型训练,剩下那一份数据用于测试模型。然后重复第二步k次,我们就得到了k个模型和他的评估结果(译者注:为了减小由于数据分割引入的误差,通常k折交叉验证要随机使用不同的划分方法重复p次,常见的有10次10折交叉验证)。然后我们计算k折交叉验证结果的平均值作为参数/模型的性能评估。
    划分为k部分:有很多不同的采样方法,比如针对非平衡数
    据的分层采样。分层采样就是在每一份子集中都保持原始数据集的类别比例。比如原始数据集正类:负类=3:1,这个比例也要保持在各个子集中才行
import sklearn.cross_validation import StratifiedKFold
kfold=StratifiedKFold(y=y_train,n_folds=10,random_state=1)
scores=[]
for k,(train,test) in enumerate(kfold):
    pipe_lr.fit(X_train[train],y_train[train])
    score=pipe_lr.score(X_train[test],y_train[test])
    scores.append(score)
print np.mean(scores),np.std(scores)

sklearn还实现了一个直接得到交叉验证评估结果的方法cross_val_score(内部同样是分层k折交叉验证)

from sklearn.cross_validation import cross_val_score
scores=cross_val_score(estimator=pipe_lr,X=X_train,y=y_train,cv=10,n_jobs=1

18.学习曲线和验证曲线

  • 学习曲线
    不同训练集大小下的训练集准确率和测试集准确率,进而根据曲线选择合适的划分大小
from sklearn.learning_curve import learning_curve
pipe_lr=Pipeline([
('scl',StandardScaler()),
('clf',LogisticRegression(penalty='l2',random_state=0))])
train_size,train_score,test_scores=learning_curve(estimator=pipe_lr,X=X_train,y=y_train,train_size=np.linspace(0.1,1.0,10),cv=10,n_jobs=1)
train_mean=np.mean(train_scores,axis=1)
train_std=np.std(train_scores,axis=1)
test_mean=np.mean(test_scores,axis=1)
test_std=np.std(test_scores,axis=1)
plt.plot(train_size,train_mean,color='blue',marker='o',markersize=5,label='training accuracy')
plt.fill_between(train_sizes,train_mean+train_std,train_mean-train_std,alpha=0.5,color='blue')
plt.plot(train_size,test_mean,color='green',linestyle='--',marker='o',markersize=5,label='validation accuracy')
plt.fill_between(train_sizes,test_mean+test_std,test_mean-test_std,alpha=0.15,color='green')
plt.grid()
plt.xlabel('number of training samples')
plt.ylabel('accuracy')
plt.legend(loc='lower right')
plt.ylim([0.8,1.0])
plt.show()

learning_curve默认使用分层k折交叉验证计算交叉验证的准确率,我们通过cv设置k。

  • 验证曲线
    不同参数下模型的准确率,进而根据曲线选择合适的参数
from sklearn.learning_curve import validation_curve
param_range=[0.001,0.01,0.1,1.0,10.0]
train_scores,test_scores=validation_curve(estimator=pipe_lr,X=X_train,y=y_train,param_name='clf__C',param_range=param_range,cv=10)
train_mean=np.mean(train_scores,axis=1)
train_std=np.std(train_scores,axis=1)
test_mean=np.mean(test_scores,axis=1)
test_std=np.std(test_scores,axis=1)
plt.plot(train_size,train_mean,color='blue',marker='o',markersize=5,label='training accuracy')
plt.fill_between(train_sizes,train_mean+train_std,train_mean-train_std,alpha=0.5,color='blue')
plt.plot(train_size,test_mean,color='green',linestyle='--',marker='o',markersize=5,label='validation accuracy')
plt.fill_between(train_sizes,test_mean+test_std,test_mean-test_std,alpha=0.15,color='green')
plt.grid()
plt.xscale('log')
plt.xlabel('param C')
plt.ylabel('accuracy')
plt.legend(loc='lower right')
plt.ylim([0.8,1.0])
plt.show()

19.网格搜索

from sklearn.grid_search import GridSearchCV
from sklearn.svm import SVC
pipe_svc=Pipeline([('scl',StandardScaler()),
('clf',SVC(random_state=1))])
param_range=[0.0001,0.001,0.1,1.0,10.0]
param_grid=[
{'clf__C':param_range,
'clf__kernel':['linear']},
{'clf__C':param_range,'clf__gamma':param_range,
'clf_kernel':['rbf']}
]
gs=GridSearchCV(estimator=pipe_svc,param_grid=param_grid,scoring='accuracy',cv=10,n_jobs=1)
gs=gs.fit(X_train,y_train)
print gs.best_score_
print gs.best_params_
clf=gs.best_estimator_#直接得到模型
clf.fit(X_train,y_train)
print clf.score(X_test,y_test)

20 随机搜索

网格搜索虽然不错,但是穷举过于耗时
RandomizedSearchCV随机采样出不同的参数组合

21.嵌套交叉验证

嵌套交叉验证外层有一个k折交叉验证将数据分为训练集和测试集。还有一个内部交叉验证用于选择模型算法。

如下使用:


gs=GridSearchCV(estimator=pipe_svc,param_grid=param_grid,scoring='accuracy',cv=10)
scores=cross_val_score(gs,X,y,scoring='accuracy',cv=5)
print np.mean(scores)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值