本人是一名数学系研究生,于2017年底第一次接触python和机器学习,作为一名新手,欢迎与大家交流。
我主要给大家讲解代码,理论部分给大家推荐3本书:
《机器学习实战中文版》
《机器学习》周志华
《统计学习方法》李航
以上3本书,第一本是基于python2的代码实现;剩余两本主要作为第一本书理论省略部分的补充,理论大部分都讲得很细。
博客上关于机器学习实战理论解释都很多,参差不齐,好作品也大都借鉴了以上3本书,网上有很多电子版的书。
与其看看一些没用的博客,真心不如以上3本书有收获。
说实话,学习一定要静下心来,切忌浮躁。不懂可以每天看一点,每天你懂一点,天天积累就多了。
操作系统:windows8.1
python版本:python3.6
运行环境:spyder(anaconda)
# -*- coding: utf-8 -*-
"""
Created on Thu Nov 16 19:55:33 2017
@author: Lelouch_C.C
"""
from numpy import *
import operator
#创建一个简单的数据集createDataSet
def createDataSet():
group = array([[1.0, 0.9], [1.0, 1.0], [0.1, 0.2], [0.0, 0.1]])
labels = ['A', 'A', 'B', 'B']
return group, labels
def classify0(inX, dataSet, labels, k):
"""
函数说明:kNN算法分类器
参数:用于分类的数据(测试集)inX
用于训练的数据(训练集)dataSet
类别标签labes
kNN算法参数,选择距离最小的k个点k
返回值:分类结果sortedClassCount[0][0]
"""
dataSetSize = dataSet.shape[0] #shape[0]返回dataSet的样本个数
diffMat = tile(inX, (dataSetSize, 1)) - dataSet #tile()用于复制
#在列向量方向上重复inX共1次(横向),行向量方向上重复inX共dataSetSize次(纵向)
sqDiffMat = diffMat**2 #二维特征相减后平方
sqDistances = sqDiffMat.sum(axis=1)
#sum()所有元素相加,sum(0)列相加,sum(1)行相加
distances = sqDistances**0.5 #开方,计算出距离
sortedDistIndices = distances.argsort()
#argsort()返回distances中元素从小到大排序后的索引值
classCount = {} #初始化一个记录类别次数的空字典
for i in range(k): #遍历前k个元素(距离最小的k个点),
voteIlabel = labels[sortedDistIndices[i]] #取出它们的类别标签
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #计算类别次数
#字典的get()方法,返回指定键的值,如果键不在字典中返回设定值0。
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
#python3中用items()替换python2中的iteritems()
#key=operator.itemgetter(1)根据字典的值进行排序,若key=operator.itemgetter(0)根据字典的键进行排序
#reverse降序/逆序/从大到小排序
return sortedClassCount[0][0] #返回次数最多的类别,即所要分类的类别(注意数据结构)
#准备数据:从文本文件中解析数据
def file2matrix(filename):
"""
函数说明:数据导入函数
"""
fr = open(filename)
arrayLines=fr.readlines() #观察readlines()读取后的返回值/列表
numberOfLines = len(arrayLines) #读取文件的行数#
returnMat = zeros((numberOfLines,3))
#初始化一个与文件行数相等,列数为3的零矩阵作为特征矩阵,来存储样本的3个特征
classLabelVector = [] #初始化一个空列表,来存储样本类别标签
index = 0 #index用来指定矩阵的索引值
for line in arrayLines:
line = line.strip()
#strip()删除字符串line中开头、结尾处,位于括号内删除序列的字符,
#若为空,默认删除所有的空白符(包括'\n','\r','\t',' ')
listFromLine = line.split('\t')
#将以制表符(\t)作为分隔符将整行数据分割成一个元素列表
returnMat[index,:] = listFromLine[0:3]
#将returnMat矩阵的第index个元素(其实是整行)用listFromLine的前3个元素组成的列表替换
classLabelVector.append(int(listFromLine[-1]))
#将listfromline最后一列的元素转化为整型(告知解释器为整型,否则会直接被当成字符串),
#再加到classlabelvedtor中
index += 1
return returnMat,classLabelVector
"""
if __name__ == '__main__':
dataSet, labels =createDataSet()
inX = array([1.2, 1.0])
k = 3
outputLabel = classify0(inX, dataSet, labels, 3)
print ("Your input is:", inX, "and classified to class: ", outputLabel)
inX = array([0.1, 0.3])
outputLabe1 = classify0(inX, dataSet, labels, 3)
print ("Your input is:", inX, "and classified to class: ", outputLabe1)
#输出:
#Your input is: [1.2 1. ] and classified to class: A
#Your input is: [0.1 0.3] and classified to class: B
#"""
#分析数据:使用Matplotlib创建散点图
from matplotlib.font_manager import FontProperties
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
def showdatas(datingDataMat, datingLabels):
"""
函数说明:画散点图
"""
font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14) #设置汉字格式
fig, axs = plt.subplots(nrows=2, ncols=2,figsize=(13,8))
#将fig画布分成2行2列,不共享x轴和y轴,fig画布的大小为(13,8)
#当nrow=2,nclos=2时,代表fig画布被分为四个区域,axs[0][0]表示第一行第一个区域,以此类推
numberOfLabels = len(datingLabels)
LabelsColors = []
for i in datingLabels:
if i == 1:
LabelsColors.append('black')
if i == 2:
LabelsColors.append('orange')
if i == 3:
LabelsColors.append('red')
axs[0][0].scatter(x=datingDataMat[:,0], y=datingDataMat[:,1], color=LabelsColors,s=15, alpha=.5)
#画出散点图,以datingDataMat矩阵的第一(飞行常客例程)、第二列(玩游戏)数据画散点数据,散点大小为15,透明度为0.5
axs0_title_text = axs[0][0].set_title(u'每年获得的飞行常客里程数与玩视频游戏所消耗时间占比',FontProperties=font)
axs0_xlabel_text = axs[0][0].set_xlabel(u'每年获得的飞行常客里程数',FontProperties=font)
axs0_ylabel_text = axs[0][0].set_ylabel(u'玩视频游戏所消耗时间占比',FontProperties=font)
plt.setp(axs0_title_text, size=9, weight='bold', color='red')
plt.setp(axs0_xlabel_text, size=7, weight='bold', color='black')
plt.setp(axs0_ylabel_text, size=7, weight='bold', color='black')
#设置标题,x轴label,y轴label
axs[0][1].scatter(x=datingDataMat[:,0], y=datingDataMat[:,2], color=LabelsColors,s=15, alpha=.5)
#画出散点图,以datingDataMat矩阵的第一(飞行常客例程)、第三列(冰激凌)数据画散点数据,散点大小为15,透明度为0.5
axs1_title_text = axs[0][1].set_title(u'每年获得的飞行常客里程数与每周消费的冰激淋公升数',FontProperties=font)
axs1_xlabel_text = axs[0][1].set_xlabel(u'每年获得的飞行常客里程数',FontProperties=font)
axs1_ylabel_text = axs[0][1].set_ylabel(u'每周消费的冰激淋公升数',FontProperties=font)
plt.setp(axs1_title_text, size=9, weight='bold', color='red')
plt.setp(axs1_xlabel_text, size=7, weight='bold', color='black')
plt.setp(axs1_ylabel_text, size=7, weight='bold', color='black')
#设置标题,x轴label,y轴label
axs[1][0].scatter(x=datingDataMat[:,1], y=datingDataMat[:,2], color=LabelsColors,s=15, alpha=.5)
#画出散点图,以datingDataMat矩阵的第二(玩游戏)、第三列(冰激凌)数据画散点数据,散点大小为15,透明度为0.5
axs2_title_text = axs[1][0].set_title(u'玩视频游戏所消耗时间占比与每周消费的冰激淋公升数',FontProperties=font)
axs2_xlabel_text = axs[1][0].set_xlabel(u'玩视频游戏所消耗时间占比',FontProperties=font)
axs2_ylabel_text = axs[1][0].set_ylabel(u'每周消费的冰激淋公升数',FontProperties=font)
plt.setp(axs2_title_text, size=9, weight='bold', color='red')
plt.setp(axs2_xlabel_text, size=7, weight='bold', color='black')
plt.setp(axs2_ylabel_text, size=7, weight='bold', color='black')
#设置标题,x轴label,y轴label
didntLike = mlines.Line2D([], [], color='black', marker='.',
markersize=6, label='didntLike') #设置图例
smallDoses = mlines.Line2D([], [], color='orange', marker='.',
markersize=6, label='smallDoses') #设置图例
largeDoses = mlines.Line2D([], [], color='red', marker='.',
markersize=6, label='largeDoses') #设置图例
axs[0][0].legend(handles=[didntLike,smallDoses,largeDoses])#添加图例
axs[0][1].legend(handles=[didntLike,smallDoses,largeDoses])#添加图例
axs[1][0].legend(handles=[didntLike,smallDoses,largeDoses])#添加图例
plt.show() #显示图片
"""
if __name__ == '__main__':
datingDataMat, datingLabels=file2matrix('datingTestSet.txt')
showdatas(datingDataMat, datingLabels)
#"""
#准备数据
def autoNorm(dataSet):
"""
函数说明:归一化特征值
"""
minVals = dataSet.min(0) #获得dataSet每列的最小值
maxVals = dataSet.max(0) #获得dataSet每列的最大值
ranges = maxVals - minVals #最大值和最小值的范围
normDataSet = zeros(shape(dataSet)) #shape(dataSet)返回dataSet的矩阵行列数
m = dataSet.shape[0] #返回dataSet的行数
normDataSet = dataSet - tile(minVals, (m, 1)) #原始值减去最小值
normDataSet = normDataSet / tile(ranges, (m, 1))
#除以最大和最小值的差,得到归一化数据
return normDataSet, ranges, minVals #返回归一化数据结果,数据范围,最小值
"""
if __name__ == '__main__':
normMat,ranges,minVals=autoNorm(datingDataMat)
print ('normMat=',normMat)
print ('ranges=',ranges)
print ('minVals=',minVals)
#输出:
#normMat= [[0.44832535 0.39805139 0.56233353]
#[0.15873259 0.34195467 0.98724416]
#[0.28542943 0.06892523 0.47449629]
#...
#[0.29115949 0.50910294 0.51079493]
#[0.52711097 0.43665451 0.4290048 ]
#[0.47940793 0.3768091 0.78571804]]
#ranges= [9.1273000e+04 2.0919349e+01 1.6943610e+00]
#minVals= [0. 0. 0.001156]
#"""
#测试算法
#分类器针对约会网站的测试代码
def datingClassTest():
datingDataMat, datingLabels = file2matrix("datingTestSet.txt")
hoRatio = 0.10 #取所有数据的百分之十
normMat, ranges, minVals = autoNorm(datingDataMat)
#数据归一化,返回归一化后的矩阵,数据范围,数据最小值
m = normMat.shape[0] #获得normMat的行数
numTestVecs = int(m * hoRatio) #百分之十的测试数据的个数
errorCount = 0.0 #初始化分类错误计数
for i in range(numTestVecs):
classifierResult = classify0(normMat[i,:], normMat[numTestVecs:m,:],
datingLabels[numTestVecs:m], 4)
#前numTestVecs个数据作为测试集,后m-numTestVecs个数据作为训练集
print("分类结果:%d\t真实类别:%d" % (classifierResult, datingLabels[i]))
if classifierResult != datingLabels[i]:
errorCount += 1.0
print("错误率:%f%%" %(errorCount/float(numTestVecs)*100))
#%f 匹配一个浮点数,后面的%%输出一个%,因为%是作为格式符号了,因此需要2个表示1个%字符
"""
if __name__ == '__main__':
datingClassTest()
#输出:
#错误率:4.000000%
#"""
#
def classifyPerson():
"""
函数说明:约会网站预测函数
"""
resultList = ['讨厌','有些喜欢','非常喜欢'] #输出结果
precentTats = float(input("玩视频游戏所耗时间百分比:"))
ffMiles = float(input("每年获得的飞行常客里程数:"))
iceCream = float(input("每周消费的冰激淋公升数:"))
datingDataMat, datingLabels = file2matrix("datingTestSet.txt") #生成训练数据集
normMat, ranges, minVals = autoNorm(datingDataMat) #训练集归一化
inArr = array([precentTats, ffMiles, iceCream]) #生成测试集
norminArr = (inArr - minVals) / ranges #测试集归一化
classifierResult = classify0(norminArr, normMat, datingLabels, 3)#返回分类结果
print("你可能%s这个人" % (resultList[classifierResult-1])) #打印结果
"""
if __name__ == '__main__':
classifyPerson()
#输出:
#玩视频游戏所耗时间百分比:10
#每年获得的飞行常客里程数:10000
#每周消费的冰激淋公升数:0.5
#你可能讨厌这个人
#"""
#示例:手写识别系统
#准备数据:将图像转换成测试向量
def img2vector(filename):
"""
函数说明:将32*32的二进制图像转换成1*1024的向量
"""
returnVect = zeros((1,1024)) #初始化一个1*1024零矩阵
fr = open(filename)
for i in range(32): #行数循环
lineStr = fr.readline() #读每一行
for j in range(32): #列数循环
returnVect[0,32*i+j] = int(lineStr[j])
#将每行32个字符转化为整型存入returnVect对应的位置
return returnVect
from os import listdir
def handwritingClassTest():
hwLabels = [] #初始化一个空列表来储存手写数字数据集的类别标签
trainingFileList = listdir('trainingDigits') #获取目录内容
#列出给定目录的文件名存入列表中,将这些文件名对应的文件作为训练集
m = len(trainingFileList) #文件名个数,也就是训练样本个数
trainingMat = zeros((m,1024)) #初始化训练特征矩阵,每行数据存储一个图像
for i in range(m): #从文件名解析分类数字
fileNameStr = trainingFileList[i]
fileStr = fileNameStr.split('.')[0] #去掉 .txt
#文件名是按一定规则命名的,切分文件名并取第一部分为文件名字符串,这些事先知道
classNumStr = int(fileStr.split('_')[0]) #取首字符为图像的实际数字
hwLabels.append(classNumStr) #类别标签依次存储在该向量中
trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
#将每个图像转化为向量后依次储存在特征矩阵trainingMat中
testFileList = listdir('testDigits') #存储测试集的文件名
errorCount = 0.0
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0]
classNumStr = int(fileStr.split('_')[0])
vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
#对每个测试样本依次进行分类
print (u"分类器返回: %d, 真实类别: %d" % (classifierResult, classNumStr))
if (classifierResult != classNumStr): errorCount += 1.0
print (u"分类错误总数: %d" % errorCount)
print (u"总错误率: %f%%" % (errorCount/float(mTest)))
"""
if __name__ =='__main__':
handwritingClassTest()
#输出:
#错误总数: 10
#总的错误率: 0.010571%
#"""
"""
Scikit-learn 也简称sklearn,是机器学习领域当中最知名的python模块之一。
sklearn包含了很多机器学习的方式:
•Classification 分类
•Regression 回归
•Clustering 非监督分类
•Dimensionality reduction 数据降维
•Model Selection 模型选择
•Preprocessing 数据与处理
使用sklearn可以很方便地让我们实现一个机器学习算法。
一个复杂度算法的实现,使用sklearn可能只需要调用几行API即可。
所以学习sklearn,可以有效减少我们特定任务的实现周期。
"""
from sklearn.neighbors import KNeighborsClassifier as kNN
def handwritingClassTest1():
hwLabels = [] #初始化一个空列表来储存手写数字数据集的类别标签
trainingFileList = listdir('trainingDigits') #获取目录内容
#列出给定目录的文件名存入列表中,将这些文件名对应的文件作为训练集
m = len(trainingFileList) #文件名个数,也就是训练样本个数
trainingMat = zeros((m,1024)) #初始化训练特征矩阵,每行数据存储一个图像
for i in range(m): #从文件名解析分类数字
fileNameStr = trainingFileList[i]
fileStr = fileNameStr.split('.')[0] #去掉 .txt
#文件名是按一定规则命名的,切分文件名并取第一部分为文件名字符串,这些事先知道
classNumStr = int(fileStr.split('_')[0]) #取首字符为图像的实际数字
hwLabels.append(classNumStr) #类别标签依次存储在该向量中
trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
#将每个图像转化为向量后依次储存在特征矩阵trainingMat中
neigh = kNN(n_neighbors = 3, algorithm = 'auto') #构建kNN分类器
neigh.fit(trainingMat, hwLabels)
#拟合模型, trainingMat为测试矩阵,hwLabels为对应的标签
testFileList = listdir('testDigits') #返回testDigits目录下的文件列表
errorCount = 0.0 #错误检测计数
mTest = len(testFileList) #测试数据的数量
for i in range(mTest):
fileNameStr = testFileList[i] #获得文件的名字
classNumber = int(fileNameStr.split('_')[0]) #获得分类的数字
vectorUnderTest = img2vector('testDigits/%s' % (fileNameStr))
#获得测试集的1x1024向量,用于训练
classifierResult = neigh.predict(vectorUnderTest) #获得预测结果
#对比classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
print("分类器返回:%d\t真实结果:%d" % (classifierResult, classNumber))
if(classifierResult != classNumber):
errorCount += 1.0
print("分类错误总数:%d\t总错误率:%f%%" % (errorCount, errorCount/mTest * 100))
#"""
if __name__ =='__main__':
handwritingClassTest1()
#输出:
#分类错误总数:12 总错误率:1.268499%
#"""
参考: https://blog.csdn.net/c406495762/article/details/75172850