【火炉炼AI】机器学习008-简单线性分类器解决二分类问题

【火炉炼AI】机器学习008-简单线性分类器解决二分类问题

(本文所使用的Python库和版本号: Python 3.5, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )git

分类问题,就是将数据点按照不一样的类别区分开来,所谓人以类聚,物以群分,就是这个道理。之前的【机器学习001-007】都是讲解的回归问题,二者的不一样之处在于:回归输出的结果是实数,而且通常是连续的实数值,而分类问题的输出结果是离散的某一个类别或不一样类别的几率。github

最简单的分类问题是二元分类,将整个样本划分为两个类别,好比将整我的类分为男人和女人(泰国人妖不在考虑范围内,呵呵)。稍微复杂一点的分类问题是多元分类,它将整个样本划分为多个(通常大于两个)不一样类别,好比将家禽数据集能够划分为:鸡,鸭,鹅等,将家畜样本划分为:狗,猪,牛,羊等等。dom

下面从一个最简单的二元分类问题入手,看看二元分类器是如何构建的。机器学习


1. 准备数据集

因为二元分类问题比较简单,此处咱们本身构建了一些数据点,并将这些数据点按照不一样类别放入不一样变量中,好比把全部第0类别的数据点都放置到class_0中,把全部第1类别的数据点放入class_1中,以下所示。学习

# 首先准备数据集
# 特征向量
X = np.array([[3,1], [2,5], [1,8], [6,4], [5,2], [3,5], [4,7], [4,-1]]) # 自定义的数据集
# 标记
y = [0, 1, 1, 0, 0, 1, 1, 0]

# 因为标记中只含有两类,故而将特征向量按照标记分割成两部分
class_0=np.array([feature for (feature,label) in zip(X,y) if label==0])
print(class_0) # 确保没有问题
class_1=np.array([feature for (feature,label) in zip(X,y) if label==1])
print(class_1)

# 划分也能够采用以下方法:两个打印后结果同样
# class_0=np.array([X[i] for i in range(len(X)) if y[i]==0])
# print(class_0)
# class_1=np.array([X[i] for i in range(len(X)) if y[i]==1])
# print(class_1)
复制代码

-------------------------------------输---------出--------------------------------测试

[[ 3 1] [ 6 4] [ 5 2] [ 4 -1]] [[2 5] [1 8] [3 5] [4 7]]spa

--------------------------------------------完-------------------------------------code

上面虽然构建了数据点,可是难以直观的看清这个二分类问题的数据点有什么特色,因此为了有更加直观的认识,通常会把数据点的散点图画出来,以下所示:orm

# 在图中画出这两个不一样类别的数据集,方便观察不一样类别数据的特色
plt.figure()
plt.scatter(class_0[:,0],class_0[:,1],marker='s',label='class_0')
plt.scatter(class_1[:,0],class_1[:,1],marker='x',label='class_1')
plt.legend()
复制代码

两个类别数据集的分布图

########################小**********结###############################cdn

1,本次研究的二分类问题是极其简单的分类问题,故而构建了8个样本的两个类别的数据点,每一个类别有四个点。

2,为了更加直观的查看数据点的分布特色,通常咱们要把数据点画在平面上,对数据点的分布状况有一个初步的了解,便于后面咱们采用哪一种分类器。

3,本次构建的数据集是由8行2列构成的特征矩阵,即8个样本,每一个样本有两个features.

#################################################################


2. 构建简单线性分类器

所谓线性可分问题,是指在平面上能够经过一条直线(或更高维度上的,一个平面)来将全部数据点划分开来的问题,“能够用直线分开”是线性可分问题的本质。相对应的,“不能够用直线分开”即是线性不可分问题的本质,对于线性不可分问题,须要用曲线或曲面来将这些数据分开,对应的就是非线性问题。好比,上面本身定义的数据集能够用简单的直线划分开来,好比能够采用y=x这条直线分开,以下所示:

# 从上面图中能够看出,能够画一条直线轻松的将class_0和class_1两个数据点分开
# 其实有不少直线能够起到分类器的效果,此处咱们只用最简单的y=x做为演示
plt.figure()
plt.scatter(class_0[:,0],class_0[:,1],marker='s',label='class_0')
plt.scatter(class_1[:,0],class_1[:,1],marker='x',label='class_1')
plt.plot(range(10),range(10),label='line_classifier') # 此处x=range(10), y=x
plt.legend()
复制代码

使用一条直线能够将这两个数据集分开

实际上,能够采用很是多的直线来将本数据集的两个类别区分开来,以下图所示,这些直线是在斜率和截距上稍微调整而来。

能够分开的直线有不少条

那么,这么多直线均可以解决简单分类问题,确定会有一条最佳直线,可以达到最佳的分类效果。下面,使用sklearn模块中的SGD分类器构建最佳直线分类器。以下代码:

# 上面虽然随机的选择了一条直线(y=x)做为分类器,但不少时候咱们不知道分类
# 下面构建一个SGD分类器,它使用随机梯度降低法来训练
# 训练以前须要对数据进行标准化,保证每一个维度的特征数据方差为1,均值为0,避免某个特征值过大而成为影响分类的主因
from sklearn.preprocessing import StandardScaler
ss=StandardScaler()
X_train=ss.fit_transform(X) # 因为本项目数据集太少,故而所有用来train

# 构建SGD分类器进行训练
from sklearn.linear_model import SGDClassifier
sgdClassifier=SGDClassifier(random_state=42)
sgdClassifier.fit(X_train,y) # y做为label已是0,1形式,不需进一步处理

# 使用训练好的SGD分类器对陌生数据进行分类
X_test=np.array([[3,2],[2,3],[2.5,2.4],[2.4,2.5],[5,8],[6.2,5.9]])
X_test=ss.fit_transform(X_test) # test set也要记过一样的处理
test_predicted=sgdClassifier.predict(X_test)
print(test_predicted)
复制代码

-------------------------------------输---------出--------------------------------

[0 1 1 1 1 0]

--------------------------------------------完-------------------------------------

########################小**********结###############################

1,使用sklearn中的SGDClassifier能够对数据集进行简单的线性分类,达到比较好的分类效果。

2,在数据集的特征上,貌似x>y时,数据属于class_0, 而x<y时,数据属于class_1,SGDClassifier模型在测试数据集上也基本可以正确划分,只有在x和y大致相等的关键点处容易出现错误判断。

#################################################################


注:本部分代码已经所有上传到(个人github)上,欢迎下载。

参考资料:

1, Python机器学习经典实例,Prateek Joshi著,陶俊杰,陈小莉译

相关文章
相关标签/搜索