・今日の頑張り見て
SIGNATEの練習問題をやってたら一日経ってた。下のリンクから見れる。
【練習問題】民泊サービスの宿泊価格予測 | SIGNATE - Data Science Competition
1. MINPAKU.py
データの確認やクレンジング(欠損値の保管や、データのダミー変数化)、変数の返還方針の決定、変換したデータの吐き出し、変数同士の相関をヒートマップで見てる。
import pandas as pdimport matplotlib.pyplot as pltimport seaborn as sns import numpy as np# CSV の読み込み data = pd.read_csv ('C: \\ work \\ SIGNATE \\ TRAIN_MINPAKU \\ train.csv ' )# 欠損地が何個あるか確認 # print(data.isnull().sum()) ''''' ・欠損のあるデータと補完の仕方 bathrooms :風呂の数 平均 bedrooms :ベッドルーム数 平均 beds :ベッド数 平均 first_review :最初のレビュー日 x host_has_profile_pic : ホストの写真があるかどうか f 埋め host_identity_verified :ホストの身元確認が取れているか f 埋め host_response_rate :ホストの返信率 平均 host_since :ホストの登録日 2020/1/1 last_review :最後のレビュー日 2020/1/1 neighbourhood :近隣情報 x review_scores_rating :レビュースコア 平均 thumbnail_url :サムネイル画像リンク x zipcode :郵便番号 x ・特徴量の選択、加工 1. 削除カラム id ,description ,name ,neiborhood , thumbnail_url ,zipcode latitude ,longitude 2. 加工カラム amenities ⇒ 文字データからアメニティの個数に加工、その後 amenities は drop bed_type ⇒ ダミー変数へ加工し drop cancellation_policy ⇒ ダミー変数へ加工し drop city ⇒ ダミー変数へ加工し drop cleaning_fee ⇒ダミー変数へ加工し drop last_review - host_since ⇒ 営業日数として扱う その後 first_review,last_review,host_since を drop host_has_profile_pic ⇒ダミー変数へ加工し drop host_identity_verified ⇒ダミー変数へ加工し drop instant_bookable ⇒ダミー変数にして drop property_type ⇒ダミー変数にして drop room_type ⇒ ダミー変数にして drop ''' # 欠損値を f で置換 data = data.fillna({'host_has_profile_pic' :'f' , 'host_identity_verified' :'f' })# ホストからの返信率は文字置換して数字型へ data['host_response_rate' ] = data['host_response_rate' ].str.replace('%' , '' ) data['host_response_rate' ] = data['host_response_rate' ].astype(float )# 欠損値を 平均値 で置換 data = data.fillna({'bathrooms' :data['bathrooms' ].mean() , 'bedrooms' :data['bedrooms' ].mean() , 'beds' :data['beds' ].mean() , 'host_response_rate' :data['host_response_rate' ].mean() , 'review_scores_rating' :data['review_scores_rating' ].mean()})# last_review - host_since を計算 # 日付のデータを - で分割 df_last = data['last_review' ].str.split('-' , expand =True ) df_since = data['host_since' ].str.split('-' , expand =True )# 欠損部分を平均で置換 df_last = df_last.fillna(df_last.astype(float ).mean()) df_since = df_since.fillna(df_since.astype(float ).mean())# period を営業している期間の長さとして定義 data = data.assign(period =365 *(df_last[0 ].astype(float )-df_since[0 ].astype(float )) + 30 *(df_last[1 ].astype(float )-df_since[1 ].astype(float )) + (df_last[2 ].astype(float )-df_since[2 ].astype(float )) )# アメニティの文字データをアメニティの個数データに変換 df_amenities = data['amenities' ].str.split(',' , expand =True ) data = data.assign(amenities =len (df_amenities.columns) - df_amenities.isnull().sum(axis =1 ))# 文字型の変数をダミー変数へ data = pd.get_dummies(data, drop _first =True, columns =['bed_type' , 'cancellation_policy' , 'city' , 'cleaning_fee' , 'host_has_profile_pic' , 'host_identity_verified' , 'instant_bookable' , 'room_type' ])# 不要なカラムを drop data = data.drop (['property_type' , 'last_review' , 'host_since' , 'id' , 'description' , 'first_review' , 'name' , 'neighbourhood' , 'thumbnail_url' , 'zipcode' , 'latitude' , 'longitude' ] , axis =1 )# 全て 1 のカラムを追加 data = data.assign(seppen =1 )# 欠損地があるか再確認 # print(data.isnull().sum()) data.to_csv ('train_trance.csv ' )# ---------------------- 変換ここまで ------------------------------------------------ # ---------------------- 可視化 ------------------------------------------------------ # ダミー変数を除く変数でヒートマップを描いてみる cols = ['accommodates' , 'amenities' , 'bathrooms' , 'bedrooms' , 'beds' , 'host_response_rate' , 'number_of_reviews' , 'review_scores_rating' , 'y' , 'period' ] cm = np.corrcoef(data[cols].values.T) heat_map = sns .heatmap(cm , cbar =True , annot =True , square =True , fmt ='.2f' , yticklabels =cols , xticklabels =cols) plt.tight_layout() plt.show()
>>出力
ヒートマップ
2. MINPAKU_LinerRegiression.py
回帰に使う変数や関数をクラスを定義して、線形単回帰と重回帰でパラメータを推定。テストデータで平均偏差を求めて、モデルの評価としてる。最後にSIGNATEのモデル評価用のデータを加工して、予測値を算出してcsv に吐いてる
import numpy as npimport pandas as pdfrom sklearn.model_selection import train_test_splitimport matplotlib.pyplot as plt# 加工した csv を読み込み df = pd.read_csv ('train_trance.csv ' )# ----------------------- 回帰の為のクラスを定義 ---------------------- class liner_Regression(object ): # 学習率とパラメータの更新回数を定義 def __init__ (self , eta =0.00000005 , n_iter =5000 ): self .eta = eta self .n_iter = n_iter # パラメータを推定する fit メソッドを定義 def fit (self , X, y): # パラメータ w を初期化 self .w = np.random.random(len (X.columns)) # 更新規則に則ってパラメータを更新 for i in range (self .n_iter ): # 推定値と実測値の誤差を計算 self .error = y - self .predict(X) # j 番目のパラメータを推定 for j in range (len (X.columns)): self .w[j] += self .eta * np.dot(X.iloc[:, j], self .error) return self # 入力に対して予測値を計算する関数を定義 def predict (self , X): return np.dot(X, self .w) # 平均 2 乗誤差を求める関数を定義 def error_ave_test (self , X, y): self .errors = y - self .predict(X) return np.sqrt(0.5 * (self .errors*self .errors).sum()/len (X))# ----------------------- クラスの定義ここまで ------------------------------------------ # 学習データとテストデータへ分割 df_train, df_test = train_test_split(df, test_size =0.4 )# ----------------------------------------- 単回帰モデルの実装 --------------------------------------- # 単回帰なので accommodates を説明変数にし、切片を求めるために seppen を抽出 data_train = df_train[['accommodates' , 'seppen' ]]# 目的変数に y を設定 target_train = df_train['y' ]# 回帰クラスをインスタンス 化 linerReg = liner_Regression()# fit メソッドを呼び出して、学習データに fit するパラメータを推定。 linerReg.fit(data_train, target_train)# モデルの性能を評価 error = linerReg.error_ave_test(data_train, target_train)print (' 単回帰のトレーニン グ 2 乗誤差: ' , error)# テストデータで 2 乗誤差を推定 data_test = df_test[['accommodates' , 'seppen' ]] target_test = df_test['y' ] test_error = linerReg.error_ave_test(data_test, target_test)print (' 単回帰のテスト 2 乗誤差 : ' , test_error)# ------------------------------ 重回帰モデルの推定 ---------------------------------------------------- # カラムを指定して説明変数を用意 colmuns = ['accommodates' , 'amenities' , 'bathrooms' , 'bedrooms' , 'beds' , 'bed_type_Couch ' , 'bed_type_Futon ' , 'bed_type_Pull-out Sofa' , 'bed_type_Real Bed' , 'cancellation_policy_moderate' , 'cancellation_policy_strict' , 'cancellation_policy_super_strict_30' , 'cancellation_policy_super_strict_60' , 'city_Chicago' , 'city_DC' , 'city_LA' , 'city_NYC' , 'city_SF' , 'cleaning_fee_t' , 'host_has_profile_pic_t' , 'host_identity_verified_t' , 'instant_bookable_t' , 'room_type_Private room' , 'room_type_Shared room' , 'seppen' ] data_train = df_train[colmuns]# 目的変数に y を設定 target_train = df_train['y' ]# 重回帰クラスをインスタンス 化 Multiple_regression = liner_Regression()# fit メソッドを呼び出して、学習データに fit するパラメータを推定。 Multiple_regression.fit(data_train, target_train)# モデルの性能を評価 error = Multiple_regression.error_ave_test(data_train, target_train)print (' 重回帰のトレーニン グ 2 乗誤差: ' , error)# テストデータで 2 乗誤差を推定 data_test = df_test[colmuns] target_test = df_test['y' ] test_error = Multiple_regression.error_ave_test(data_test, target_test)print (' 重回帰のテスト 2 乗誤差 : ' , test_error)# ----------------------- 予測した様子を可視化 ---------------------------------------------- plt.scatter(target_test, Multiple_regression.predict(data_test)) plt.xlabel('correct' ) plt.ylabel('predict' ) plt.show()# ------------------------------- テストデータから予測値を計算 ----------------------------------------------- # CSV の読み込み data = pd.read_csv ('C: \\ work \\ SIGNATE \\ TRAIN_MINPAKU \\ test.csv ' )# 欠損値を f で置換 data = data.fillna({'host_has_profile_pic' :'f' , 'host_identity_verified' :'f' })# ホストからの返信率は文字置換して数字型へ data['host_response_rate' ] = data['host_response_rate' ].str.replace('%' , '' ) data['host_response_rate' ] = data['host_response_rate' ].astype(float )# 欠損値を 平均値 で置換 data = data.fillna({'bathrooms' :data['bathrooms' ].mean() , 'bedrooms' :data['bedrooms' ].mean() , 'beds' :data['beds' ].mean() , 'host_response_rate' :data['host_response_rate' ].mean() , 'review_scores_rating' :data['review_scores_rating' ].mean()})# last_review - host_since を計算 # 日付のデータを - で分割 df_last = data['last_review' ].str.split('-' , expand =True ) df_since = data['host_since' ].str.split('-' , expand =True )# 欠損部分を平均で置換 df_last = df_last.fillna(df_last.astype(float ).mean()) df_since = df_since.fillna(df_since.astype(float ).mean())# period を営業している期間の長さとして定義 data = data.assign(period =365 *(df_last[0 ].astype(float )-df_since[0 ].astype(float )) + 30 *(df_last[1 ].astype(float )-df_since[1 ].astype(float )) + (df_last[2 ].astype(float )-df_since[2 ].astype(float )) )# アメニティの文字データをアメニティの個数データに変換 df_amenities = data['amenities' ].str.split(',' , expand =True ) data = data.assign(amenities =len (df_amenities.columns) - df_amenities.isnull().sum(axis =1 ))# 文字型の変数をダミー変数へ data = pd.get_dummies(data, drop _first =True, columns =['bed_type' , 'cancellation_policy' , 'city' , 'cleaning_fee' , 'host_has_profile_pic' , 'host_identity_verified' , 'instant_bookable' , 'property_type' , 'room_type' ])# 不要なカラムを drop data = data.drop (['last_review' , 'host_since' , 'id' , 'description' , 'first_review' , 'name' , 'neighbourhood' , 'thumbnail_url' , 'zipcode' , 'latitude' , 'longitude' ] , axis =1 )# 全て 1 のカラムを追加 data = data.assign(seppen =1 )# データから予測値を計算 data = data[colmuns] predicts = Multiple_regression.predict(data) predicts = pd.DataFrame(predicts) predicts.to_csv ('predicts.csv ' , header =None )# 参考 ----------------------- 正規方程式を使った回帰パラメータの推定 ------------------------------ def normal_equation (X, y): param = np.linalg.pinv(X.T.dot(X)).dot(X.T).dot(y) return param W = normal_equation(data_train, target_train)# --------------------------------------- ここまで ----------------------------------------------------
>>出力
単回帰のトレーニン グ2乗誤差: 101.35950150166111 単回帰のテスト2乗誤差 : 101.34383018796446 重回帰のトレーニン グ2乗誤差: 92.66598989721335 重回帰のテスト2乗誤差 : 92.4839200158771
プロセスは終了コード 0 で完了しました
まぁ重回帰の方が予測性能が良い、過学習 してる様子も見られないし、線形回帰の限界はこの辺りにありそう。まぁデータから有益な特徴量を作れれば話は別なんだけど、どうやって作るんだろ...。今度は非線形 の回帰も勉強してみるか...。因みに自分でクラスを定義したのは初めてだったんだけど、使ってみると便利さが分かるね...。
3. Nural_network_regression.py
線形回帰の限界をみたので、気になっているニューラルネットワーク 回帰に手を出してみた。中身はブラックボックス だけど、やっぱり予測の精度は重回帰より全然よかった。ただ使う分にはこれで問題ないのだけど、やっぱり使うからには中身で何やってるか理解しないと何か気持ち悪いな...。何も分かってなくても回帰より良い結果が得られちゃうの、ちょっと怖い。
import numpy as npimport pandas as pdfrom sklearn.neural_network import MLPRegressorfrom sklearn.model_selection import train_test_splitimport matplotlib.pyplot as plt# 加工した csv を読み込み df = pd.read_csv ('train_trance.csv ' )# 学習データとテストデータへ分割 df_train, df_test = train_test_split(df, test_size =0.4 ) colmuns = ['accommodates' , 'amenities' , 'bathrooms' , 'bedrooms' , 'beds' , 'bed_type_Couch ' , 'bed_type_Futon ' , 'bed_type_Pull-out Sofa' , 'bed_type_Real Bed' , 'cancellation_policy_moderate' , 'cancellation_policy_strict' , 'cancellation_policy_super_strict_30' , 'cancellation_policy_super_strict_60' , 'city_Chicago' , 'city_DC' , 'city_LA' , 'city_NYC' , 'city_SF' , 'cleaning_fee_t' , 'host_has_profile_pic_t' , 'host_identity_verified_t' , 'instant_bookable_t' , 'room_type_Private room' , 'room_type_Shared room' , 'seppen' ] data_train = df_train[colmuns]# 目的変数に y を設定 target_train = df_train['y' ]# ニューラル回帰をインスタンス 化 mlp = MLPRegressor(hidden_layer_sizes =(100 , ), max_iter =500 )mlp .fit(data_train, target_train)# テストデータの生成 data_test = df_test[colmuns] target_test = df_test['y' ]# predict 関数で予測値を計算 pred = mlp .predict(data_test)# 平均 2 乗誤差を計算 errors = np.sqrt(0.5 *((target_test - pred)*(target_test - pred)).sum()/len (pred))print (' ニューラルネットワーク 回帰の2 乗誤差: ' , errors) plt.scatter(target_test, pred) plt.xlabel('correct' ) plt.ylabel('predict' )# plt.show() # -------------------------- テストデータに対して予測値を計算 ----------------------------------- # CSV の読み込み data = pd.read_csv ('C: \\ work \\ SIGNATE \\ TRAIN_MINPAKU \\ test.csv ' )# 欠損値を f で置換 data = data.fillna({'host_has_profile_pic' :'f' , 'host_identity_verified' :'f' })# ホストからの返信率は文字置換して数字型へ data['host_response_rate' ] = data['host_response_rate' ].str.replace('%' , '' ) data['host_response_rate' ] = data['host_response_rate' ].astype(float )# 欠損値を 平均値 で置換 data = data.fillna({'bathrooms' :data['bathrooms' ].mean() , 'bedrooms' :data['bedrooms' ].mean() , 'beds' :data['beds' ].mean() , 'host_response_rate' :data['host_response_rate' ].mean() , 'review_scores_rating' :data['review_scores_rating' ].mean()})# last_review - host_since を計算 # 日付のデータを - で分割 df_last = data['last_review' ].str.split('-' , expand =True ) df_since = data['host_since' ].str.split('-' , expand =True )# 欠損部分を平均で置換 df_last = df_last.fillna(df_last.astype(float ).mean()) df_since = df_since.fillna(df_since.astype(float ).mean())# period を営業している期間の長さとして定義 data = data.assign(period =365 *(df_last[0 ].astype(float )-df_since[0 ].astype(float )) + 30 *(df_last[1 ].astype(float )-df_since[1 ].astype(float )) + (df_last[2 ].astype(float )-df_since[2 ].astype(float )) )# アメニティの文字データをアメニティの個数データに変換 df_amenities = data['amenities' ].str.split(',' , expand =True ) data = data.assign(amenities =len (df_amenities.columns) - df_amenities.isnull().sum(axis =1 ))# 文字型の変数をダミー変数へ data = pd.get_dummies(data, drop _first =True, columns =['bed_type' , 'cancellation_policy' , 'city' , 'cleaning_fee' , 'host_has_profile_pic' , 'host_identity_verified' , 'instant_bookable' , 'property_type' , 'room_type' ])# 不要なカラムを drop data = data.drop (['last_review' , 'host_since' , 'id' , 'description' , 'first_review' , 'name' , 'neighbourhood' , 'thumbnail_url' , 'zipcode' , 'latitude' , 'longitude' ] , axis =1 )# 全て 1 のカラムを追加 data = data.assign(seppen =1 ) colmuns = ['accommodates' , 'amenities' , 'bathrooms' , 'bedrooms' , 'beds' , 'bed_type_Couch ' , 'bed_type_Futon ' , 'bed_type_Pull-out Sofa' , 'bed_type_Real Bed' , 'cancellation_policy_moderate' , 'cancellation_policy_strict' , 'cancellation_policy_super_strict_30' , 'cancellation_policy_super_strict_60' , 'city_Chicago' , 'city_DC' , 'city_LA' , 'city_NYC' , 'city_SF' , 'cleaning_fee_t' , 'host_has_profile_pic_t' , 'host_identity_verified_t' , 'instant_bookable_t' , 'room_type_Private room' , 'room_type_Shared room' , 'seppen' ] data = data[colmuns]# predict 関数で予測値を計算して csv に吐き出す pred = mlp .predict(data) predicts = pd.DataFrame(pred) predicts.to_csv ('NN_predicts.csv ' , header =None )
>>出力
ConvergenceWarning: Stochastic Optimizer: Maximum iterations (500) reached and the optimization hasn't converged yet. % self.max_iter , ConvergenceWarning)ニューラルネットワーク 回帰の2乗誤差: 86.69826189432175
ちょっとエラーは言えるけど原因分から無し、でも結果は出てるから無視...。
以上。