Optunaでパラメータチューニングしてみた【第一弾】
このサイトを参考にOptunaでパラメータチューニングを初めてやってみた。
参考サイトは別のCSVのデータで行っていますが、こちらの記事ではsklearnに入っているデータを利用してみた。
参考サイトですごいなと思ったのは他のサイトであるあるな感じでoptunaで普通に単純にパラメータを出すだけではなく、rmse値を最小化するようにパラメータをチューニングする以下の関数
def objective(trial): params = {'metric': {'rmse'}, 'max_depth' : trial.suggest_int('max_depth', 1, 10), 'subsumple' : trial.suggest_uniform('subsumple', 0.0, 1.0), 'subsample_freq' : trial.suggest_int('subsample_freq', 0, 1), 'leaning_rate' : trial.suggest_loguniform('leaning_rate', 1e-5, 1), 'feature_fraction' : trial.suggest_uniform('feature_fraction', 0.0, 1.0), 'lambda_l1' : trial.suggest_uniform('lambda_l1' , 0.0, 1.0), 'lambda_l2' : trial.suggest_uniform('lambda_l2' , 0.0, 1.0)} gbm = lgb.train(params, lgb_train, valid_sets=(lgb_train, lgb_eval), num_boost_round=10000, early_stopping_rounds=100, verbose_eval=50) predicted = gbm.predict(X_test) RMSE = np.sqrt(mean_squared_error(y_test, predicted)) pruning_callback = optuna.integration.LightGBMPruningCallback(trial, 'rmse') return RMSE
を作っていたのが非常に面白かったので利用してみました。
以下がコードの全貌です。
#データセット用のライブラリ from sklearn import datasets, model_selection #データ分析用のライブラリ import pandas as pd import numpy as np #データ可視化ライブラリ import matplotlib.pyplot as plt import seaborn as sns #LightGBMライブラリ import lightgbm as lgb #訓練データとモデル評価用データに分けるライブラリ from sklearn.model_selection import train_test_split #ハイパーパラメータチューニング自動化ライブラリ import optuna #関数処理で必要なライブラリ from sklearn.metrics import mean_squared_error from sklearn.metrics import r2_score #その他 from sklearn import metrics #データ準備 features, labels = datasets.load_boston(return_X_y = True) #データ分割 X_train,X_test,y_train,y_test = train_test_split(features, labels, test_size=0.2) #LightGBM用のデータセットに加工 lgb_train = lgb.Dataset(X_train, y_train) lgb_eval = lgb.Dataset(X_test, y_test) #optunaへ入れる情報をまとめた関数 def objective(trial): params = {'metric': {'rmse'}, 'max_depth' : trial.suggest_int('max_depth', 1, 10), 'subsumple' : trial.suggest_uniform('subsumple', 0.0, 1.0), 'subsample_freq' : trial.suggest_int('subsample_freq', 0, 1), 'leaning_rate' : trial.suggest_loguniform('leaning_rate', 1e-5, 1), 'feature_fraction' : trial.suggest_uniform('feature_fraction', 0.0, 1.0), 'lambda_l1' : trial.suggest_uniform('lambda_l1' , 0.0, 1.0), 'lambda_l2' : trial.suggest_uniform('lambda_l2' , 0.0, 1.0)} gbm = lgb.train(params, lgb_train, valid_sets=(lgb_train, lgb_eval), num_boost_round=1000, early_stopping_rounds=100, verbose_eval=300) predicted = gbm.predict(X_test) RMSE = np.sqrt(mean_squared_error(y_test, predicted)) pruning_callback = optuna.integration.LightGBMPruningCallback(trial, 'rmse') return RMSE #optunaの起動 study = optuna.create_study() study.optimize(objective, timeout = 60) print('Best trial:') trial = study.best_trial print('Value:{}'.format(trial.value)) print('Paramas:') for key, value in trial.params.items(): print(',"{}":{}'.format(key, value)) #予測値と正解値を描写する関数 def True_Pred_map(pred_df): RMSE = np.sqrt(mean_squared_error(pred_df['true'], pred_df['pred'])) R2 = r2_score(pred_df['true'], pred_df['pred']) plt.figure(figsize=(8,8)) ax = plt.subplot(111) ax.scatter('true', 'pred', data=pred_df) ax.set_xlabel('True Value', fontsize=15) ax.set_ylabel('Pred Value', fontsize=15) ax.set_xlim(pred_df.min().min()-0.1 , pred_df.max().max()+0.1) ax.set_ylim(pred_df.min().min()-0.1 , pred_df.max().max()+0.1) x = np.linspace(pred_df.min().min()-0.1, pred_df.max().max()+0.1, 2) y = x ax.plot(x,y,'r-') plt.text(0.1, 0.9, 'RMSE = {}'.format(str(round(RMSE, 5))), transform=ax.transAxes, fontsize=15) plt.text(0.1, 0.8, 'R^2 = {}'.format(str(round(R2, 5))), transform=ax.transAxes, fontsize=15) #Optunaで最適化されたパラメータ params = { "metric": {'rmse'} ,"max_depth":4 ,"subsumple":0.5654007940457206 ,"subsample_freq":0 ,"leaning_rate":0.00017894703178220227 ,"feature_fraction":0.5230674363641012 ,"lambda_l1":0.7312452385011556 ,"lambda_l2":0.021966875171314314 } #LightGBMのモデル構築 model = lgb.train( params ,lgb_train ,valid_sets=(lgb_train, lgb_eval) ,num_boost_round=10000 ,early_stopping_rounds=100 ,verbose_eval=300 ) #モデル評価用データで予測値出力 y_pred = model.predict(X_test) #可視化関数にぶち込めるように予測値と正答値をデータフレームに加工 pred_df = pd.concat([pd.Series(y_test), pd.Series(y_pred)], axis=1) pred_df.columns = ['true', 'pred'] #可視化関数を実行 True_Pred_map(pred_df) # 特徴量の重要度をプロット lgb.plot_importance(model)
何もしていないのに結構精度が良くてさすがLightGBMとOptunaですね。
InstagramのAPIをGASを使って叩いてみた
参考の記事はこちら
qiita.com
InstagramのAPIに関するアクセストークンやIDは簡単に取得できず、FacebookのAPIから何度かAIPを叩いてようやく取得というのが本当にめんどくさい。
以下コードを転載します。
function reporting(){ var today = new Date(); //instagram数値記録用のスプレットシートID var SSId = '【スプレッドシートID】'; //instagram Graph API 必要情報 var instragramID = '【InstagramのビジネスアカウントID】'; var username = '【Instagramユーザー名】'; var ACCESS_TOKEN = "【アクセストークンC】"; getFollower(today,SSId,instragramID,username,ACCESS_TOKEN); } //instagramの数値を引っ張り記録する関数 function getFollower(date,SSId,instragramID,username,ACCESS_TOKEN) { var mySS = SpreadsheetApp.openById(SSId); //IDでスプレッドシートを開く var sheetName = username; //シートの名前をインスタユーザー名 var sheet = mySS.getSheetByName(sheetName); //日付フォーマット var today = Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy/MM/dd'); //Graph API followers_count(フォロワー数),follows_count(フォロー数),media_count(投稿数)を取りに行く var facebook_url = 'https://graph.facebook.com/v4.0/'+ instragramID +'?fields=business_discovery.username('+ username +'){followers_count,follows_count,media_count}&access_token='+ ACCESS_TOKEN; var encodedURI = encodeURI(facebook_url); var response = UrlFetchApp.fetch(encodedURI); //URLから情報を取得 var jsonData = JSON.parse(response);//JSONデータをパース var followers = jsonData['business_discovery']['followers_count']; var follows = jsonData['business_discovery']['follows_count']; var media_count = jsonData['business_discovery']['media_count']; //シートにデータを追加またはアップデート var newData =[today,followers,follows,media_count]; insertOrUpdate(sheet, newData); } //行の存在に応じて追加もしくは更新を行う関数 function insertOrUpdate(sheet, data) { var row = findRow(sheet, data[0]);//日付比較の関数、行番号を受け取る if (row) { // 行が見つかったら更新 sheet.getRange(row, 1, 1, data.length).setValues([data]); } else { // 行が見つからなかったら新しくデータを挿入 sheet.appendRow(data); } } // 日付比較を行い、データがあれば行番号を返す関数 function findRow(sheet, date) { var searchDate = Utilities.formatDate(new Date(date), 'Asia/Tokyo','yyyy/MM/dd'); var values = sheet.getDataRange().getValues(); Logger.log(values + "findRow"); for (var i = values.length - 1; i > 0; i--) { var dataDate = Utilities.formatDate(new Date(values[i][0]), 'Asia/Tokyo','yyyy/MM/dd'); if (dataDate == searchDate) { return i + 1; } } return false; }
SQLインジェクション脆弱性を持つサイトを作ってみた
dev.classmethod.jp
ここのサイトを真似してSQLインジェクション脆弱性を持つサイトを作ろうとしたら色々とハマったので覚書。
※そもそもPHPでデータベースに接続することすらしたことない素人が頑張ってみました。
まずはログイン画面(これは上のサイトのソースをそのままコピペ)
■index.html
<html> <meta charset="UTF-8"> <head> <title>ログイン画面</title> </head> <body> <form action="db.php" method="post"> <table> <tr> <td>ユーザID</td> <td><input type="text" name="uid"></td> </tr> <tr> <td>パスワード</td> <td><input type="text" name="password"></td> </tr> </table> <input type="submit" value="ログイン"> </form> </body> </html>
次にデータベース接続を行ったりSELECT文を実行するページこれがこのページの最初に書いたブログでは情報が古くてそのままコピペできなかった。
ということでこちらは以下のQiitaの記事等を色々と参照。
■単純な接続部分
qiita.com
■接続確認コード含む等
kahoo.blog
■db.php
<html> <meta charset="UTF-8"> <head> <title>ログイン処理</title> </head> <body> <?php // エラーを出力する ini_set('display_errors', "On"); // defineの値は環境によって変えてください。 define('HOSTNAME', 'localhost'); define('DATABASE', 'system'); define('USERNAME', 'root'); define('PASSWORD', 'root'); //入力されたIDとpassword $uid = $_POST['uid']; $pass = $_POST['password']; //データベース接続 $db = new PDO('mysql:host=' . HOSTNAME . ';dbname=' . DATABASE, USERNAME, PASSWORD); //SQL実行と結果 $sql = "SELECT email FROM users where uid='$uid' AND passwd='{$pass}'"; $stmt = $db->query($sql); $stmt->execute(); $count=$stmt->rowCount(); //入力に誤りがあった場合 if ($count == 0) { echo "ユーザ名または、パスワードに誤りがあります。"; exit; } //SQLで取得したデータを表示 while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) { print('email addressはこちらです '.$result['email']); print('<br>'); } $dbh = null; ?> <a href="index.html">ログイン画面に戻る</a> </body> </html>
なお、IDやパスワードが誤っていた場合は取得した結果が0行ということで判別しているが、PDOで行数(レコード数)をカウントする関数がなくてややこしかった。それくらい用意してくれよ。このブログを参考にして解決できたから良いけど。
www.php-mysql-linux.com
■データベース
systemというデータベースにusersテーブルを作成する。テーブルの中身はこんな感じ。
usersテーブルを作成します。
uid | varchar(20) |
passwd | varchar(20) |
varchar(20) |
レコードは2レコード以上入れておきましょう。
■SQLインジェクションを試してみる
パスワード欄に「'OR 'A' = 'A」と入れると全ユーザのデータが表示されて情報漏洩が起こることが確認できると思います。
LightGBMのサンプルはどれが一番良いか
個人的にはここのサンプルが最も理解しやすかったので忘れないように書いておく
mathmatical22.xyz
あとはこの記事が初めてLightGBMを触った際に参考にさせてもらったブログということでこちらも記載
qiita.com
こういうサンプルを上げられる人ってすごいな〜。
日々精進しないと。
pandasで条件に合わせてデータを書き換える
■lambdaを利用する方法
#0,1でフラグを立てる時には便利 #columnsの値が'ok'の場合colums1を1にしてそれ以外の場合には0にする df['column1'] = df['column2'].apply(lambda x: 1 if x == 'ok' else 0)
■maskを利用する方法
#条件を満たす場合のみ値を変更 #columnsの値が'ok'の場合colums1を1にしてそれ以外の場合にはそのまま df['column1'] = df['column1'].mask(df['column2'] == 'ok', 1)
■whereを利用する方法
#maskの反対で条件を満たさない場合にのみ値を変更 #columnsの値が'ok'の場合colums1はそのままにして'ok'ではない場合に1にする df['column1'] = df['column1'].where(df['column2'] == 'ok', 1)
参考の記事はこちら
note.nkmk.me
なんだかSQLに慣れているとこのコードが結構違和感。
MacのAnacondaにlibompをインストールするのは不可
Anacondaに
conda install lightgbm -c conda-forge
でLightGBMをインストールして機械学習を試そうと思ったらlibompがインストールされていません的なワーニングが出た。
実際に実行するのには問題はないがなんか気持ち悪いので
conda install libomp -c conda-forge
とやってみたけどインストールはできない。
そこでGoogleで「libomp anaconda」と調べると
anaconda.org
これが検索結果の一番上に出たのでとりあえず
conda install -c conda-forge openmp
と打ってインストールしてみたらうまく行った。
ということでMacのAnacondaでLightGBMを使うときには「openmp」も入れたほうが良さそうだよという話でした。
理由はわかっていません。