一.KNN算法介紹
1.1簡要介紹
在模式識別領(lǐng)域中,最近鄰居法(KNN算法,又譯K-近鄰算法)是一種用于分類和回歸的非參數(shù)統(tǒng)計(jì)方法[1],由美國統(tǒng)計(jì)學(xué)家伊芙琳·費(fèi)克斯和小約瑟夫·霍奇斯于1951年首次提出,后來由托馬斯·寇弗擴(kuò)展。在這兩種情況下,輸入包含特征空間中的k個(gè)最接近的訓(xùn)練樣本。
- 在k-NN分類中,輸出是一個(gè)分類族群。一個(gè)對象的分類是由其鄰居的“多數(shù)表決”確定的,k個(gè)最近鄰居(k為正整數(shù),通常較?。┲凶畛R姷姆诸悰Q定了賦予該對象的類別。若k?=?1,則該對象的類別直接由最近的一個(gè)節(jié)點(diǎn)賦予。
- 在k-NN回歸中,輸出是該對象的屬性值。該值是其k個(gè)最近鄰居的值的平均值。
最近鄰居法采用向量空間模型來分類,概念為相同類別的案例,彼此的相似度高,而可以借由計(jì)算與已知類別案例之相似度,來評估未知類別案例可能的分類。
以上部分來自維基百科,大致意思就是根據(jù)已有數(shù)據(jù)的標(biāo)簽進(jìn)行新數(shù)據(jù)標(biāo)簽的預(yù)測,也就是說,通過一個(gè)人身邊高收入者的數(shù)量判斷這個(gè)人是不是高收入者,一個(gè)人身邊的高收入朋友越多,這個(gè)人就越有可能是高收入者。通過這個(gè)思路,通過了解這個(gè)人身邊富人朋友的數(shù)量是否多到一個(gè)閾值k,我們就可以預(yù)測其是否為富人。而這個(gè)k值,就是該算法的一個(gè)重點(diǎn)。
1.2 算法流程介紹
1.2.1數(shù)據(jù)收集
要進(jìn)行這個(gè)算法的實(shí)現(xiàn),首先需要一定的數(shù)據(jù)的訓(xùn)練和測試以確定預(yù)測正確率最高的k值,所以第一步時(shí)進(jìn)行數(shù)據(jù)的收集,這一步可以通過上網(wǎng)尋找或者通過其他大佬的博客進(jìn)行下載,或者通過調(diào)取python的sklearn庫中的內(nèi)置數(shù)據(jù)集進(jìn)行實(shí)現(xiàn)
1.2.2數(shù)據(jù)處理
這一步需要對已有的數(shù)據(jù)進(jìn)行結(jié)構(gòu)化處理,即對單個(gè)樣本擁有的標(biāo)簽進(jìn)行格式化規(guī)范化,形成表格式的數(shù)據(jù)集。
再之后,還需要對數(shù)據(jù)進(jìn)行歸一化或者賦予比重。因?yàn)椴糠謽颖静煌瑯?biāo)簽下的數(shù)據(jù)完全不成比例,在這種情況下如果完全不對其進(jìn)行處理,那么將會(huì)出現(xiàn)某個(gè)標(biāo)簽在進(jìn)行判斷時(shí)判斷權(quán)重很小甚至完全被忽略的情況。
進(jìn)行歸一化的公式為
即以該值減去該標(biāo)簽下的最小值除以標(biāo)簽下最大值和最小值的差,將數(shù)據(jù)進(jìn)行該處理后可保證哥哥標(biāo)簽下的范圍為[0,1]。
1.2.3 算法實(shí)施
該算法需要計(jì)算在n維空間中,預(yù)測點(diǎn)與其他已知樣本點(diǎn)的距離,然后選取與之最近的k個(gè)點(diǎn),然后在k個(gè)點(diǎn)中選取出現(xiàn)頻率最高的屬性,并將之作為預(yù)測結(jié)果。
此處的距離可采用歐幾里得距離,公式為
其中n值為標(biāo)簽數(shù)量,i表示第i個(gè)標(biāo)簽,x和y分別為預(yù)測點(diǎn)和已知樣本點(diǎn)。
二. 實(shí)操
2.1數(shù)據(jù)準(zhǔn)備
本次使用的數(shù)據(jù)為橙子蘋果梨的判斷,每個(gè)樣本點(diǎn)有兩個(gè)標(biāo)簽,分別為直徑和高度,范圍設(shè)置如下表格(范圍為帖主本人瞎編,數(shù)據(jù)集全部為隨機(jī)數(shù)生成,如有雷同純屬巧合)。
數(shù)據(jù)文本示例如下圖
此為一部分內(nèi)容,本次實(shí)踐設(shè)置了200個(gè)數(shù)據(jù)樣本作為訓(xùn)練集。
2.2 數(shù)據(jù)導(dǎo)入
首先導(dǎo)入保存于.txt中的數(shù)據(jù),對每行的數(shù)據(jù)進(jìn)行分割,并將前兩項(xiàng)數(shù)據(jù)加入至data_set中,標(biāo)簽存入lables中。
def createDataSet(filename):
data_set = [] # 保存數(shù)據(jù)
data_labels = [] # 保存標(biāo)簽
with open(filename, 'r', encoding='utf-8') as file:
for line in file:
d, h, name = line.strip().split(',')
data_set.append([int(d), int(h)])
data_labels.append(name)
return np.array(data_set), data_labels
2.3 數(shù)據(jù)歸一化
在這段函數(shù)中通過numpy庫的內(nèi)置函數(shù)找到訓(xùn)練集中的最大最小值并依照上面給出的公式進(jìn)行處理,最后返回處理過的數(shù)據(jù)。
def normalize(dataset, mydata):
mindata = np.min(dataset, axis=0) # axis=0按行進(jìn)行比較
maxdata = np.max(dataset, axis=0)
my_data = (mydata - mindata) / (maxdata - mindata)
data_set = (dataset - mindata) / (maxdata - mindata)
return data_set, my_data
2.4 knn算法主體部分
在這段函數(shù)中,通過.shape[0]獲取data_set的行數(shù),再通過numpy庫中的tile函數(shù),根據(jù)mydata生成一個(gè)與data_set行數(shù)相同的矩陣并與data_set進(jìn)行計(jì)算,獲取平方后再使用.sum方法,獲取平方后的各個(gè)值的和,再依據(jù)和的大小按從小到大的順序進(jìn)行排列。
完成排列后的列表中,依次選取k個(gè)值并獲取其數(shù)目最大的標(biāo)簽并且返回。
def knn(data_set, data_labels, k, mydata):
data_size = data_set.shape[0]
temp_distance = (np.tile(mydata, (data_size, 1)) - data_set) ** 2
distances = temp_distance.sum(axis=1) ** 0.5
sorted_distances_indices = distances.argsort()
data_dict = {}
for i in range(k):
data_label = data_labels[sorted_distances_indices[i]]
data_dict[data_label] = data_dict.get(data_label, 0) + 1
sort_dict = sorted(data_dict.items(), key=operator.itemgetter(1), reverse=True)
return sort_dict[0][0]
2.5 測試集的驗(yàn)證及k值的選取
knn算法的一個(gè)重點(diǎn)就是k值的選取,這個(gè)值的選取應(yīng)該通過驗(yàn)證來選取,因此,在這次實(shí)操中加載了一個(gè)含有100組數(shù)據(jù)的測試集,依次測試k的值不同時(shí)得到的正確率有多高,最后打印折線圖并且返回最佳的k
def find_k():
# 獲取數(shù)據(jù)集以及標(biāo)簽
data_set, data_labels = createDataSet("fruit_data.txt")
test_set, test_labels = createDataSet("fruit_2.txt")
# 初始化準(zhǔn)確率列表
accuracy_list = []
# 遍歷 k 值從 1 到 30
for k in range(1, 31):
correct_count = 0
# 遍歷測試集
for i in range(len(test_set)):
# 進(jìn)行歸一化
set_data, test_data = normalize(data_set, test_set[i])
# 使用 KNN 算法進(jìn)行預(yù)測
predicted_label = knn(set_data, data_labels, k, test_data)
# 比較預(yù)測結(jié)果與實(shí)際標(biāo)簽
if predicted_label == test_labels[i]:
correct_count += 1
# 計(jì)算準(zhǔn)確率
accuracy = correct_count / len(test_set)
accuracy_list.append(accuracy)
# 繪制準(zhǔn)確率隨 k 值變化的折線圖
plt.plot(range(1, 31), accuracy_list, marker='o', linestyle='-', color='blue', label='Accuracy')
plt.xlabel('k')
plt.ylabel("accuracy")
plt.title("result")
plt.legend()
plt.grid(True)
plt.show()
# 找出最優(yōu)的 k 值
max_accuracy = max(accuracy_list)
optimal_k = accuracy_list.index(max_accuracy) + 1
print(f"Best value of k: {optimal_k} with an accuracy of {max_accuracy:.2f}")
return optimal_k
最后得到的折線圖和結(jié)果如下
2.6主函數(shù)
依據(jù)find_k函數(shù)找到k值,再根據(jù)讀入的數(shù)據(jù)進(jìn)行判斷即可
def main():
# 獲取數(shù)據(jù)集以及標(biāo)簽
data_set, data_labels = createDataSet("fruit_data.txt")
my_test = [int(input("請輸入待分類水果的直徑:\n")), int(input("請輸入待分類水果的高:\n"))]
# 進(jìn)行歸一化
k = find_k()
set_data, test_data = normalize(data_set, my_test)
print('輸入的數(shù)據(jù)所對應(yīng)的水果類別是:{}'.format(knn(set_data, data_labels, k, test_data)))
結(jié)果圖如下
三.總結(jié)
本次實(shí)踐對knn算法有了一定的理解
首先其核心內(nèi)容易理解,思想較為簡單,但由于每次運(yùn)算都需要跑完全部的數(shù)據(jù)集,因而計(jì)算量較大,較為花費(fèi)時(shí)間。而當(dāng)k值選取有誤時(shí)容易出現(xiàn)過擬合現(xiàn)象。文章來源:http://www.zghlxwxcb.cn/news/detail-844907.html
作為本學(xué)期的第一個(gè)實(shí)驗(yàn),完整順下來之后對于python的函數(shù)等內(nèi)容有了一定的了解,但在編碼能力上還有欠缺,多多學(xué)習(xí)吧文章來源地址http://www.zghlxwxcb.cn/news/detail-844907.html
到了這里,關(guān)于K-NN算法實(shí)操及介紹的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!