1. 程式人生 > 程式設計 >原生python實現knn分類演算法

原生python實現knn分類演算法

一、題目要求

用原生Python實現knn分類演算法。

二、題目分析

資料來源:鳶尾花資料集(見附錄Iris.txt)

資料集包含150個數據集,分為3類,分別是:Iris Setosa(山鳶尾)、Iris Versicolour(雜色鳶尾)和Iris Virginica(維吉尼亞鳶尾)。每類有50個數據,每個資料包含四個屬性,分別是:Sepal.Length(花萼長度)、Sepal.Width(花萼寬度)、Petal.Length(花瓣長度)和Petal.Width(花瓣寬度)。

將得到的資料集按照7:3的比例劃分,其中7為訓練集,3為測試集。編寫演算法實現:學習訓練集的資料特徵來預測測試集鳶尾花的種類,並且計算出預測的準確性。

KNN是通過測量不同特徵值之間的距離進行分類。它的思路是:如果一個樣本在特徵空間中的k個最相似(即特徵空間中最鄰近)的樣本中的大多數屬於某一個類別,則該樣本也屬於這個類別,其中K通常是不大於20的整數。KNN演算法中,所選擇的鄰居都是已經正確分類的物件。該方法在定類決策上只依據最鄰近的一個或者幾個樣本的類別來決定待分樣本所屬的類別。

三、演算法設計

1)將文字檔案按行分割,寫入列表datas中

def data_read(filepath): # 讀取txt檔案,將讀出的內容存入datas列表中
  fp = open(filepath,"r")
  datas = [] # 儲存處理後的資料
  lines = fp.readlines() # 讀取整個檔案資料
  for line in lines:
    row = line.strip('\n').split(',') # 去除兩頭的換行符,按空格分割
    datas.append(row)
  fp.close()
  return datas

2)劃分資料集與測試集,將資料集的資料存入labeldata_list列表,標籤存入label_list列表,測試集資料存入text_list列表,標籤存入textlabel_list列表。

3)對得到的兩個資料集的資料和標籤列表進行處理。將labeldata_list列表資料轉換為元組labeldata_tuple,構造形入{labeldata_tuple: label_list}的字典mydict。這樣不僅可以去掉重複資料,而且可唯一的標識各個資料所對應的鳶尾花種類。

for i in range(0,105): # 資料集按照3:7的比例劃分,其中105行為訓練集,45行為測試集
  labeldata_list.append([datas[i][0],datas[i][1],datas[i][2],datas[i][3]])
  label_list.append(datas[i][4])

for i in range(105,150): # 測試集的資料
  text_list.append([datas[i][0],datas[i][3]])
  textlabel_list.append(datas[i][4])

j = 0
for i in labeldata_list:
  labeldata_tuple = tuple(i)
  mydict.update({labeldata_tuple: label_list[j]})
  j = j + 1

4)計算測試集資料與各個訓練集資料之間的距離,得到distance_list列表,外層迴圈進行一次,都會有一個該測試資料所對應的與訓練資料最短距離。標記出該距離對應的訓練集,在一個近鄰的條件下,這個訓練集的種類,就是該測試集的種類。
在計算距離時,使用絕對距離來計算。將每個訓練集對應資料的屬性值相減後求和add,得到一個測試資料與每個樣本的距離,add的最小值就是距離最小值。

for i in range(len(text_list)):
  count += 1
  for j in range(len(train_list)):
    add1 = abs(float(train_list[j][0]) - float(text_list[i][0])) + abs(float(train_list[j][1])
                                      - float(text_list[i][1])) + abs(
      float(train_list[j][2]) - float(text_list[i][2])) + abs(float(train_list[j][3])
                                  - float(text_list[i][3]))
    distance_list.append(add1)
    if add > add1:
      add = add1
      index = train_list[j]
  print("預測",text_list[i],"的標籤是:",mydict.get(index))

5)判斷預測結果的準確性:將預測的測試資料種類與原始資料對比,若相同,則分子加一。

right = 0 # 分子
count = 0 # 分母
for i in range(len(text_list)):
  count += 1
  for j in range(len(train_list)):
    add1 = abs(float(train_list[j][0]) - float(text_list[i][0])) + abs(float(train_list[j][1])
                                      - float(text_list[i][1])) + abs(
      float(train_list[j][2]) - float(text_list[i][2])) + abs(float(train_list[j][3])
                                  - float(text_list[i][3]))
    distance_list.append(add1)
    if add > add1:
      add = add1
      index = train_list[j]
  print("預測",mydict.get(index))
  if mydict.get(index) == textlabel_list[i]: # 當計算出來的1個近鄰與測試集正確的標籤相同時,分子加一
    right = right + 1
print('預測準確性:{:.2f}'.format(right / count))

6)舉例,繪圖

以測試集7.6,3.0,6.6,2.1,Iris-virginica為例:
首先運用anaconda繪製出資料集的散點圖,其次,將需要測試的資料於資料集繪製在同一張圖上,在一個近鄰的前提下,距離測試資料最近的點的標籤即為測試資料的的標籤。如下圖,黑色的測試點距離紅點最近,所以,測試資料的標籤就為virginica。

import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import load_iris  #匯入資料集iris
 
#載入資料集 
iris = load_iris() 
#獲取花卉兩列資料集 
DD = iris.data 
X = [x[0] for x in DD] 
Y = [x[1] for x in DD] 
#plt.scatter(7.6,color='black',marker='o')
plt.scatter(X[:50],Y[:50],color='red',marker='o',label='setosa') #前50個樣本
plt.scatter(X[50:100],Y[50:100],color='blue',marker='x',label='versicolor') #中間50個
plt.scatter(X[100:],Y[100:],color='green',marker='+',label='Virginica') #後50個樣本
plt.legend(loc=2) #左上角
plt.show()

演算法資料流圖:

在這裡插入圖片描述

計算各個測試資料與訓練集間距離詳細流程圖:

在這裡插入圖片描述

五、測試

匯入資料集

在這裡插入圖片描述

劃分資料集

訓練集:

在這裡插入圖片描述

測試集:

在這裡插入圖片描述

對得到的兩個資料集的資料和標籤列表進行處理

在這裡插入圖片描述

計算測試集資料與各個訓練集資料之間的距離

在這裡插入圖片描述

判斷預測結果的準確性

在這裡插入圖片描述

繪圖舉例

在這裡插入圖片描述

五、執行結果

1.對測試集所有資料進行預測,得到預測測試集的標籤與預測準確性

在這裡插入圖片描述

繪出散點圖:7.6,Iris-virginica作為測試集的舉例

在這裡插入圖片描述

六、總結

學習了關於繪圖的函式與庫
發現在繪圖方面anaconde比pycharm要方便的多

對向量之間的距離公式進行了複習
除了這次作業中使用到的絕對距離之外,還有:
a)歐氏距離
兩個n維向量a(x11,x12,…,x1n)與 b(x21,x22,x2n)間的歐氏距離:
在這裡插入圖片描述
b)曼哈頓距離
兩個n維向量a(x11,x2n)間的曼哈頓距離
在這裡插入圖片描述
c)閔可夫斯基距離
兩個n維變數a(x11,x2n)間的閔可夫斯基距離定義為:
在這裡插入圖片描述

對檔案的讀操作進行使用

演算法缺點:用了許多for迴圈,會降低效率,增加演算法的時間複雜度;只是一個近鄰的判斷依據

七、原始碼

def data_read(filepath): # 讀取txt檔案,將讀出的內容存入datas列表中
  fp = open(filepath,') # 去除兩頭的換行符,按空格分割
    datas.append(row)
  fp.close()
  return datas


datas = data_read("iris .txt")

labeldata_list = [] # 訓練集的資料
label_list = [] # 訓練集的標籤
text_list = [] # 測試集資料
textlabel_list = [] # 測試集標籤
labeldata_tuple = () # 轉換列表為元組
mydict = {} # 以四維資料為鍵,以鳶尾花的特徵為值。這樣便可唯一標識

'''
劃分資料集與測試集,將資料集的資料存入labeldata_list列表,標籤存入label_list列表,
測試集資料存入text_list列表,標籤存入textlabel_list列表。
'''
for i in range(0,datas[i][3]])
  textlabel_list.append(datas[i][4])

j = 0
for i in labeldata_list:
  labeldata_tuple = tuple(i)
  mydict.update({labeldata_tuple: label_list[j]})
  j = j + 1


add = 100
index = 0
distance_list = []
train_list = []
for key,value in mydict.items():
  train_list.append(key)

right = 0 # 分子
count = 0 # 分母
'''
在計算距離時,使用絕對距離來計算。
將每個訓練集對應資料的屬性值相減後求和add,
得到一個測試資料與每個樣本的距離,add的最小值就是距離最小值。
'''
for i in range(len(text_list)):
  count += 1
  for j in range(len(train_list)):
    add1 = abs(float(train_list[j][0]) - float(text_list[i][0])) + abs(float(train_list[j][1])
                                      - float(text_list[i][1])) + abs(
      float(train_list[j][2]) - float(text_list[i][2])) + abs(float(train_list[j][3])
                                  - float(text_list[i][3]))
    distance_list.append(add1)
    if add > add1:
      add = add1
      index = train_list[j]
  print("預測",mydict.get(index))
  if mydict.get(index) == textlabel_list[i]: # 當計算出來的1個近鄰與測試集正確的標籤相同時,分子加一
    right = right + 1
print('預測準確性:{:.2f}'.format(right / count))

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。