爱情电影亲吻镜头更多,动作电影打斗场面更多
优点:精度高、对异常值不敏感、无数据输入假定
缺点:计算复杂度高、空间复杂度高
使用数据范围:数值型和标称型
KNN:对于要预测的点,将其放到数据集中去,距这个点最近的K个点的类别是已知的,要预测点的类别就是这K个类别中占比例最大的类别。
工作原理:
-
存在一个样本数据集合,也称训练样本集,并且样本集中的每个数据都存在标签,即知道样本集中每一数据所属分类的对应的关系。
-
输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似(最邻近)的分类标签。一般来说,选择样本数据集中前k各最相似的数据。
-
K-邻近算法一般流程
1.收集数据:可以使用任何方法
2.准备数据:距离计算所需要的数值,最好是结构化的数据格式
3.分析数据
4.训练算法:此步骤不适用于KNN算法
5.测试数据:计算错误率
6.使用算法:首先需要输入样本数据和结构化的输出结果,然后运行KNN判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理
KNN算法的缺点
1.算法必须保存全部数据集,如果训练集很大,必须使用大量的存储空间
2.由于对数据集中的每个数据计算距离值,实际使用可能非常耗时
3.它无法给出任何数据的基础结构信息,因此我们无法知晓平均实例样本和点行实例样本具有什么特征。
from numpy import * #科学计算包
import operator #运算符模块
import logging
def createDataSet():
"""创建数据集和标签"""
group = array([[1.0,1.1],[1.0,0.5],[0,0],[0,0.1]])
#向量labels包含了每个数据点的标签信息,包含的元素个数为group矩阵的行数
labels = ['A','C','B','B']
return group,labels
def classify0(inX,dataset,labels,k):
"""KNN算法
inX:用于分类的输入向量
dataset:输入的训练样本集
labels:标签向量
k:表示用于选择最近邻居的数目
1.计算已知类别数据集中的点与当前点之间的距离
2.按照距离递增次序排序
3.选取与当前点距离最小的k个点
4.确定前K个点所在类别的出现的概率
5.返回前k个点出现频率最高的类别作为当前点的预测类型
"""
data_set_size = dataset.shape[0] #获取矩阵的行数
diff_mat = tile(inX,(data_set_size,1))-dataset #np.tile将测试数据转换为与训练数据一样的形状并相减
sq_diff_mat = diff_mat**2
sq_distance = sq_diff_mat.sum(axis=1) #np.sum(axis=1)按行相加,不保持其维度
distances = sq_distance**0.5 #计算欧几里得距离
sorted_dist_indicies = distances.argsort()#np.argsort()对大小进行排序,并返回元素原来所在位置的索引
class_count = {}
for i in range(k):
vote_label = labels[sorted_dist_indicies[i]]
class_count[vote_label] = class_count.get(vote_label,0) +1
#将class_count字典分解为元组列表,然后使用itemgetter方法,按照第二个元素的次序对元组进行排序
sorted_class_count = sorted(
class_count.items(),
key=operator.itemgetter(1),
reverse=True
)
return sorted_class_count[0][0]
logger = logging.getLogger()
fh = logging.FileHandler('./KNN.log',encoding='utf-8')
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s-%(name)s-%(message)s')
fh.setLevel(logging.INFO)
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# try:
group,labels = createDataSet()
result = classify0([1.0,0.0],group,labels,2)
print(result)
# except Exception as e:
# print("未知错误")
logging.info("debug message")
#获取矩阵形状
# print(group.shape)
#获取矩阵的行数
# print(group.shape[0])
约会网站行为预测
import numpy as np
import matplotlib.pyplot as plt
import operator
class KNN_on_dateing(object):
"""
约会网站喜好预测
如何将数据改造成分类器可以使用的特征值。
在约会网站上使用kNN算法
1.收集数据:提供文本文件
2.准备数据:使用python解析文本文件
归一化处理:不同的数据尺度不一样,带来的影响也不同,old_value = (old_value - min)/(max - min)可以将任意取值范围的特征值转化为0到1区间内的值。其中Min和max分别为数据集中的最小特征值和最大特征值
3.分析数据:使用matplotlib画二维扩散图
4.训练算法:KNN算法不需要训练
5.测试算法:使用海伦提供的部分数据作为测试样本
通常使用训练数据的90%作为训练数据,10%作为测试数据,检测分类器的正确率。注意:10%的数据应该是随机选择的。
测试样本和非测试样本的区别在于:测试样本是已经完成分类的数据,如果预测分类与实际分类不同,则标记为一个错误
6.使用算法:产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否为自己喜欢的类型
"""
pass
def file2matrix(filename):
"""转换文本格式为Numpy数组"""
fr = open(filename)
array_oflines = fr.readlines()
number_oflines = len(array_oflines)
#40920 8.326976 0.953952 largeDoses
return_mat = np.zeros((number_oflines,3))
class_label_vector_string = []
class_label_vector = []
index = 0
for line in array_oflines:
line = line.strip() #截掉所有回车字符
list_formline = line.split('\t')
return_mat[index,:] = list_formline[0:3] #赋值给第index行所有数据
#class_label_vector.append(int(list_formline[-1],base=32)) #int()将字符串转换为整数,将label转换为整数
class_label_vector_string.append(list_formline[-1])
index +=1
for label in class_label_vector_string: #将label标签转换为整型数字
if label == 'largeDoses':
label = 1
class_label_vector.append(label)
elif label == 'smallDoses':
label = 2
class_label_vector.append(label)
else:
label = 3
class_label_vector.append(label)
return return_mat,class_label_vector
# dataset,label_vactor = file2matrix('./datingTestSet.txt')
# print(dataset)
# print(label_vactor)
def plot(x,y,label=None):
fig = plt.figure()
ax = fig.add_subplot(111)
#使用label标签对数据进行区别显示
ax.scatter(x,y,15.0*np.array(label),15.0*np.array(label))
plt.show()
# x,y = dataset[:,0],dataset[:,1]
# plot(x,y,label_vactor)
def autoNorm(dataset):
"""对数据集进行归一化处理,提高数据处理的效率\n
return norm_dataset,ranges,min_vals
"""
min_vals = dataset.min(0) #获取每列中的最小值1X3矩阵
print("最小值矩阵的形状是",min_vals.shape)
max_vals = dataset.max(0)
ranges = max_vals - min_vals
norm_dataset = np.zeros(np.shape(dataset))
m = dataset.shape[0] #获取矩阵的行数
norm_dataset = dataset - np.tile(min_vals,(m,1))
norm_dataset = norm_dataset/np.tile(ranges,(m,1)) #在numpy数组中,矩阵中的每个元素对应做数值运算,/,+,-,x.
#如果需要矩阵除法,使用函数linalg.solve(matA,matB)
return norm_dataset,ranges,min_vals
# normilized_dataset,ranges,min_vals,norm_label_vactor = auto_norm(dataset,label_vactor)
# print(normilized_dataset)
def classify0(inX,dataset,labels,k):
"""KNN算法
inX:用于分类的输入向量
dataset:输入的训练样本集
labels:标签向量
k:表示用于选择最近邻居的数目
1.计算已知类别数据集中的点与当前点之间的距离
2.按照距离递增次序排序
3.选取与当前点距离最小的k个点
4.确定前K个点所在类别的出现的概率
5.返回前k个点出现频率最高的类别作为当前点的预测类型
"""
data_set_size = dataset.shape[0] #获取矩阵的行数
diff_mat = np.tile(inX,(data_set_size,1))-dataset #np.tile将测试数据转换为与训练数据一样的形状并相减
sq_diff_mat = diff_mat**2
sq_distance = sq_diff_mat.sum(axis=1) #np.sum(axis=1)按行相加,不保持其维度
distances = sq_distance**0.5 #计算欧几里得距离
sorted_dist_indicies = distances.argsort()#np.argsort()对大小进行排序,并返回元素原来所在位置的索引
class_count = {}
for i in range(k):
#取出排名前k个的特征的label标签
vote_label = labels[sorted_dist_indicies[i]]
#计算前k个label中不同label的的个数,取个数最多的为预测数据的label
class_count[vote_label] = class_count.get(vote_label,0) +1 #Return the value for key if key is in the dictionary, else default.
#将class_count字典分解为元组列表,然后使用itemgetter方法,按照第二个元素的次序对元组进行排序
sorted_class_count = sorted(
class_count.items(),
key=operator.itemgetter(1),
reverse=True
)
return sorted_class_count[0][0]
def datingClassTest():
"""测试分类器效果,最后得到合适的训练集大小"""
ho_ratios = [0.02,0.05,0.10,0.15]
error_ratios = []
for ho_ratio in ho_ratios:
#对KNN来说,训练集越大,测试结果准确率越高
dating_data_mat,dating_labels = file2matrix('./datingTestSet.txt')
norm_mat,ranges,min_val = autoNorm(dating_data_mat)
m = norm_mat.shape[0]
num_test_vecs = int(m*ho_ratio) #用以区分测试数据集和训练数据集
error_count = 0.0
for i in range(num_test_vecs):
"""i->num_test_vecs 测试集,num_test_vects->m(norm_data_shape[0])训练集"""
classifier_result = classify0(norm_mat[i,:],norm_mat[num_test_vecs:m,:],dating_labels[num_test_vecs:m],3)
print("the classifier came back with:%d, the real answer is: %d" % (classifier_result,dating_labels[i]))
if (classifier_result != dating_labels[i]): error_count +=1.0
error_ratio = error_count/float(num_test_vecs)
error_ratios.append(error_ratio)
print("the ho_ratio is %f,the total error rate is:%f" % (ho_ratio,error_ratio))
return ho_ratios,error_ratios
# ho_ratios,error_ratios = datingClassTest()
# #可视化错误率与测试集大小之间的关系
# plt.plot(ho_ratios,error_ratios)
# plt.xlabel('ho_ratio')
# plt.ylabel('error_ratio')
# plt.show()
def classifyPerson():
"""约会网站预测函数"""
result_list = ['not at all','in small doses','in large doses']
percent_tats = float(input('percentage of time spent playing video games?'))
ff_miles = float(input('frequent flier miles earned per year?'))
ice_Cream = float(input('liters of ice cream consumed per year?'))
dating_data_mat,dating_labels = file2matrix('./datingTestSet.txt')
normMat,ranges,min_val = autoNorm(dating_data_mat)
inArr = np.array([ff_miles,percent_tats,ice_Cream])
classifier_result = classify0((inArr-min_val)/ranges,normMat,dating_labels,3)
print("You will probably like the person:",result_list[classifier_result-1])
classifyPerson()
手写体数字识别
from PIL import Image
import numpy as np
import os
import operator
def introduction():
"""
KNN算法实现手写体识别
1.收集数据:提供文本文件
2.准备数据:编写函数classify0(),将图像转换为分类器使用的list格式
3.分析数据:在python命令提示符中检查数据,确保它符合要求
4.训练算法:此步骤不适用于k-邻近算法
5.测试算法:编写函数使用提供的部分数据集作为测试样本,测试样本与非测试样本的区别在于测试样本是已经完成分类的数据,如果测试分类与实际类别不同,则标记为一个错误
6.使用算法:可从图像中提取数据,并完成数字识别。
"""
pass
def image2txt():
"""收集数据将图片转化为txt格式
调整图片大小32X32
"""
img=Image.open("G:/PM/data_analyse/testdata/7.png")
img_to_txt=open("G:/PM/data_analyse/testdata/7.txt","a")
#img.save("G:/PM/netcrawler_learning/7.png")#保存图片
width=img.size[0]
height=img.size[1]
#k=img.getpixel((1,9))#获取像素点(1,9)的颜色
#RGB:(0,0,0)black;(255,255,255)white
#print(k)
for i in range(0,height):#高在外层循环
for j in range(0,width):
clor=img.getpixel((j,i))#注意genpixel参数顺序与循环的匹配(宽,高)
clorall=clor[0]+clor[1]+clor[2]
if clorall==0:
img_to_txt.write("1")#若为黑色,写入1
else:
img_to_txt.write("0")
img_to_txt.write("\n")#换行
img_to_txt.close()
def img2vector(filename):
"""准备数据:将图片转换为向量,循环读出文件的前32行,并将每行的头32个字符值存储在Numpy数组中"""
return_vect = np.zeros((1,1024))
fr = open(filename)
for i in range(32):
line_str = fr.readline()
for j in range(32):
return_vect[0,32*i+j] = int(line_str[j])
return return_vect
def classify0(inX,dataset,labels,k):
"""KNN算法
inX:用于分类的输入向量
dataset:输入的训练样本集
labels:标签向量
k:表示用于选择最近邻居的数目
1.计算已知类别数据集中的点与当前点之间的距离
2.按照距离递增次序排序
3.选取与当前点距离最小的k个点
4.确定前K个点所在类别的出现的概率
5.返回前k个点出现频率最高的类别作为当前点的预测类型
"""
data_set_size = dataset.shape[0] #获取矩阵的行数
diff_mat = np.tile(inX,(data_set_size,1))-dataset #np.tile将测试数据转换为与训练数据一样的形状并相减
sq_diff_mat = diff_mat**2
sq_distance = sq_diff_mat.sum(axis=1) #np.sum(axis=1)按行相加,不保持其维度
distances = sq_distance**0.5 #计算欧几里得距离
sorted_dist_indicies = distances.argsort()#np.argsort()对大小进行排序,并返回元素原来所在位置的索引
class_count = {}
for i in range(k):
vote_label = labels[sorted_dist_indicies[i]]
class_count[vote_label] = class_count.get(vote_label,0) +1
#将class_count字典分解为元组列表,然后使用itemgetter方法,按照第二个元素的次序对元组进行排序
sorted_class_count = sorted(
class_count.items(),
key=operator.itemgetter(1),
reverse=True
)
return sorted_class_count[0][0]
def handwritingClassTest():
"""手写数字识别"""
hw_labels = []
training_filelist = os.listdir('./M_02_KNN_digits/trainingDigits')
m = len(training_filelist)
training_mat = np.zeros((m,1024))
for i in range(m):
#获取label
filename_str = training_filelist[i]
file_str = filename_str.split('.')[0]
classnum_str = int(file_str.split('_')[0])
hw_labels.append(classnum_str)
#获取文本信息
training_mat[i,:] = img2vector('./M_02_KNN_digits/trainingDigits/%s' % filename_str)
testfile_list = os.listdir('./M_02_KNN_digits/testDigits')
error_count = 0.0
mTest = len(testfile_list)
for i in range(mTest):
filename_str = testfile_list[i]
file_str = filename_str.split('.')[0]
classnum_str = int(file_str.split('_')[0])
vector_of_test = img2vector('./M_02_KNN_digits/testDigits/%s' % filename_str)
classifier_result = classify0(vector_of_test,training_mat,hw_labels,3)
print("the classifier came back with:%d,the real answer is:%d" % (classifier_result,classnum_str))
if (classifier_result != classnum_str): error_count += 1.0
print("\nthe total number of errors is:%d" % error_count)
print("\nthe total error rate is:%f" % (error_count/float(mTest)))
handwritingClassTest()