欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

机器学习 之k-近邻算法实战案例学习

程序员文章站 2024-02-10 15:52:22
...

机器学习之k-近邻算法案例实战

本博客讲解knn算法的实际案例运用,采用jupyter note逐步讲解,及后面用python进行封装,偏于读者对knn算法的整体了解。
本博客涉及两个小案例。
1、电影类别的分类
2、约会网站的分析

1、电影类别的分类

1.1 电影数据如图1

机器学习 之k-近邻算法实战案例学习
由图1知:
判断一个电影类型,我们用两个指标,打斗镜头和接吻镜头,通过这两个指标所占的数量来判断电影类型是动作片还是爱情片。
新电影的数据已知,我们采用knn近邻算法能够解决这个问题。

1.2 实现knn近邻算法(jupyter notebook)
#导入包
import pandas as pd
#1、导入数据
rowdata = {'电影名称':['无问西东','后来的我们','前任3','红海行动','唐人街探案','战狼2'],
           '打斗镜头':[1,5,12,108,112,115],
           '接吻镜头':[101,89,97,5,9,8],
           '电影类型':['爱情片','爱情片','爱情片','动作片','动作片','动作片']}

#将数据转换成二维表格形式
movie_data = pd.DataFrame(rowdata)
movie_data 

如图2:
机器学习 之k-近邻算法实战案例学习

#2、计算距离
#新电影数据
new_data = [24,67]
#计算距离
dist = list((((movie_data.iloc[:6,1:3] - new_data)**2).sum(1))**0.5)
dist

#3、将距离升序排序,然后选取距离最小的k个点
#将距离与标签对应
dist_label = pd.DataFrame({'dist':dist,'label':(movie_data.iloc[:6,1:3])})
dist_label
#升序
dist_label.sort_values(by = 'dist')
#4、确定前k个点所在类别的出现频率
k=4
dr = dist_label.sort_values(by = 'dist')[:k]
dr

如图3:
机器学习 之k-近邻算法实战案例学习

#5、确定前k个点所在类别的出现频率
re = dr.loc[:,'label'].value_counts()
re
#识别结果
result = []
result.append(re.index[0])
result
1.3 封装成函数
import pandas as pd

class Moviesort():
    #1、构建数据
    rowdata = {'电影名称':['无问西东','后来的我们','前任3','红海行动','唐人街探案','战狼2'],
                     '打斗镜头':[1,5,12,108,112,115],
                     '接吻镜头':[101,89,97,5,9,8],
                     '电影类型':['爱情片','爱情片','爱情片','动作片','动作片','动作片']}

    movie_data = pd.DataFrame(rowdata)
    #1、计算距离
    def distance(self,new_data):
        dist = list((((movie_data.iloc[:,1:3] - new_data)**2).sum(1))**0.5)
        return dist
    
    #2、找出前k个距离最近的值
    def dist_label(self,k):
        result = []
        #将距离与标签对应
        d_l = pd.DataFrame({'dist':dist,'label':(movie_data.iloc[:,3])})
        #对距离值做升序
        d_v = d_l.sort_values(by='dist')[:k]
        #对前k个标签进行统计
        label_num = d_v.loc[:,'label'].value_counts()
        re = label_num.index[0]
        result.append(re)
        return result
    
def main():
    
    m = Moviesort()
    #new_data=[24,67]
    m.distance([24,67])
    print(dist)
    #k=4
    m.dist_label(4)
    print(result)
        
    
if __name__ == '__main__':
    main()
    

2、约会网站数据分析

2.1 加载约会网站数据
datingTest = pd.read_table('datingTestSet.txt',header=None)
datingTest.head()
2.2 分析数据
%matplotlib inline 
import matplotlib as mpl 
import matplotlib.pyplot as plt

#将不同标签用颜色区分
colors = []
for i in range(datingTest.shape[0]):
    m = datingTest.iloc[i,-1]
    if m == 'didntLike':
        colors.append('black')
    elif m == 'smallDoses':
        colors.append('orange')
    elif m == 'largeDoses':
        colors.append('red')

#绘制两两特征之间的散点图
plt.rcParams['font.sans-serif'] = ['Simhei'] #图中字体设置为黑体
pl = plt.figure(figsize=(12,8))
fig1 = pl.add_subplot(221) #x,y,标签1
plt.scatter(datingTest.iloc[:,1],datingTest.iloc[:,2],marker='.',c=colors)
plt.xlabel('玩游戏视频所占时间比') 
plt.ylabel('每周消费冰激凌公升数')


fig2 = pl.add_subplot(222) #x,y,标签2
plt.scatter(datingTest.iloc[:,0],datingTest.iloc[:,1],marker='.',c=colors)
plt.xlabel('每年飞行常客里程') 
plt.ylabel('玩游戏视频所占时间比')


fig3 = pl.add_subplot(223) #x,y,标签3
plt.scatter(datingTest.iloc[:,0],datingTest.iloc[:,2],marker='.',c=colors)
plt.xlabel('每年飞行常客里程') 
plt.ylabel('每周消费冰激凌公升数')

plt.show()
    


3、数据归一化
'''
函数功能:归一化
参数说明:dataset:原始数据集
返回:0-1标准化之后的数据集
'''

def minmax(dataset):
    minDf = dataset.min()
    maxDf = dataset.max()
    normset = (dataset - minDf) / (maxDf - minDf)
    return normset

#将数据代入函数,进行归一化处理
datingT = pd.concat([minmax(datingTest.iloc[:,:3]),datingTest.iloc[:,3]],axis=1)
datingT
4、划分训练集与测试集
#90%的训练集,10%的测试集


'''
函数功能:切分训练集与测试集
参数说明:dataset:原始数据集
          rate:训练集所占比例
返回:切分好的训练集和测试集
'''
def randsplit(dataset,rate=0.9):
    n = dataset.shape[0] #行数
    m = int(n*rate) #训练集比例
    train = dataset.iloc[:m,:]
    test = dataset.iloc[m:,:]
    test.index = range(test.shape[0])
    return train,test

train,test = randsplit(datingT)
train
test


5、测试代码
'''
函数功能:k-近邻算法分类器
参数说明:
          train:训练集、
          test:测试集
          k:k-近邻参数,即选择距离最小的k个点
返回:预测好分类的测试集
'''
def datingclass(train,test,k):
    n = train.shape[1] - 1
    m = test.shape[0]
    result = []
    #k-近邻算法
    for i in range(m):
        #1、计算距离
        dist = list((((train.iloc[:,:n] - test.iloc[i,:n])**2).sum(1))**0.5)
        #2、取前k个距离最近值
        #test加标签
        d_l = pd.DataFrame({'dist':dist,'label':(train.iloc[:,n])})
        #对距离排序取前k个值
        dist_value = d_l.sort_values(by='dist')[:k]
        #统计类别数量
        label_num = dist_value.loc[:,'label'].value_counts()
        result.append(label_num.index[0]) #概率最大的标签在最前面
    
    result = pd.Series(result)
    test['predict'] = result
    acc = (test.iloc[:,-1] == test.iloc[:,-2]).mean()
    print(f'模型预测准确率为{acc}')
    print(dist_value)
    return test
2.3 用python函数封装
import pandas as pd
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt


class Data_knn:
    #1、数据准备
    dataloader = pd.read_table('datingTestSet.txt',header = None)
    datingTest = dataloader
    
    #2、数据归一化
    def data_norm(self,dataset):
        data = dataset.iloc[:,:3]
        minDf = data.min()
        maxDf = data.max()
        normset = (data - minDf) / (maxDf - minDf)
        return normset
    
    
    
    #2、分析数据
    def analyze_data(self,dataset):
        #把不同标签用颜色区分
        colors = []
        for i in range(datingTest.shape[0]):
            m = datingTest.iloc[i,-1]
            if m == 'didntLike':
                colors.append('black')
            elif m == 'smallDoses':
                colors.append('orange')
            elif m == 'largeDoses':
                colors.append('red')
                

        
        plt.rcParams['font.sans-serif'] = ['simhei'] #图中字体为黑体
        pl = plt.figure(figsize=(12,8))
        fig1 = pl.add_subplot(221)
        plt.scatter(datingTest.iloc[:,1],datingTest.iloc[:,2],marker='.',c=colors)
        plt.xlabel('玩游戏视频所占时间比')
        plt.ylabel('每周消费冰淇淋公升数')
        
        fig2 = pl.add_subplot(222)
        plt.scatter(datingTest.iloc[:,0],datingTest.iloc[:,1],marker='.',c=colors)
        plt.xlabel('每年飞行常客里程')
        plt.ylabel('玩游戏视频所占时间比')
        
        fig3 = pl.add_subplot(223)
        plt.scatter(datingTest.iloc[:,0],datingTest.iloc[:,2],marker='.',c=colors)
        plt.xlabel('每年飞行常客里程')
        plt.ylabel('每周消费冰淇淋公升数')
        
        plt.show()
        
    #训练   
    def test_knn(self,dataset,k,rate=0.9):
        #划分数据集
        n = dataset.shape[0]
        m = int(n*rate)
        train = dataset.iloc[:m,:]
        test = dataset.iloc[m:,:]
        #将test数据集索引从0开始
        test.index = range(test.shape[0])
        #k-近邻
        #计算距离
        a = train.shape[1] - 1
        b = test.shape[0]
        
        result = []
        for i in range(b):
            
            dist = list((((train.iloc[:,:a] - test.iloc[i,:a])**2).sum(1))**0.5)
            #给距离加标签
            d_l = pd.DataFrame({'dist':dist,'label':(train.iloc[:,-1])})
            #提取前面k个最小的距离
            d_v = d_l.sort_values(by='dist')[:k]
            #统计前k个标签的概率
            re = d_v.loc[:,'label'].value_counts()
            result.append(re.index[0])
        result = pd.Series(result)
        test['predict'] = result
        acc = (test.iloc[:,-1] == test.iloc[:,-2]).mean()
        print(f'模型预测准确率为{acc}')
        return test       

d = Data_knn()
test = d.test_knn(datingTest,k=5)
test
相关标签: 机器学习 算法