自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

用定租問題學透K近鄰算法

開發(fā) 前端 算法
k近鄰思想是我覺得最純粹最清晰的一個思想,k近鄰算法(KNN)只是這個思想在數(shù)據(jù)領(lǐng)域都一個應(yīng)用。

 [[405033]]

k近鄰思想是我覺得最純粹最清晰的一個思想,k近鄰算法(KNN)只是這個思想在數(shù)據(jù)領(lǐng)域都一個應(yīng)用。

你的工資由你周圍的人決定。

你的水平由你身邊最接近的人的水平?jīng)Q定。

你所看到的世界,由你身邊的人決定。

思想歸思想,不能被編碼那也無法應(yīng)用于數(shù)據(jù)科學領(lǐng)域。

我們提出問題,然后應(yīng)用該方法加以解決,以此加深我們對方法的理解。

問題: 假設(shè)你是airbnb平臺的房東,怎么給自己的房子定租金呢?

分析: 租客根據(jù)airbnb平臺上的租房信息,主要包括價格、臥室數(shù)量、房屋類型、位置等等挑選自己滿意的房子。給房子定租金是跟市場動態(tài)息息相關(guān)的,同樣類型的房子我們收費太高租客肯定不租,收費太低收益又不好。

解答: 收集跟我們房子條件差不多的一些房子信息,確定跟我們房子最相近的幾個,然后求其定價的平均值,以此作為我們房子的租金。

這就是K-Nearest Neighbors(KNN),k近鄰算法。KNN的核心思想是未標記樣本的類別,由距離其最近的k個鄰居投票決定。

本文就基于房租定價問題梳理下該算法應(yīng)用的全流程,包含如下部分。

  1. 讀入數(shù)據(jù)
  2. 數(shù)據(jù)處理
  3. 手寫算法代碼預(yù)測
  4. 利用sklearn作模型預(yù)測
  5. 超參優(yōu)化
  6. 交叉驗證
  7. 總結(jié)

提前聲明,本數(shù)據(jù)集是公開的,你可以在網(wǎng)上找到很多相關(guān)主題的材料,本文力圖解釋地完整且精準,如果你找到了更詳實的學習材料,那再好不過了。

1.讀入數(shù)據(jù)

先讀入數(shù)據(jù),了解下數(shù)據(jù)情況,發(fā)現(xiàn)目標變量price,以及cleaning_fee和security_deposit的格式有點問題,另有一些變量是字符型,都需要處理。我對dataframe進行了轉(zhuǎn)置顯示,方便查看。

2.數(shù)據(jù)處理

我們先只處理price,盡量集中在算法思想本身上面去。

  1. # 處理下目標變量price,并轉(zhuǎn)換成數(shù)值型 
  2. stripped_commas = dc_listings['price'].str.replace(','''
  3. stripped_dollars = stripped_commas.str.replace('$'''
  4. dc_listings['price'] = stripped_dollars.astype('float'
  5.  
  6. # k近鄰算法也是模型,需要劃分訓練集和測試集 
  7. sample_num = len(dc_listings) 
  8. # 在這我們先把數(shù)據(jù)隨機打散,保證數(shù)據(jù)集的切分隨機有效 
  9. dc_listings = dc_listings.loc[np.random.permutation(len(sample_num))] 
  10. train_df = dc_listings.iloc[0:int(0.7*sample_num)] 
  11. test_df = dc_listings.iloc[int(0.7*sample_num):] 

3.手寫算法代碼預(yù)測

根據(jù)k近鄰算法的定義直接編寫代碼,從簡單高效上考慮,我們僅針對單變量作預(yù)測。

入住人數(shù)應(yīng)該是和租金關(guān)聯(lián)度很高的信息,面積應(yīng)該也是。我們這里采用前者。

我們的目標是理解算法邏輯。實際操作中一般不會只考慮單一變量。

  1. # 注意,這兒是train_df 
  2. def predict_price(new_listing): 
  3.     temp_df = train_df.copy() 
  4.     temp_df['distance'] = temp_df['accommodates'].apply(lambda x: np.abs(x - new_listing)) 
  5.     temp_df = temp_df.sort_values('distance'
  6.     nearest_neighbor_prices = temp_df.iloc[0:5]['price'
  7.     predicted_price = nearest_neighbor_prices.mean() 
  8.     return(predicted_price) 
  9.  
  10. # 這兒是test_df 
  11. test_df['predicted_price'] = test_df['accommodates'].apply(predict_price) 
  12. # MAE(mean absolute error), MSE(mean squared error), RMSE(root mean squared error) 
  13. test_df['squared_error'] = (test_df['predicted_price'] - test_df['price'])**(2) 
  14. mse = test_df['squared_error'].mean() 
  15. rmse = mse ** (1/2) 

值得強調(diào)的是,模型算法的構(gòu)建都是基于訓練集的,預(yù)測評估基于測試集。應(yīng)用評估嚴格上還有一類樣本,oot:跨時間樣本。

從結(jié)果來看,即使我們只用了入住人數(shù)accommodates這一個變量去做近鄰選擇,預(yù)測結(jié)果也是很有效的。

4.利用sklearn作模型預(yù)測

這次我們要用更多的變量,只剔掉字符串和不可解釋的變量,剩下能用的變量都用上。

當用了多個變量的時候,這些不變量綱是不一樣的,我們需要進行標準化處理。保證了各自變量的分布差異,同時又保證變量之間可疊加。

  1. # 剔掉非數(shù)值型變量和不合適的變量 
  2. drop_columns = ['room_type''city''state''latitude''longitude''zipcode''host_response_rate''host_acceptance_rate''host_listings_count'
  3. dc_listings = dc_listings.drop(drop_columns, axis=1) 
  4. # 剔掉缺失比例過高的列(變量) 
  5. dc_listings = dc_listings.drop(['cleaning_fee''security_deposit'], axis=1) 
  6. # 剔掉有缺失值的行(樣本) 
  7. dc_listings = dc_listings.dropna(axis=0) 
  8. # 多個變量的量綱不一樣,需要標準化 
  9. normalized_listings = (dc_listings - dc_listings.mean())/(dc_listings.std()) 
  10. normalized_listings['price'] = dc_listings['price'
  11.  
  12. # 于是我們得到了可用于建模的數(shù)據(jù)集,7:3劃分訓練集測試集 
  13. train_df = normalized_listings.iloc[0:int(0.7*len(normalized_listings))] 
  14. test_df = normalized_listings.iloc[int(0.7*len(normalized_listings)):] 
  15. # price是y,其余變量都是X 
  16. features = train_df.columns.tolist() 
  17. features.remove('price'

處理后的數(shù)據(jù)集如下,其中price是我們要預(yù)測的目標,其余是可用的變量。

  1. from sklearn.neighbors import KNeighborsRegressor 
  2. from sklearn.metrics import mean_squared_error 
  3.  
  4. knn = KNeighborsRegressor(n_neighbors=5, algorithm='brute'
  5. knn.fit(train_df[features], train_df['price']) 
  6. predictions = knn.predict(test_df[features]) 
  7. mse = mean_squared_error(test_df['price'], predictions) 
  8. rmse = mse ** (1/2) 

最后得到的rmse=111.9,相比單變量knn的117.4要小,結(jié)果得到優(yōu)化。嚴格來說,這個對比不完全公平,因為我們丟掉了少量的特征缺失樣本。

5.超參優(yōu)化

在第3和第4部分,我們預(yù)設(shè)了k=5,但這個拍腦袋確定的。該取值合不合理,是不是最優(yōu),都需要進一步確定。

其中,這個k就是一個超參數(shù)。對于任何一個數(shù)據(jù)集,只要你用knn,就需要確定這個k值。

k值不是通過模型基于數(shù)據(jù)去學習得到的,而是通過預(yù)設(shè),然后根據(jù)結(jié)果反選確定的。任何一個超參數(shù)都是這樣確定的,其他算法也如此。

  1. import matplotlib.pyplot as plt 
  2. %matplotlib inline 
  3.  
  4. hyper_params = [x for x in range(1,21)] 
  5. rmse_values = [] 
  6. features = train_df.columns.tolist() 
  7. features.remove('price'
  8.  
  9. for hp in hyper_params: 
  10.     knn = KNeighborsRegressor(n_neighbors=hp, algorithm='brute'
  11.     knn.fit(train_df[features], train_df['price']) 
  12.     predictions = knn.predict(test_df[features]) 
  13.     mse = mean_squared_error(test_df['price'], predictions) 
  14.     rmse = mse**(1/2) 
  15.     rmse_values.append(rmse) 
  16.      
  17. plt.plot(hyper_params, rmse_values,c='r',linestyle='-',marker='+'

我們發(fā)現(xiàn),k越大,預(yù)測價格和真實價格的偏差從趨勢看會更準確。但要注意,k越大計算量就越大。

我們在確定k值時,可以用albow法,也就是看上圖的拐點,形象上就是手肘的肘部。

相比k=5,k=7或10可能是更好的結(jié)果。

6.交叉驗證

上面我們的計算結(jié)果完全依賴訓練集和測試集,雖然對它們的劃分我們已經(jīng)考慮了隨機性。但一次結(jié)果仍然具備偶爾性,尤其是當樣本量不夠大時。

交叉驗證就是為了解決這個問題。我們可以對同一個樣本集進行不同的訓練集測試集劃分。每次劃分后都重新進行訓練和預(yù)測,然后綜合去看待這些結(jié)果。

應(yīng)用最廣泛的是n折交叉驗證,其過程是隨機將數(shù)據(jù)集切分成n份,用其中n-1個子集做訓練集,剩余1個子集做測試集。這樣一共可以進行n次訓練和預(yù)測。

我們可以直接手寫該邏輯,如下。

  1. sample_num = len(normalized_listings) 
  2. normalized_listings.loc[normalized_listings.index[0:int(0.2*sample_num)], "fold"] = 1 
  3. normalized_listings.loc[normalized_listings.index[int(0.2*sample_num):int(0.4*sample_num)], "fold"] = 2 
  4. normalized_listings.loc[normalized_listings.index[int(0.4*sample_num):int(0.6*sample_num)], "fold"] = 3 
  5. normalized_listings.loc[normalized_listings.index[int(0.6*sample_num):int(0.8*sample_num)], "fold"] = 4 
  6. normalized_listings.loc[normalized_listings.index[int(0.8*sample_num):], "fold"] = 5 
  7.  
  8. fold_ids = [1,2,3,4,5] 
  9. def train_and_validate(df, folds): 
  10.     fold_rmses = [] 
  11.     for fold in folds: 
  12.         # Train 
  13.         model = KNeighborsRegressor() 
  14.         train = df[df["fold"] != fold] 
  15.         test = df[df["fold"] == fold].copy() 
  16.         model.fit(train[features], train["price"]) 
  17.         # Predict 
  18.         labels = model.predict(test[features]) 
  19.         test["predicted_price"] = labels 
  20.         mse = mean_squared_error(test["price"], test["predicted_price"]) 
  21.         rmse = mse**(1/2) 
  22.         fold_rmses.append(rmse) 
  23.     return(fold_rmses) 
  24.  
  25. rmses = train_and_validate(normalized_listings, fold_ids) 
  26. avg_rmse = np.mean(rmses) 

工程上,我們要充分利用工具和資源。sklearn庫就包含了我們常用的機器學習算法實現(xiàn),可以直接用來驗證。

  1. from sklearn.model_selection import cross_val_score, KFold 
  2. kf = KFold(5, shuffle=True, random_state=1) 
  3. model = KNeighborsRegressor() 
  4. mses = cross_val_score(model, normalized_listings[features], normalized_listings["price"], scoring="neg_mean_squared_error", cv=kf) 
  5. rmses = np.sqrt(np.absolute(mses)) 
  6. avg_rmse = np.mean(rmses) 

交叉驗證的結(jié)果置信度會更高,尤其是在小數(shù)據(jù)集上。因為它能夠一定程度地減輕偶然性誤差。

結(jié)合交叉驗證和超參優(yōu)化,我們一般就得到了該數(shù)據(jù)集下用knn算法預(yù)測的最優(yōu)結(jié)果。

  1. # 超參優(yōu)化 
  2. num_folds = [x for x in range(2,50,2)] 
  3. rmse_values = [] 
  4.  
  5. for fold in num_folds: 
  6.     kf = KFold(fold, shuffle=True, random_state=1) 
  7.     model = KNeighborsRegressor() 
  8.     mses = cross_val_score(model, normalized_listings[features], normalized_listings["price"], scoring="neg_mean_squared_error", cv=kf) 
  9.     rmses = np.sqrt(np.absolute(mses)) 
  10.     avg_rmse = np.mean(rmses) 
  11.     std_rmse = np.std(rmses) 
  12.     rmse_values.append(avg_rmse) 
  13.      
  14. plt.plot(num_folds, rmse_values,c='r',linestyle='-',marker='+'

我們得到了相同的趨勢,k越大,效果趨勢上更好。同時因為交叉驗證一定程度上解決了過擬合問題,理想的k值越大,模型可以更復(fù)雜些。

7.總結(jié)

從k-近鄰算法的核心思想以及以上編碼過程可以看出,該算法是基于實例的學習方法,因為它完全依靠訓練集里的實例。

該算法不需什么數(shù)學方法,很容易理解。但是非常不適合應(yīng)用在大數(shù)據(jù)集上,因為k-近鄰算法每一次預(yù)測都需要計算整個訓練集的數(shù)據(jù)到待預(yù)測數(shù)據(jù)的距離,然后增序排列,計算量巨大。

如果能用數(shù)學函數(shù)來描述數(shù)據(jù)集的特征變量與目標變量的關(guān)系,那么一旦用訓練集獲得了該函數(shù)表示,預(yù)測就是簡簡單單的數(shù)學計算問題了。計算復(fù)雜度大大降低。

其他的經(jīng)典機器學習算法基本都是一個函數(shù)表達問題。后面我們再看。

本文轉(zhuǎn)載自微信公眾號「 thunderbang」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系 thunderbang公眾號。

 

 

責任編輯:武曉燕 來源: thunderbang
相關(guān)推薦

2018-04-06 05:10:04

K-NN數(shù)據(jù)集算法

2020-06-30 07:00:00

推薦算法推薦系統(tǒng)

2022-04-06 08:58:39

歸并排序Go算法

2019-12-20 13:56:04

HTTPSTCP加密

2022-04-26 10:27:52

機器算法KNN數(shù)據(jù)

2023-09-25 08:32:03

Redis數(shù)據(jù)結(jié)構(gòu)

2023-10-04 00:32:01

數(shù)據(jù)結(jié)構(gòu)Redis

2010-05-04 17:05:29

DNS負載均衡

2024-11-26 09:30:00

模型算法

2022-10-28 15:19:28

機器學習距離度量數(shù)據(jù)集

2018-02-25 11:39:36

Python監(jiān)督學習算法

2022-11-22 08:00:00

開源工具數(shù)據(jù)集

2022-09-14 08:58:24

python高德API

2024-09-06 12:52:59

2020-12-22 10:10:10

算法代碼技術(shù)

2011-04-07 09:32:49

遞歸

2024-06-26 09:13:03

2021-12-20 10:39:30

TopK排序代碼

2024-10-12 17:13:53

2021-10-12 08:43:20

排列回溯算法
點贊
收藏

51CTO技術(shù)棧公眾號