全部課程
發(fā)布時(shí)間: 2019-09-25 14:13:40
舉個(gè)簡(jiǎn)單的例子,我們可以使用k-近鄰算法分類一個(gè)電影是愛情片還是動(dòng)作片。
上表就是我們已有的數(shù)據(jù)集合,也就是訓(xùn)練樣本集。這個(gè)數(shù)據(jù)集有兩個(gè)特征,即打斗鏡頭數(shù)和接吻鏡頭數(shù)。除此之外,我們也知道每個(gè)電影的所屬類型,即分類標(biāo)簽。用肉眼粗略地觀察,接吻鏡頭多的,是愛情片。打斗鏡頭多的,是動(dòng)作片。以我們多年的看片經(jīng)驗(yàn),這個(gè)分類還算合理。如果現(xiàn)在給我一部電影,你告訴我這個(gè)電影打斗鏡頭數(shù)和接吻鏡頭數(shù)。不告訴我這個(gè)電影類型,我可以根據(jù)你給我的信息進(jìn)行判斷,這個(gè)電影是屬于愛情片還是動(dòng)作片。而k-近鄰算法也可以像我們?nèi)艘粯幼龅竭@一點(diǎn),不同的地方在于,我們的經(jīng)驗(yàn)更”牛逼”,而k-鄰近算法是靠已有的數(shù)據(jù)。比如,你告訴我這個(gè)電影打斗鏡頭數(shù)為2,接吻鏡頭數(shù)為102,我的經(jīng)驗(yàn)會(huì)告訴你這個(gè)是愛情片,k-近鄰算法也會(huì)告訴你這個(gè)是愛情片。你又告訴我另一個(gè)電影打斗鏡頭數(shù)為49,接吻鏡頭數(shù)為51,我”邪惡”的經(jīng)驗(yàn)可能會(huì)告訴你,這有可能是個(gè)”愛情動(dòng)作片”,畫面太美,我不敢想象。 (如果說(shuō),你不知道”愛情動(dòng)作片”是什么?請(qǐng)?jiān)u論留言與我聯(lián)系,我需要你這樣像我一樣純潔的朋友。) 但是k-近鄰算法不會(huì)告訴你這些,因?yàn)樵谒难劾?,電影類型只有愛情片和?dòng)作片,它會(huì)提取樣本集中特征最相似數(shù)據(jù)(最鄰近)的分類標(biāo)簽,得到的結(jié)果可能是愛情片,也可能是動(dòng)作片,但絕不會(huì)是”愛情動(dòng)作片”。當(dāng)然,這些取決于數(shù)據(jù)集的大小以及最近鄰的判斷標(biāo)準(zhǔn)等因素。
2.距離度量
我們已經(jīng)知道k-近鄰算法根據(jù)特征比較,然后提取樣本集中特征最相似數(shù)據(jù)(最鄰近)的分類標(biāo)簽。那么,如何進(jìn)行比較呢?比如,我們還是以表2為例,怎么判斷紅色圓點(diǎn)標(biāo)記的電影所屬的類別呢?如下圖所示:
圖2?
??
通過(guò)計(jì)算可知,紅色圓點(diǎn)標(biāo)記的電影到動(dòng)作片 (108,5)的距離最近,為16.55。如果算法直接根據(jù)這個(gè)結(jié)果,判斷該紅色圓點(diǎn)標(biāo)記的電影為動(dòng)作片,這個(gè)算法就是最近鄰算法,而非k-近鄰算法。那么k-鄰近算法是什么呢?k-近鄰算法步驟如下:
1.計(jì)算已知類別數(shù)據(jù)集中的點(diǎn)與當(dāng)前點(diǎn)之間的距離;
2.按照距離遞增次序排序;
3.選取與當(dāng)前點(diǎn)距離最小的k個(gè)點(diǎn);
4.確定前k個(gè)點(diǎn)所在類別的出現(xiàn)頻率;
5.返回前k個(gè)點(diǎn)所出現(xiàn)頻率較高的類別作為當(dāng)前點(diǎn)的預(yù)測(cè)分類。
比如,現(xiàn)在我這個(gè)k值取3,那么在電影例子中,按距離依次排序的三個(gè)點(diǎn)分別是動(dòng)作片(108,5)、動(dòng)作片(115,8)、愛情片(5,89)。在這三個(gè)點(diǎn)中,動(dòng)作片出現(xiàn)的頻率為三分之二,愛情片出現(xiàn)的頻率為三分之一,所以該紅色圓點(diǎn)標(biāo)記的電影為動(dòng)作片。這個(gè)判別過(guò)程就是k-近鄰算法。
3.k近鄰算法實(shí)例-預(yù)測(cè)入住位置??
import pandas as pd from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.neighbors import KNeighborsClassifier from sklearn.preprocessing import StandardScaler ''' k近鄰 ''' def knncl(): #讀取數(shù)據(jù) data = pd.read_csv("../data/train.csv") #處理數(shù)據(jù),選擇一部分?jǐn)?shù)據(jù) data = data.query("x>1.0 & x <1.25 & y>2.5 & y<2.75") #處理時(shí)間戳 2016-10-21 20:30:00 time_value = pd.to_datetime(data["time"]) #將時(shí)間轉(zhuǎn)成日歷的格式 {"day":...,"hour":...} time_value = pd.DatetimeIndex(time_value) #增加日期、小時(shí)、星期等幾個(gè)特征 data["day"] = time_value.day data["hour"] = time_value.hour data["weekday"] = time_value.weekday # 把時(shí)間戳特征刪除 data = data.drop(["time"],axis=1) # 按place_id分組,統(tǒng)計(jì)每個(gè)位置的入住次數(shù) place_count = data.groupby("place_id").count() # print(place_count) # reset_index()將place_id單獨(dú)一列 tf = place_count[place_count.row_id > 3].reset_index() # 把簽到數(shù)據(jù)少于n個(gè)目標(biāo)位置刪除 data = data[data['place_id'].isin(tf.place_id)] # 取出數(shù)據(jù)中的特征值的目標(biāo)值 y = data['place_id'] x = data.drop(['place_id'], axis=1) # 數(shù)據(jù)集分割,分成訓(xùn)練集和測(cè)試集 x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25) # 特征工程,標(biāo)準(zhǔn)化處理 std = StandardScaler() # 對(duì)測(cè)試集和訓(xùn)練集的特征值進(jìn)行標(biāo)準(zhǔn)化 x_train = std.fit_transform(x_train) x_test = std.transform(x_test) print(data.head(10)) # 進(jìn)行算法流程 # 超參數(shù) knn = KNeighborsClassifier() knn.fit(x_train, y_train) y_predict = knn.predict(x_test) print("預(yù)測(cè)的目標(biāo)簽到位置為:", y_predict) # 得出準(zhǔn)確率 print("預(yù)測(cè)的準(zhǔn)確率:", knn.score(x_test, y_test)) #進(jìn)行算法流程 # 超參數(shù) #網(wǎng)絡(luò)搜索 # params = {"n_neighbors":[3,5,10]} # gc = GridSearchCV(knn,param_grid=params,cv=2) # gc.fit(x_train,y_train) # # #預(yù)測(cè)數(shù)據(jù) # print("在測(cè)試集上準(zhǔn)確率:", gc.score(x_test, y_test)) # print("在交叉驗(yàn)證當(dāng)中最好的結(jié)果:", gc.best_score_) # print("選擇最好的模型是:", gc.best_estimator_) # print("每個(gè)超參數(shù)每次交叉驗(yàn)證的結(jié)果:", gc.cv_results_) return None if __name__ == "__main__": knncl() |