Jack-Cherish 笔记
《机器学习实战》
1 计算未知点与样本的距离
2 距离递增排序
3 根据排序结果选出前K个样本
4 确定前k个样本的出现频率
5 频率最高的点的类别为结果
1
axis=0 #按行,向下压
axis=1 #按列,向右压
2 返回排序后的索引
In [23]:
dist.argsort()
Out[21]:
array([2, 3, 1, 0], dtype=int64)
In [23]:
dist.argsort()[:2]
Out[23]:
array([2, 3], dtype=int64)
在这里插入代码片
3 统计排序
import collections
In [33]:
collections.Counter(k_labels)
Out[33]:
Counter({'B': 2})
In [38]:
collections.Counter(k_labels).most_common(1) #得到1个频率最高的元素
Out[38]:
[('B', 2)]
In [41]:
collections.Counter(k_labels).most_common(1)[0]
Out[41]:
('B', 2)
In [42]:
collections.Counter(k_labels).most_common(1)[0][0]
Out[42]:
'B'
def classify0(inx,dataset,labels,k):
#1 计算距离
dist=np.sum((inx-dataset)**2,axis=1)*0.5
#从小到大排序,并返回索引,通过索引确定距离最近的K个标签
k_labels=[labels[index] for index in dist.argsort()[0:k]]
#选出前K个频率最高的标签
label=collections.Counter(k_labels).most_common(1)[0][0]
return label
fr=open('data/datingTestSet.txt')
fr.readlines()[0] #根据读取结果可知 用\t分割
>> '40920\t8.326976\t0.953952\tlargeDoses\n'
使用read_csv可读取txt文件,分隔符设置sep, 属性名用names指定,否则默认第一行数据为属性名
df=pd.read_csv('data/datingTestSet.txt',sep='\t',names=["flynums","gametime","icecream","rating"])
#前三列为特征矩阵
X_raw=df.iloc[:,[0,1,2]] #取部分列用iloc 索引方式
#得到的X_raw是dataframe格式
X_raw=X_raw.values #dataframe转ndarray
#Y同X
使用LabelEncoder标签处理为数字
from sklearn.preprocessing import LabelEncoder
y=LabelEncoder().fit_transform(Y_raw.flatten()) #使用flatten使二阶矩阵拉伸到一维
Y_raw
>>array([['largeDoses'],
['smallDoses'],
['didntLike'],
['didntLike'],
['didntLike'],
Y_raw.flatten()[:5]
>>array(['largeDoses', 'smallDoses', 'didntLike', 'didntLike', 'didntLike'],dtype=object)
y[:5]
>> array([1, 2, 0, 0, 0])
import matplotlib.pyplot as plt
#显示中文
plt.rcParams['font.sans-serif'] = [u'SimHei']
plt.rcParams['axes.unicode_minus'] = False
目标:共3个属性,对应3个标签。现设置3个子图,分别显示两两属性与3个标签之间的关系。需要使用不同颜色标识3个标签,并显示图例
网上查到的可以只画一次显示3种颜色,但是区分图例都是重新画3个图,再设置图例。目前的方法只有Jack所做的使用了mline。
#设置4个子图
fig,ax=plt.subplots(nrows=2,ncols=2,sharex=False,sharey=False,figsize=(13,8))
LabelsColors=[]
for i in y :
if i==0:
LabelsColors.append("black")
if i==1:
LabelsColors.append("orange")
if i==2:
LabelsColors.append("red")
#根据Y的值 生成每个点对应的颜色数组
print(LabelsColors[:5])
ax[0][0].scatter(X_raw[:,0],X_raw[:,1],color=LabelsColors)
ax[0][0].set_xlabel("每年获得的飞行常客里程数")
ax[0][0].set_ylabel("玩视频游戏所消耗时间占比")
ax[0][0].set_title("每年获得的飞行常客里程数与玩视频游戏所消耗时间占比")
#设置图例(学习jack)
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')
#添加图例
ax[0][0].legend(handles=[didntLike,smallDoses,largeDoses])
plt.show
另外两个图省略
对Matplotlib不熟悉,没有更好的方法
因为3个属性的值大小差距太大,需要进行归一化。
方法:
使用 new=(old - min) / (max -min) 可以使值归一到0-1
使用 new=(old - u) / (max -min) 可以使值归一到-1-1 (u为均值)
注意
求最大值最小值等 是求一个属性的最小值,而不是一个样本三个属性的最小值。也就是纵向求值,而不是横向求值。 axis=0 向下压
def autoNorm(X_raw):
minL=X_raw.min(0)
maxL=X_raw.max(0)
ranges=maxL-minL
meanL=X_raw.mean(0)
return (X_raw-meanL)/(maxL-minL),ranges
在Jupyter中使用另一个文件的方法,只需运行它就行
%run kNN.ipynb #引用另一个文件的方法
使用90%做训练集,10%测试集
给出的数据挺大的,
digits文件夹中分为trainingDigits和testDigits文件夹。每个文件夹使用 标签_标号 命名。图案是0 1 组成的数字。
图像为3232大小,需展成11024大小。
方法是先设置一个1*1024的0矩阵。然后读取每一行,再把每行的字符传给矩阵。
fr= open('data/digits/trainingDigits/0_0.txt')
returnVect=np.zeros((1,1024))
for i in range(32):
lineStr=fr.readline()
for j in range(32):
returnVect[0,32*i+j]=int(lineStr[j])
def img2vector(filename):
returnVect=np.zeros((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])
return returnVect
def handwritingClassTest:
#通过文件名分离出标签
trainLabels=[]
##返回trainingDigits目录下的文件名
trainingFileList=listdir("trainingDigits")
m=len(trainingFileList)
trainingMat=np.zeros((m,1024))
for i in range(m):
fileNameStr=trainingFileList[i]
#首先分隔后缀
fileStr=fileNameStr.split('.')[0]
#再分隔标签
classNumStr=int(fileStr.split('_')[0])
trainLabels.append(classNumStr)
#特征矩阵
trainingMat[i,:]=img2vector('trainingDigits/%s' %fileNameStr)
testFileList=listdir('testDigits')
errorCount=0
mTest=len(testFileList)
for i in range(mTest):
fileNameStr=testFileList[i]
fileStr=fileNameStr.split('.')[0]
classNumStr=int(fileStr.split('_')[0])
testLabels.append(classNumStr)
testVector=img2vector('testDigits/%s' %fileNameStr)
#测试,每次传入一个待判断数据
classResult=classify0(testVector,trainingMat,trainLabels,3)
if classResult!=classNumStr :
errorCount+=1
print(errorCount)
print(errorCount/mTest)
from sklearn.neighbors import KNeighborsClassifier as kNN
def handwritingClassTest:
testLabels=[]
trainLabels=[]
trainingFileList=listdir("trainingDigits")
m=len(trainingFileList)
trainingMat=np.zeros((m,1024))
for i in range(m):
fileNameStr=trainingFileList[i]
fileStr=fileNameStr.split('.')[0]
classNumStr=int(fileStr.split('_')[0])
trainLabels.append(classNumStr)
trainingMat[i,:]=img2vector('trainingDigits/%s' %fileNameStr)
#构建kNN分类器,algorithm是找临近点的算法,默认auto,由算法自己决定最合适的
neigh=kNN(n_neighbors=3,algorithm='auto')
#拟合模型
neigh.fit(trainingMat,trainLabels)
testFileList=listdir('testDigits')
errorCount=0
mTest=len(testFileList)
for i in range(mTest):
fileNameStr=testFileList[i]
fileStr=fileNameStr.split('.')[0]
classNumStr=int(fileStr.split('_')[0])
testLabels.append(classNumStr)
testVector=img2vector('testDigits/%s' %fileNameStr)
#返回预测结果
classResult=neigh.predict(testVector)
if classResult!=classNumStr :
errorCount+=1
print(errorCount)
print(errorCount/mTest)
运行超级慢就对了