今天介绍一下机器学习常用算法,以及常用的数据处理技巧等。我们都知道机器学习针对特定任务从经验中学习,并且使得我们的任务效果越来越好。我们看一机器学习的workflow,如下所示:
数据采集和标记->数据清洗->特征选择->模型选择->模型训练和测试->模型性能评估和优化->模型使用即上线。
我们一般通过Python来实现机器学习常用算法的程序,所以基于Python语言常用的机器学习类库及其第三方扩展库有:IPython,Jupyter,numpy,matplotlib,scipy,scikit-learn,seaborn。
我们先安装这些类库即。
pip install ipython,jupyter,numpy,matplotlib,scipy,scikit-learn,seaborn
下面我们来简单的介绍一下这几个类库。
1.ipython是一种探索性编程的类库,它可以非常方便的执行你的python代码。快捷键和魔法用法可以自己百度和google,介绍一个常用的技巧就是通过魔法函数可以直接启用魔法命令,不用每次执行魔法命令时键入%。
%automagic on
pwd
cd
2.可视化的嵌套可以通过。
%matplotlib inline
Numpy 是Python计算机科学基础库,里面有很多的数学算法。
import numpy as np
a = np.array([[1,2,4],[1,2,3]])
a.shape,a.ndim,a.dtype
#分别是多维数据的维度,轴和数据类型
(2, 3), 2, dtype('int64')
numpy是共享内存的,如果需要独立保存则需要显式的备份。可以通过np.may_share_memory(),判断两个数组是否是共享内存。
a = np.arange(10)
b = a[2:5]
np.may_share_memory(a,b)
#输出
True
b = a[2:5].copy()
np.may_share_memory(a,b)
#输出
False
关于轴的问题,numpy的多维数组是面向轴处理的。例如:
a = np.random.randint(1,5,(4,6))
print(a)
#输出
array([[2, 4, 2, 3, 4, 3],
[2, 2, 1, 3, 4, 2],
[1, 3, 1, 1, 3, 1],
[1, 3, 3, 2, 3, 3]])
#面向轴处理,axis=0代表按行处理,axis=1面向列处理。
print(a.sum(axis=0),a.sum(axis=1))
#输出
(array([ 6, 12, 7, 9, 14, 9]), array([18, 14, 10, 15]))
还有一个经常使用的用法就是按照array的维度操作。比如:
a = np.arange(12)
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
b = a.reshape((3,4))
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
b.ravel()
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]))
b=a[:,np.newaxis]
array([[ 0],
[ 1],
[ 2],
[ 3],
[ 4],
[ 5],
[ 6],
[ 7],
[ 8],
[ 9],
[10],
[11]])
排序,排序不仅支持按照值排序而且还通过index返回。比如
a=np.array([10,3,4,7,12])
a.argsort()
#输出
array([1, 2, 3, 0, 4])
我在Numpy 数据处理一文中介绍了一些常用的用法,或者参考它的官方文档。
关于pandas的技巧,可以参考Pandass 数据处理
官方文档已经非常全面了,建议参考官方文档。
在之前我们已经介绍了机器学习算法理论,下面我们介绍两个几个重要的关键术语。过拟合:模型能很好的拟合训练数据,但是对于新数据或者测试数据的预测准确性较差。欠拟合:模型不能很好的拟合训练样本且对新数据或者测试数据的预测准确性较差。相对应的我们一般称欠拟合为高偏差,过拟合称为高方差。我们现在常用的机器学习算法是通过模型算法成本来反馈(反推)模型参数,使得在成本函数或者代价函数最低的情况下,寻找最优的模型参数。比如:
J_{test}(\theta)=\frac 1{2m}\sum_{i=0}^m(h_\theta(x^{(i)})-y^{i})^2
我们通过模型在数据集上的最少成本来求解最优模型参数。
我们在采用机器学习应用业务时,我们通常通过交叉验证数据集来衡量模型,即:训练数据集:交叉验证数据集:测试数据集=6:2:2。
在模型选择时,使用训练数据集来训练算法参数,用交叉验证集来验证参数,选择交叉验证集的成本J最下的算法作为数据拟合模型,最后再用测试数据集来测试选择出来的模型准确性。但是在实践中,大多数直接将数据集分成训练数据集和测试数据集,而没有交叉验证数据集,主要是大多数时候并不需要横向对比不同的模型。在工程上,我们最主要的工作不是选择模型,而是获取更多的数据、分析数据以及数据挖掘。
学习曲线是观察模型准确率与训练数据集关系。步骤:
1.将数据集分为训练数据集和交叉验证数据集。
2.取训练数据集的20%作为训练样本,训练出模型参数。
3.使用交叉验证数据集来计算训练出来的模型的准确率。
4.以训练数据集的准确性,交叉验证的准确性作为纵坐标,训练数据集个数作为横坐标,在坐标轴画出。
5.训练数据集增加10%,跳到第三步骤继续执行,知道训练数据集大小为100%为止。
在详细的机器学习算法里面,我们会画出一个学习曲线。一般我们会通过学习曲线,来判断算法是高偏差还是高方差。
对于过拟合一般采取的方法:
1.获取更多的训练数据。
2.减少输入的特征数。
对于欠拟合一般采取的方法:
1.增加有价值的特征。
2.增加多项式特征。
除了学习曲线外,我们一般还会通过查准率和召回率来评价一个算法的好坏。比如关于一个肿瘤预测的实例中:
预测数据/实际数据 实际恶性肿瘤 实际良性肿瘤
预测恶性肿瘤 TruePositive FalsePositive
预测良性肿瘤 FalseNegative TrueNegative
Precision=\frac {TruePositive}{TruePositive+FalsePositive} Recall=\frac {TruePositive}{TruePositive+FalseNegative} F_1Score=2\frac{PR}{P+R}
k-近邻算法是针对未标记的样本类别,由距离其最近的k个邻居投票决定的。优点:准确性高,对异常值和噪声有较高的的容忍度。缺点:计算量较大,对内存的需求较大。一般而言,k值越大,模型的偏差越大,对噪声数据越不敏感,当k值很大时,可能造成欠拟合;k值越小,模型的方差越大,当k值太小时容易造成过拟合。我们通过k-近邻算法来进行糖尿病预测。数据集为diabetes.csv,我们依次来看一下。
1.加载数据
data_path="diabetes.csv"
import pandas as pd
data = pd.read_csv(data_path)
data.head()
数据的8个特征分别为
我们可以看一下实例数据。
data.shape
(768,9)
ata.groupby("Outcome").size()
Outcome
0 500
1 268
dtype: int64
其中阳性有500个,阴性有268个。我们将数据集分类出来方便我们训练和衡量。
#只含有特征的数据集
x=data.iloc[:,0:8]
#标记数据
y=data.iloc[:,8]
print('shape of x {};shape of y {}'.format(x.shape,y.shape))
#输出 shape of x (768, 8);shape of y (768,)
from sklearn.model_selection import train_test_split
#将数据集划分为训练数据集和测试数据集,其中测试数据集为20%。
x_train,x_test,y_trian,y_test = train_test_split(x,y,test_size=0.2)
2.模型选择
我们使用三种算法对数据进行拟合即普通的k-均值算法,带权重的k-均值算法和指定半径的k-均值算法。
from sklearn.neighbors import KNeighborsClassifier,RadiusNeighborsClassifier
models=[]
models.append(("KNN",KNeighborsClassifier(n_neighbors=2)))
models.append(("KNN with weights",KNeighborsClassifier(n_neighbors=2,weights="distance")))
models.append(("Radius Neighbors",RadiusNeighborsClassifier(n_neighbors=2,radius=500)))
results=[]
for name,model in models:
model.fit(x_train,y_trian)
results.append((name,model.score(x_test,y_test)))
for i in range(len(results)):
print("name:{};score:{}".format(results[i][0],results[i][1]))
#输出
name:KNN;score:0.7142857142857143
name:KNN with weights;score:0.6168831168831169
name:Radius Neighbors;score:0.6948051948051948
因为训练样本和测试样本是随机分配的,那么如何衡量模型呢?所以我们需要多次分配训练数据集和交叉验证数据集,然后对多次预测结果进行平均。
#kfold 将数据分成10份,其中一份作为交叉验证数据集来计算模型准确性。
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
results=[]
for name,model in models:
kfold=KFold(n_splits=10)
cv_result=cross_val_score(model,x,y,cv=kfold)
results.append((name,cv_result))
for i in range(len(results)):
print("name:{};score:{}".format(results[i][0],results[i][1].mean()))
我们采用普通的k-近邻算法。
3.模型分析
我们分别对训练集和测试集进行分析,如下:
knn = KNeighborsClassifier(n_neighbors=2)
knn.fit(X=x_train,y=y_trian)
train_score=knn.score(x_train,y_trian)
test_score=knn.score(x_test,y_test)
print("train score {};test score {}".format(train_score,test_score))
#输出
train score 0.8289902280130294;test score 0.7142857142857143
一是模型在训练样本上表现不佳,这说明算法太简单。二是在测试集的准确性欠佳。
我们下面通过学习曲线来看一下:
from sklearn.model_selection import learning_curve
import numpy as np
import matplotlib.pyplot as plt
def plot_learning_curve(plt, estimator, title, X, y, ylim=None, cv=None,n_jobs=1, train_sizes=np.linspace(.1, 1.0, 5)):
plt.title(title)
if ylim is not None:
plt.ylim(*ylim)
plt.xlabel("Training examples")
plt.ylabel("Score")
train_sizes, train_scores, test_scores = learning_curve(
estimator, X, y, cv=cv, n_jobs=n_jobs, train_sizes=train_sizes)
train_scores_mean = np.mean(train_scores, axis=1)
train_scores_std = np.std(train_scores, axis=1)
test_scores_mean = np.mean(test_scores, axis=1)
test_scores_std = np.std(test_scores, axis=1)
plt.grid()
plt.fill_between(train_sizes, train_scores_mean - train_scores_std,
train_scores_mean + train_scores_std, alpha=0.1,
color="r")
plt.fill_between(train_sizes, test_scores_mean - test_scores_std,
test_scores_mean + test_scores_std, alpha=0.1, color="g")
plt.plot(train_sizes, train_scores_mean, 'o--', color="r",
label="Training score")
plt.plot(train_sizes, test_scores_mean, 'o-', color="g",
label="Cross-validation score")
plt.legend(loc="best")
return plt
cv=ShuffleSplit(n_splits=10,test_size=0.2,random_state=0)
plt.figure(figsize=(10,6),dpi=64)
plot_learning_curve(plt,knn,"cure",x,y,ylim=(0.0,1.01),cv=cv)
plt.show()
我们能看到学习曲线,和我们的之前的模型分析的结果是一致的。如下图所示:
后面我们会介绍如何提高该算法准确率。
4.特征可视化和分析
有时候我们想通过将最相关的一个或者多个特征选择出来进行可视化分析,那么如何选择最相关的特征呢?我们一般通过如下方法:
from sklearn.feature_selection import SelectKBest
selector = SelectKBest(k=2)
x_new=selector.fit_transform(x,y)
results=[]
for name,model in models:
kfold=KFold(n_splits=10)
cv_result=cross_val_score(model,x_new,y,cv=kfold)
results.append((name,cv_result))
for i in range(len(results)):
print("name:{};score:{}".format(results[i][0],results[i][1].mean()))
#输出
name:KNN;score:0.725205058099795
name:KNN with weights;score:0.6900375939849623
name:Radius Neighbors;score:0.6510252904989747
然后可以将这两个特征和输出标记投影在坐标轴上,看一下数据分布。可以看到数据分布和重叠性很大,所以选择k-近邻算法无法达到一个很好的预测准确性。
这里的最相关的特征选择主要采用了统计学上的相关性检验,比如:卡方检验、t检验。
通过一个简单的例子对机器学习的常用算法-k近邻算法有了一个整体上的了解。下面我们介绍一下另外一个常用算法:线性回归。
参考
1.《scikit-learning 机器学习》
3.《机器学习导论》