欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

python機(jī)器學(xué)習(xí)案例教程——K最近鄰算法的實(shí)現(xiàn)

 更新時(shí)間:2017年12月28日 10:31:56   作者:欒鵬  
本篇文章主要介紹了python機(jī)器學(xué)習(xí)案例教程——K最近鄰算法的實(shí)現(xiàn),詳細(xì)的介紹了K最近鄰算法的概念和示例,具有一定的參考價(jià)值,有興趣的可以了解一下

K最近鄰屬于一種分類算法,他的解釋最容易,近朱者赤,近墨者黑,我們想看一個(gè)人是什么樣的,看他的朋友是什么樣的就可以了。當(dāng)然其他還牽著到,看哪方面和朋友比較接近(對(duì)象特征),怎樣才算是跟朋友親近,一起吃飯還是一起逛街算是親近(距離函數(shù)),根據(jù)朋友的優(yōu)秀不優(yōu)秀如何評(píng)判目標(biāo)任務(wù)優(yōu)秀不優(yōu)秀(分類算法),是否不同優(yōu)秀程度的朋友和不同的接近程度要考慮一下(距離權(quán)重),看幾個(gè)朋友合適(k值),能否以分?jǐn)?shù)的形式表示優(yōu)秀度(概率分布)。

K最近鄰概念:

它的工作原理是:存在一個(gè)樣本數(shù)據(jù)集合,也稱作為訓(xùn)練樣本集,并且樣本集中每個(gè)數(shù)據(jù)都存在標(biāo)簽,即我們知道樣本集中每一個(gè)數(shù)據(jù)與所屬分類的對(duì)應(yīng)關(guān)系。輸入沒(méi)有標(biāo)簽的新數(shù)據(jù)后,將新的數(shù)據(jù)的每個(gè)特征與樣本集中數(shù)據(jù)對(duì)應(yīng)的特征進(jìn)行比較,然后算法提取樣本最相似數(shù)據(jù)(最近鄰)的分類標(biāo)簽。一般來(lái)說(shuō),我們只選擇樣本數(shù)據(jù)集中前k個(gè)最相似的數(shù)據(jù),這就是k-近鄰算法中k的出處,通常k是不大于20的整數(shù)。最后,選擇k個(gè)最相似數(shù)據(jù)中出現(xiàn)次數(shù)最多的分類,作為新數(shù)據(jù)的分類。

今天我們使用k最近鄰算法來(lái)構(gòu)建白酒的價(jià)格模型。

構(gòu)造數(shù)據(jù)集

構(gòu)建一個(gè)葡萄酒樣本數(shù)據(jù)集。白酒的價(jià)格跟等級(jí)、年代有很大的關(guān)系。

from random import random,randint
import math

# 根據(jù)等級(jí)和年代對(duì)價(jià)格進(jìn)行模擬
def wineprice(rating,age):
 peak_age=rating-50

 # 根據(jù)等級(jí)計(jì)算價(jià)格
 price=rating/2
 if age>peak_age:
  # 經(jīng)過(guò)“峰值年”,后續(xù)5年里其品質(zhì)將會(huì)變差
  price=price*(5-(age-peak_age)/2)
 else:
  # 價(jià)格在接近“峰值年”時(shí)會(huì)增加到原值的5倍
  price=price*(5*((age+1)/peak_age))
 if price<0: price=0
 return price

# 生成一批模式數(shù)據(jù)代表樣本數(shù)據(jù)集
def wineset1():
 rows=[]
 for i in range(300):
  # 隨機(jī)生成年代和等級(jí)
  rating=random()*50+50
  age=random()*50

  # 得到一個(gè)參考價(jià)格
  price=wineprice(rating,age)

  # 添加一些噪音
  price*=(random()*0.2+0.9)

  # 加入數(shù)據(jù)集
  rows.append({'input':(rating,age),'result':price})
 return rows

數(shù)據(jù)間的距離

使用k最近鄰,首先要知道那些最近鄰,也就要求知道數(shù)據(jù)間的距離。我們使用歐幾里得距離作為數(shù)據(jù)間的距離。

# 使用歐幾里得距離,定義距離
def euclidean(v1,v2):
 d=0.0
 for i in range(len(v1)):
  d+=(v1[i]-v2[i])**2
 return math.sqrt(d)

獲取與新數(shù)據(jù)距離最近的k個(gè)樣本數(shù)據(jù)

# 計(jì)算給預(yù)測(cè)商品和原數(shù)據(jù)集中任一其他商品間的距離。data原數(shù)據(jù)集,vec1預(yù)測(cè)商品
def getdistances(data,vec1):
 distancelist=[]

 # 遍歷數(shù)據(jù)集中的每一項(xiàng)
 for i in range(len(data)):
  vec2=data[i]['input']

  # 添加距離到距離列表
  distancelist.append((euclidean(vec1,vec2),i))

 # 距離排序
 distancelist.sort()
 return distancelist #返回距離列表

根據(jù)距離最近的k個(gè)樣本數(shù)據(jù)預(yù)測(cè)新數(shù)據(jù)的屬性

1、簡(jiǎn)單求均值

# 對(duì)距離值最小的前k個(gè)結(jié)果求平均
def knnestimate(data,vec1,k=5):
 # 得到經(jīng)過(guò)排序的距離值
 dlist=getdistances(data,vec1)
 avg=0.0

 # 對(duì)前k項(xiàng)結(jié)果求平均
 for i in range(k):
  idx=dlist[i][1]
  avg+=data[idx]['result']
 avg=avg/k
 return avg

2、求加權(quán)平均

如果使用直接求均值,有可能存在前k個(gè)最近鄰中,可能會(huì)存在距離很遠(yuǎn)的數(shù)據(jù),但是他仍然屬于最近的前K個(gè)數(shù)據(jù)。當(dāng)存在這種情況時(shí),對(duì)前k個(gè)樣本數(shù)據(jù)直接求均值會(huì)有偏差,所以使用加權(quán)平均,為較遠(yuǎn)的節(jié)點(diǎn)賦予較小的權(quán)值,對(duì)較近的節(jié)點(diǎn)賦予較大的權(quán)值。

那么具體該怎么根據(jù)數(shù)據(jù)間距離分配權(quán)值呢?這里使用三種遞減函數(shù)作為權(quán)值分配方法。

2.1、使用反函數(shù)為近鄰分配權(quán)重。

def inverseweight(dist,num=1.0,const=0.1):
 return num/(dist+const)

2.2、使用減法函數(shù)為近鄰分配權(quán)重。當(dāng)最近距離都大于const時(shí)不可用。

def subtractweight(dist,const=1.0):
 if dist>const:
  return 0
 else:
  return const-dist

2.3、使用高斯函數(shù)為距離分配權(quán)重。

def gaussian(dist,sigma=5.0):
 return math.e**(-dist**2/(2*sigma**2))

有了權(quán)值分配方法,下面就可以計(jì)算加權(quán)平均了。

# 對(duì)距離值最小的前k個(gè)結(jié)果求加權(quán)平均
def weightedknn(data,vec1,k=5,weightf=gaussian):
 # 得到距離值
 dlist=getdistances(data,vec1)
 avg=0.0
 totalweight=0.0

 # 得到加權(quán)平均
 for i in range(k):
  dist=dlist[i][0]
  idx=dlist[i][1]
  weight=weightf(dist)
  avg+=weight*data[idx]['result']
  totalweight+=weight
 if totalweight==0: return 0
 avg=avg/totalweight
 return avg

第一次測(cè)試

上面完成了使用k最近鄰進(jìn)行新數(shù)據(jù)預(yù)測(cè)的功能,下面我們進(jìn)行測(cè)試。

if __name__=='__main__': #只有在執(zhí)行當(dāng)前模塊時(shí)才會(huì)運(yùn)行此函數(shù)
 data = wineset1()  #創(chuàng)建第一批數(shù)據(jù)集
 result=knnestimate(data,(95.0,3.0)) #根據(jù)最近鄰直接求平均進(jìn)行預(yù)測(cè)
 print(result)

 result=weightedknn(data,(95.0,3.0),weightf=inverseweight) #使用反函數(shù)做權(quán)值分配方法,進(jìn)行加權(quán)平均
 print(result)
 result = weightedknn(data, (95.0, 3.0), weightf=subtractweight) # 使用減法函數(shù)做權(quán)值分配方法,進(jìn)行加權(quán)平均
 print(result)
 result = weightedknn(data, (95.0, 3.0), weightf=gaussian) # 使用高斯函數(shù)做權(quán)值分配方法,進(jìn)行加權(quán)平均
 print(result)

交叉驗(yàn)證

交叉驗(yàn)證是用來(lái)驗(yàn)證你的算法或算法參數(shù)的好壞,比如上面的加權(quán)分配算法我們有三種方式,究竟哪個(gè)更好呢?我們可以使用交叉驗(yàn)證進(jìn)行查看。

隨機(jī)選擇樣本數(shù)據(jù)集中95%作為訓(xùn)練集,5%作為新數(shù)據(jù),對(duì)新數(shù)據(jù)進(jìn)行預(yù)測(cè)并與已知結(jié)果進(jìn)行比較,查看算法效果。

要實(shí)現(xiàn)交叉驗(yàn)證,要實(shí)現(xiàn)將樣本數(shù)據(jù)集劃分為訓(xùn)練集和新數(shù)據(jù)兩個(gè)子集的功能。

# 劃分?jǐn)?shù)據(jù)。test測(cè)試數(shù)據(jù)集占的比例。其他數(shù)據(jù)集為訓(xùn)練數(shù)據(jù)
def dividedata(data,test=0.05):
 trainset=[]
 testset=[]
 for row in data:
  if random()<test:
   testset.append(row)
  else:
   trainset.append(row)
 return trainset,testset

還要能應(yīng)用算法,計(jì)算預(yù)測(cè)結(jié)果與真實(shí)結(jié)果之間的誤差度。

# 使用數(shù)據(jù)集對(duì)使用算法進(jìn)行預(yù)測(cè)的結(jié)果的誤差進(jìn)行統(tǒng)計(jì),一次判斷算法好壞。algf為算法函數(shù),trainset為訓(xùn)練數(shù)據(jù)集,testset為預(yù)測(cè)數(shù)據(jù)集
def testalgorithm(algf,trainset,testset):
 error=0.0
 for row in testset:
  guess=algf(trainset,row['input']) #這一步要和樣本數(shù)據(jù)的格式保持一致,列表內(nèi)個(gè)元素為一個(gè)字典,每個(gè)字典包含input和result兩個(gè)屬性。而且函數(shù)參數(shù)是列表和元組
  error+=(row['result']-guess)**2
  #print row['result'],guess
 #print error/len(testset)
 return error/len(testset)

有了數(shù)據(jù)拆分和算法性能誤差統(tǒng)計(jì)函數(shù)。我們就可以在原始數(shù)據(jù)集上進(jìn)行多次這樣的實(shí)驗(yàn),統(tǒng)計(jì)平均誤差。

# 將數(shù)據(jù)拆分和誤差統(tǒng)計(jì)合并在一起。對(duì)數(shù)據(jù)集進(jìn)行多次劃分,并驗(yàn)證算法好壞
def crossvalidate(algf,data,trials=100,test=0.1):
 error=0.0
 for i in range(trials):
  trainset,testset=dividedata(data,test)
  error+=testalgorithm(algf,trainset,testset)
 return error/trials

交叉驗(yàn)證測(cè)試

if __name__=='__main__': #只有在執(zhí)行當(dāng)前模塊時(shí)才會(huì)運(yùn)行此函數(shù)
 data = wineset1()  #創(chuàng)建第一批數(shù)據(jù)集
 print(data)
  error = crossvalidate(knnestimate,data) #對(duì)直接求均值算法進(jìn)行評(píng)估
 print('平均誤差:'+str(error))

 def knn3(d,v): return knnestimate(d,v,k=3) #定義一個(gè)函數(shù)指針。參數(shù)為d列表,v元組
 error = crossvalidate(knn3, data)   #對(duì)直接求均值算法進(jìn)行評(píng)估
 print('平均誤差:' + str(error))

 def knninverse(d,v): return weightedknn(d,v,weightf=inverseweight) #定義一個(gè)函數(shù)指針。參數(shù)為d列表,v元組
 error = crossvalidate(knninverse, data)   #對(duì)使用反函數(shù)做權(quán)值分配方法進(jìn)行評(píng)估
 print('平均誤差:' + str(error))

不同類型、值域的變量、無(wú)用變量

在樣本數(shù)據(jù)的各個(gè)屬性中可能并不是取值范圍相同的同類型的數(shù)據(jù),比如上面的酒的屬性可能包含檔次(0-100),酒的年限(0-50),酒的容量(三種容量375.0ml、750.0ml、1500.0ml),甚至在我們獲取的樣本數(shù)據(jù)中還有可能包含無(wú)用的數(shù)據(jù),比如酒生產(chǎn)的流水線號(hào)(1-20之間的整數(shù))。在計(jì)算樣本距離時(shí),取值范圍大的屬性的變化會(huì)嚴(yán)重影響取值范圍小的屬性的變化,以至于結(jié)果會(huì)忽略取值范圍小的屬性。而且無(wú)用屬性的變化也會(huì)增加數(shù)據(jù)之間的距離。

所以就要對(duì)樣本數(shù)據(jù)的屬性進(jìn)行縮放到合適的范圍,并要能刪除無(wú)效屬性。

構(gòu)造新的數(shù)據(jù)集

# 構(gòu)建新數(shù)據(jù)集,模擬不同類型變量的問(wèn)題
def wineset2():
 rows=[]
 for i in range(300):
  rating=random()*50+50 #酒的檔次
  age=random()*50   #酒的年限
  aisle=float(randint(1,20)) #酒的通道號(hào)(無(wú)關(guān)屬性)
  bottlesize=[375.0,750.0,1500.0][randint(0,2)] #酒的容量
  price=wineprice(rating,age) #酒的價(jià)格
  price*=(bottlesize/750)
  price*=(random()*0.2+0.9)
  rows.append({'input':(rating,age,aisle,bottlesize),'result':price})
 return rows

實(shí)現(xiàn)按比例對(duì)屬性的取值進(jìn)行縮放的功能

# 按比例對(duì)屬性進(jìn)行縮放,scale為各屬性的值的縮放比例。
def rescale(data,scale):
 scaleddata=[]
 for row in data:
  scaled=[scale[i]*row['input'][i] for i in range(len(scale))]
  scaleddata.append({'input':scaled,'result':row['result']})
 return scaleddata

那就剩下最后最后一個(gè)問(wèn)題,究竟各個(gè)屬性縮放多少呢。這是一個(gè)優(yōu)化問(wèn)題,我們可以通過(guò)優(yōu)化技術(shù)尋找最優(yōu)化解。而需要優(yōu)化的成本函數(shù),就是通過(guò)縮放以后進(jìn)行預(yù)測(cè)的結(jié)果與真實(shí)結(jié)果之間的誤差值。誤差值越小越好。誤差值的計(jì)算同前面交叉驗(yàn)證時(shí)使用的相同crossvalidate函數(shù)

下面構(gòu)建成本函數(shù)

# 生成成本函數(shù)。閉包
def createcostfunction(algf,data):
 def costf(scale):
  sdata=rescale(data,scale)
  return crossvalidate(algf,sdata,trials=10)
 return costf

weightdomain=[(0,10)]*4  #將縮放比例這個(gè)題解的取值范圍設(shè)置為0-10,可以自己設(shè)定,用于優(yōu)化算法

優(yōu)化技術(shù)的可以參看http://www.dbjr.com.cn/article/131719.htm

測(cè)試代碼

if __name__=='__main__': #只有在執(zhí)行當(dāng)前模塊時(shí)才會(huì)運(yùn)行此函數(shù)
 #========縮放比例優(yōu)化===
 data = wineset2() # 創(chuàng)建第2批數(shù)據(jù)集
 print(data)
 import optimization
 costf=createcostfunction(knnestimate,data)  #創(chuàng)建成本函數(shù)
 result = optimization.annealingoptimize(weightdomain,costf,step=2) #使用退火算法尋找最優(yōu)解
 print(result)

不對(duì)稱分布

對(duì)于樣本數(shù)據(jù)集包含多種分布情況時(shí),輸出結(jié)果我們也希望不唯一。我們可以使用概率結(jié)果進(jìn)行表示,輸出每種結(jié)果的值和出現(xiàn)的概率。

比如葡萄酒有可能是從折扣店購(gòu)買的,而樣本數(shù)據(jù)集中沒(méi)有記錄這一特性。所以樣本數(shù)據(jù)中價(jià)格存在兩種形式的分布。

構(gòu)造數(shù)據(jù)集

def wineset3():
 rows=wineset1()
 for row in rows:
  if random()<0.5:
   # 葡萄酒是從折扣店購(gòu)買的
   row['result']*=0.6
 return rows

如果以結(jié)果概率的形式存在,我們要能夠計(jì)算指定范圍的概率值

# 計(jì)算概率。data樣本數(shù)據(jù)集,vec1預(yù)測(cè)數(shù)據(jù),low,high結(jié)果范圍,weightf為根據(jù)距離進(jìn)行權(quán)值分配的函數(shù)
def probguess(data,vec1,low,high,k=5,weightf=gaussian):
 dlist=getdistances(data,vec1) #獲取距離列表
 nweight=0.0
 tweight=0.0

 for i in range(k):
  dist=dlist[i][0] #距離
  idx=dlist[i][1] #索引號(hào)
  weight=weightf(dist) #權(quán)值
  v=data[idx]['result'] #真實(shí)結(jié)果

  # 當(dāng)前數(shù)據(jù)點(diǎn)位于指定范圍內(nèi)么?
  if v>=low and v<=high:
   nweight+=weight #指定范圍的權(quán)值之和
  tweight+=weight  #總的權(quán)值之和
 if tweight==0: return 0

 # 概率等于位于指定范圍內(nèi)的權(quán)重值除以所有權(quán)重值
 return nweight/tweight

對(duì)于多種輸出、以概率和值的形式表示的結(jié)果,我們可以使用累積概率分布圖或概率密度圖的形式表現(xiàn)。

繪制累積概率分布圖

from pylab import *

# 繪制累積概率分布圖。data樣本數(shù)據(jù)集,vec1預(yù)測(cè)數(shù)據(jù),high取值最高點(diǎn),k近鄰范圍,weightf權(quán)值分配
def cumulativegraph(data,vec1,high,k=5,weightf=gaussian):
 t1=arange(0.0,high,0.1)
 cprob=array([probguess(data,vec1,0,v,k,weightf) for v in t1]) #預(yù)測(cè)產(chǎn)生的不同結(jié)果的概率
 plot(t1,cprob)
 show()

繪制概率密度圖

# 繪制概率密度圖
def probabilitygraph(data,vec1,high,k=5,weightf=gaussian,ss=5.0):
 # 建立一個(gè)代表價(jià)格的值域范圍
 t1=arange(0.0,high,0.1)

 # 得到整個(gè)值域范圍內(nèi)的所有概率
 probs=[probguess(data,vec1,v,v+0.1,k,weightf) for v in t1]

 # 通過(guò)加上近鄰概率的高斯計(jì)算結(jié)果,對(duì)概率值做平滑處理
 smoothed=[]
 for i in range(len(probs)):
  sv=0.0
  for j in range(0,len(probs)):
   dist=abs(i-j)*0.1
   weight=gaussian(dist,sigma=ss)
   sv+=weight*probs[j]
  smoothed.append(sv)
 smoothed=array(smoothed)

 plot(t1,smoothed)
 show()

測(cè)試代碼

if __name__=='__main__': #只有在執(zhí)行當(dāng)前模塊時(shí)才會(huì)運(yùn)行此函數(shù)

 data = wineset3() # 創(chuàng)建第3批數(shù)據(jù)集
 print(data)
 cumulativegraph(data,(1,1),120) #繪制累積概率密度
 probabilitygraph(data,(1,1),6) #繪制概率密度圖

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Python實(shí)現(xiàn)蟻群算法

    Python實(shí)現(xiàn)蟻群算法

    本文主要介紹了Python實(shí)現(xiàn)蟻群算法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • python字典嵌套字典的情況下找到某個(gè)key的value詳解

    python字典嵌套字典的情況下找到某個(gè)key的value詳解

    這篇文章主要介紹了python字典嵌套字典的情況下找到某個(gè)key的value詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • Python中turtle庫(kù)常用代碼匯總

    Python中turtle庫(kù)常用代碼匯總

    Turtle庫(kù)是Python語(yǔ)言中一個(gè)很流行的繪制圖像的函數(shù)庫(kù),下面這篇文章主要給大家介紹了關(guān)于Python中turtle庫(kù)常用代碼的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • OpenCV?讀取圖像imread的使用詳解

    OpenCV?讀取圖像imread的使用詳解

    這篇文章主要介紹了OpenCV?讀取圖像imread的使用詳解,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下
    2022-09-09
  • Python學(xué)習(xí)筆記之解析json的方法分析

    Python學(xué)習(xí)筆記之解析json的方法分析

    這篇文章主要介紹了Python解析json的方法,結(jié)合實(shí)例形式分析了常見的Python解析與轉(zhuǎn)換json格式數(shù)據(jù)相關(guān)操作技巧,需要的朋友可以參考下
    2017-04-04
  • python為什么會(huì)環(huán)境變量設(shè)置不成功

    python為什么會(huì)環(huán)境變量設(shè)置不成功

    在本篇文章里小編給大家分享的是一篇關(guān)于python環(huán)境變量設(shè)置不成功怎么辦的解決方法內(nèi)容,有興趣的朋友們可以跟著學(xué)習(xí)下。
    2020-06-06
  • python ChainMap 合并字典的實(shí)現(xiàn)步驟

    python ChainMap 合并字典的實(shí)現(xiàn)步驟

    這篇文章主要介紹了python ChainMap 合并字典的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • Python性能優(yōu)化的20條建議

    Python性能優(yōu)化的20條建議

    不論什么語(yǔ)言我們都需要注意性能優(yōu)化問(wèn)題,提高執(zhí)行效率,這里就為大家分享下Python的性能優(yōu)化技巧,需要的朋友可以參考下
    2014-10-10
  • PyCharm2019 安裝和配置教程詳解附激活碼

    PyCharm2019 安裝和配置教程詳解附激活碼

    這篇文章主要介紹了PyCharm2019 安裝和配置,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • 使用python的pyplot繪制函數(shù)實(shí)例

    使用python的pyplot繪制函數(shù)實(shí)例

    今天小編就為大家分享一篇使用python的pyplot繪制函數(shù)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-02-02

最新評(píng)論