20210802のPythonに関する記事は19件です。

plotly で日付が密になる場合の回避方法

plotly で日付が密になるのを回避する方法 plotlyを使っていて日付が密になってしまう例 英語でplotlyの日付が密になる現象の説明は下記にある。 理由としては、plotly は、 文字列 YYYY-MM-DD のフォーマット(例 '2015-01-01') しか受け付けない。 Datetime オブジェクト の2つの型しか日付として受け付けてくれないのである。 その説明は明快なのですが、回避方法はこの記事を読んでもパッとわからない(私だけかもしれませんが..特にpandasでデータを保持した場合)。 回避方法 pandas 編 例えば、2021/08/02-10:43:33、という文字列でデータがpandasの df['time'] 保存されている場合、 df['time'] = df['time'].str.replace("-"," ").str.replace("/","-") # b/c plotly only accepts YYYY-MM-DD のように、str.replace で、適当に文字列を変換すればよい。この例だと、2021-08-02 10:43:33 のように変換されて、plotlyが解読可能な文字列になる。 このようにplotlyが受け付ける日付フォーマットに変換すれば、書式は特に指定しなくても、変な密な表示にはならない。 pandas 以外の場合は、実直に for loop 回して、replace で変換するなど、1発変換を入れるとOK。 # date is a list such as ["2021/08/02-10:43:33", "2021/08/02-10:53:33", ...] new date = [] for onedate in date: date.append(onedate.replace("-"," ").replace("/","-"))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TabNetを使う(回帰編)

テーブルデータの機械学習モデルとして注目されている TabNet なるものを、私も使ってみようとしました。まずは「回帰編」としてお届けします。 TabNet インストール !pip install git+https://github.com/dreamquark-ai/tabnet 「ワインの品質」データ読み込み データは UC Irvine Machine Learning Repository から取得したものを少し改変しました。 赤ワイン https://raw.githubusercontent.com/chemo-wakate/tutorial-6th/master/beginner/data/winequality-red.txt 白ワイン https://raw.githubusercontent.com/chemo-wakate/tutorial-6th/master/beginner/data/winequality-white.txt fixed acidity : 不揮発酸濃度(ほぼ酒石酸濃度) volatile acidity : 揮発酸濃度(ほぼ酢酸濃度) citric acid : クエン酸濃度 residual sugar : 残存糖濃度 chlorides : 塩化物濃度 free sulfur dioxide : 遊離亜硫酸濃度 total sulfur dioxide : 亜硫酸濃度 density : 密度 pH : pH sulphates : 硫酸塩濃度 alcohol : アルコール度数 quality (score between 0 and 10) : 0-10 の値で示される品質のスコア import pandas as pd red_wine = pd.read_csv('https://raw.githubusercontent.com/chemo-wakate/tutorial-6th/master/beginner/data/winequality-red.txt', sep='\t', index_col=0) red_wine fixed acidity volatile acidity citric acid residual sugar chlorides free sulfur dioxide total sulfur dioxide density pH sulphates alcohol quality 0 7.4 0.700 0.00 1.9 0.076 11.0 34.0 0.99780 3.51 0.56 9.4 5 1 7.8 0.880 0.00 2.6 0.098 25.0 67.0 0.99680 3.20 0.68 9.8 5 2 7.8 0.760 0.04 2.3 0.092 15.0 54.0 0.99700 3.26 0.65 9.8 5 3 11.2 0.280 0.56 1.9 0.075 17.0 60.0 0.99800 3.16 0.58 9.8 6 4 7.4 0.700 0.00 1.9 0.076 11.0 34.0 0.99780 3.51 0.56 9.4 5 ... ... ... ... ... ... ... ... ... ... ... ... ... 1594 6.2 0.600 0.08 2.0 0.090 32.0 44.0 0.99490 3.45 0.58 10.5 5 1595 5.9 0.550 0.10 2.2 0.062 39.0 51.0 0.99512 3.52 0.76 11.2 6 1596 6.3 0.510 0.13 2.3 0.076 29.0 40.0 0.99574 3.42 0.75 11.0 6 1597 5.9 0.645 0.12 2.0 0.075 32.0 44.0 0.99547 3.57 0.71 10.2 5 1598 6.0 0.310 0.47 3.6 0.067 18.0 42.0 0.99549 3.39 0.66 11.0 6 1599 rows × 12 columns import pandas as pd white_wine = pd.read_csv('https://raw.githubusercontent.com/chemo-wakate/tutorial-6th/master/beginner/data/winequality-white.txt', sep='\t', index_col=0) white_wine fixed acidity volatile acidity citric acid residual sugar chlorides free sulfur dioxide total sulfur dioxide density pH sulphates alcohol quality 0 7.0 0.27 0.36 20.7 0.045 45.0 170.0 1.00100 3.00 0.45 8.8 6 1 6.3 0.30 0.34 1.6 0.049 14.0 132.0 0.99400 3.30 0.49 9.5 6 2 8.1 0.28 0.40 6.9 0.050 30.0 97.0 0.99510 3.26 0.44 10.1 6 3 7.2 0.23 0.32 8.5 0.058 47.0 186.0 0.99560 3.19 0.40 9.9 6 4 7.2 0.23 0.32 8.5 0.058 47.0 186.0 0.99560 3.19 0.40 9.9 6 ... ... ... ... ... ... ... ... ... ... ... ... ... 4893 6.2 0.21 0.29 1.6 0.039 24.0 92.0 0.99114 3.27 0.50 11.2 6 4894 6.6 0.32 0.36 8.0 0.047 57.0 168.0 0.99490 3.15 0.46 9.6 5 4895 6.5 0.24 0.19 1.2 0.041 30.0 111.0 0.99254 2.99 0.46 9.4 6 4896 5.5 0.29 0.30 1.1 0.022 20.0 110.0 0.98869 3.34 0.38 12.8 7 4897 6.0 0.21 0.38 0.8 0.020 22.0 98.0 0.98941 3.26 0.32 11.8 6 4898 rows × 12 columns from sklearn.model_selection import train_test_split random_state = 0 X_train, X_test, y_train, y_test = train_test_split(red_wine.iloc[:, :-1].values, red_wine.iloc[:, [-1]].values, test_size=.3, random_state=random_state) X_train, X_valid, y_train, y_valid = train_test_split(X_train, y_train, test_size=.3, random_state=random_state) X_train.shape, y_train.shape ((783, 11), (783, 1)) X_valid.shape, y_valid.shape ((336, 11), (336, 1)) X_test.shape, y_test.shape ((480, 11), (480, 1)) 以上のように、赤ワインのデータと白ワインのデータがありますが、赤ワインの品質を回帰モデルで予測してみようと思います。このデータを用いるのが適切ではない可能性もありますが、まあそれはおいといて。白ワインのデータは、下記にあるように「事前学習」に使ってみます。 事前学習なしでTabNet学習 まずは事前学習なしで、赤ワインのデータのみを用いて回帰モデルを作って性能を見てみます。n_steps という変数は、ニューラルネットワークにおける層の数みたいなもので、どの特徴量を使ってdecision makingをしたかを表すものだと理解しています(この理解が間違ってたらすみません)。n_stepを変えると挙動がだいぶ変わります。 import torch from pytorch_tabnet.tab_model import TabNetRegressor # from pytorch_tabnet.tab_model import TabNetClassifier SEED = 53 N_STEPS = 3 tabnet_params = dict(n_d=8, n_a=8, n_steps=N_STEPS, gamma=1.3, n_independent=2, n_shared=2, seed=SEED, lambda_sparse=1e-3, optimizer_fn=torch.optim.Adam, optimizer_params=dict(lr=2e-2), mask_type="entmax", scheduler_params=dict(mode="min", patience=5, min_lr=1e-5, factor=0.9,), scheduler_fn=torch.optim.lr_scheduler.ReduceLROnPlateau, verbose=10 ) model = TabNetRegressor(**tabnet_params) # model = TabNetClassifier() model.fit( X_train, y_train, eval_set=[(X_valid, y_valid)], max_epochs=5000, patience=100, eval_metric={'rmse'} # 'rmsle', 'mse', 'mae' # from_unsupervised=pretrainer ) Device used : cuda epoch 0 | loss: 32.64989| val_0_rmse: 11.13777| 0:00:00s epoch 10 | loss: 4.0107 | val_0_rmse: 9.12493 | 0:00:00s epoch 20 | loss: 0.82725 | val_0_rmse: 2.45153 | 0:00:01s epoch 30 | loss: 0.53165 | val_0_rmse: 7.55144 | 0:00:02s epoch 40 | loss: 0.44194 | val_0_rmse: 5.80592 | 0:00:02s epoch 50 | loss: 0.40315 | val_0_rmse: 4.01958 | 0:00:03s epoch 60 | loss: 0.39364 | val_0_rmse: 3.2229 | 0:00:04s epoch 70 | loss: 0.35804 | val_0_rmse: 3.16619 | 0:00:04s epoch 80 | loss: 0.37049 | val_0_rmse: 2.94055 | 0:00:05s epoch 90 | loss: 0.32763 | val_0_rmse: 2.65781 | 0:00:06s epoch 100| loss: 0.33686 | val_0_rmse: 2.25962 | 0:00:07s epoch 110| loss: 0.33178 | val_0_rmse: 2.03964 | 0:00:07s epoch 120| loss: 0.3237 | val_0_rmse: 1.88684 | 0:00:08s epoch 130| loss: 0.29202 | val_0_rmse: 1.67104 | 0:00:09s epoch 140| loss: 0.3079 | val_0_rmse: 1.55122 | 0:00:10s epoch 150| loss: 0.29544 | val_0_rmse: 1.39493 | 0:00:10s epoch 160| loss: 0.28853 | val_0_rmse: 1.25286 | 0:00:11s epoch 170| loss: 0.29431 | val_0_rmse: 1.19063 | 0:00:12s epoch 180| loss: 0.27545 | val_0_rmse: 1.15625 | 0:00:13s epoch 190| loss: 0.28683 | val_0_rmse: 1.09202 | 0:00:13s epoch 200| loss: 0.27095 | val_0_rmse: 0.99627 | 0:00:14s epoch 210| loss: 0.28285 | val_0_rmse: 0.96371 | 0:00:15s epoch 220| loss: 0.26719 | val_0_rmse: 0.90612 | 0:00:16s epoch 230| loss: 0.27271 | val_0_rmse: 0.88299 | 0:00:16s epoch 240| loss: 0.2663 | val_0_rmse: 0.82608 | 0:00:17s epoch 250| loss: 0.25915 | val_0_rmse: 0.82236 | 0:00:18s epoch 260| loss: 0.24917 | val_0_rmse: 0.80364 | 0:00:19s epoch 270| loss: 0.25684 | val_0_rmse: 0.77136 | 0:00:19s epoch 280| loss: 0.24275 | val_0_rmse: 0.78264 | 0:00:20s epoch 290| loss: 0.23762 | val_0_rmse: 0.77993 | 0:00:21s epoch 300| loss: 0.26254 | val_0_rmse: 0.77074 | 0:00:21s epoch 310| loss: 0.25207 | val_0_rmse: 0.76689 | 0:00:22s epoch 320| loss: 0.23648 | val_0_rmse: 0.74517 | 0:00:23s epoch 330| loss: 0.25361 | val_0_rmse: 0.73926 | 0:00:23s epoch 340| loss: 0.24606 | val_0_rmse: 0.72841 | 0:00:24s epoch 350| loss: 0.24784 | val_0_rmse: 0.72501 | 0:00:25s epoch 360| loss: 0.23659 | val_0_rmse: 0.71072 | 0:00:26s epoch 370| loss: 0.24355 | val_0_rmse: 0.71563 | 0:00:26s epoch 380| loss: 0.23749 | val_0_rmse: 0.7265 | 0:00:27s epoch 390| loss: 0.22572 | val_0_rmse: 0.71044 | 0:00:28s epoch 400| loss: 0.22856 | val_0_rmse: 0.7037 | 0:00:28s epoch 410| loss: 0.22577 | val_0_rmse: 0.70413 | 0:00:29s epoch 420| loss: 0.26083 | val_0_rmse: 0.70473 | 0:00:30s epoch 430| loss: 0.2384 | val_0_rmse: 0.70011 | 0:00:31s epoch 440| loss: 0.23224 | val_0_rmse: 0.70506 | 0:00:31s epoch 450| loss: 0.23907 | val_0_rmse: 0.70495 | 0:00:32s epoch 460| loss: 0.24532 | val_0_rmse: 0.70434 | 0:00:33s epoch 470| loss: 0.24456 | val_0_rmse: 0.70559 | 0:00:33s epoch 480| loss: 0.22083 | val_0_rmse: 0.70538 | 0:00:34s epoch 490| loss: 0.2365 | val_0_rmse: 0.70484 | 0:00:35s epoch 500| loss: 0.24641 | val_0_rmse: 0.70772 | 0:00:35s epoch 510| loss: 0.22065 | val_0_rmse: 0.70898 | 0:00:36s epoch 520| loss: 0.22796 | val_0_rmse: 0.70955 | 0:00:37s epoch 530| loss: 0.21979 | val_0_rmse: 0.711 | 0:00:37s Early stopping occurred at epoch 530 with best_epoch = 430 and best_val_0_rmse = 0.70011 Best weights from best epoch are automatically used! 学習が終わったようなので学習の経過を確認しましょう。 import matplotlib.pyplot as plt for param in ['loss', 'lr', 'val_0_rmse']: plt.plot(model.history[param], label=param) plt.xlabel('epoch') plt.grid() plt.legend() plt.show() 性能評価 from sklearn.metrics import mean_squared_error test_score = mean_squared_error(model.predict(X_test), y_test) print(f"BEST VALID SCORE: {model.best_cost}") print(f"FINAL TEST SCORE: {test_score}") BEST VALID SCORE: 0.7001122835576945 FINAL TEST SCORE: 0.5577702945336053 予測結果と真の値とを比較するプロット。今回はワインの品質として整数値を与えるのが本当なので、プロットの形もこんなのになります。 for name, X, y in [["training", X_train, y_train], ["validation", X_valid, y_valid], ["test", X_test, y_test]]: plt.scatter(y, model.predict(X), alpha=0.5, label=name) plt.plot([3, 8], [3, 8]) plt.grid() plt.legend() plt.xlabel("True") plt.ylabel("Predicted") plt.show() 自己事前学習ありでTabNet学習 TabNetでは次のようにして「事前学習」を行なえます。果たしてこれで性能が向上するでしょうか? from pytorch_tabnet.pretraining import TabNetPretrainer pretrainer = TabNetPretrainer(**tabnet_params) pretrainer.fit( X_train, eval_set=[X_valid], max_epochs=5000, patience=100, ) Device used : cuda epoch 0 | loss: 84416.57031| val_0_unsup_loss: 33251194.0| 0:00:00s epoch 10 | loss: 2395.65454| val_0_unsup_loss: 19814.19141| 0:00:01s epoch 20 | loss: 301.95297| val_0_unsup_loss: 5600.98291| 0:00:01s epoch 30 | loss: 153.68903| val_0_unsup_loss: 3039.54907| 0:00:02s epoch 40 | loss: 51.07078| val_0_unsup_loss: 736.71814| 0:00:03s epoch 50 | loss: 69.6201 | val_0_unsup_loss: 442.73096| 0:00:04s epoch 60 | loss: 34.41461| val_0_unsup_loss: 233.06084| 0:00:05s epoch 70 | loss: 47.174 | val_0_unsup_loss: 247.93704| 0:00:06s epoch 80 | loss: 28.79832| val_0_unsup_loss: 293.99844| 0:00:07s epoch 90 | loss: 37.22774| val_0_unsup_loss: 248.3813| 0:00:07s epoch 100| loss: 22.29504| val_0_unsup_loss: 187.73672| 0:00:08s epoch 110| loss: 22.49255| val_0_unsup_loss: 158.42435| 0:00:09s epoch 120| loss: 14.54969| val_0_unsup_loss: 144.55991| 0:00:10s epoch 130| loss: 12.70208| val_0_unsup_loss: 104.17162| 0:00:11s epoch 140| loss: 12.65242| val_0_unsup_loss: 94.375 | 0:00:12s epoch 150| loss: 7.38195 | val_0_unsup_loss: 101.70587| 0:00:13s epoch 160| loss: 9.93811 | val_0_unsup_loss: 71.79494| 0:00:13s epoch 170| loss: 14.58065| val_0_unsup_loss: 41.21515| 0:00:14s epoch 180| loss: 12.00856| val_0_unsup_loss: 38.96758| 0:00:15s epoch 190| loss: 15.64681| val_0_unsup_loss: 27.69069| 0:00:16s epoch 200| loss: 5.2482 | val_0_unsup_loss: 23.3637 | 0:00:17s epoch 210| loss: 19.1653 | val_0_unsup_loss: 27.76682| 0:00:18s epoch 220| loss: 6.18701 | val_0_unsup_loss: 18.53819| 0:00:18s epoch 230| loss: 4.77499 | val_0_unsup_loss: 19.45325| 0:00:19s epoch 240| loss: 6.98359 | val_0_unsup_loss: 18.99881| 0:00:20s epoch 250| loss: 21.51803| val_0_unsup_loss: 33.55697| 0:00:21s epoch 260| loss: 5.4652 | val_0_unsup_loss: 11.66067| 0:00:22s epoch 270| loss: 7.04799 | val_0_unsup_loss: 13.46543| 0:00:23s epoch 280| loss: 4.69859 | val_0_unsup_loss: 13.60153| 0:00:23s epoch 290| loss: 4.7595 | val_0_unsup_loss: 12.37127| 0:00:24s epoch 300| loss: 5.02166 | val_0_unsup_loss: 13.52421| 0:00:25s epoch 310| loss: 3.72067 | val_0_unsup_loss: 15.02659| 0:00:26s epoch 320| loss: 3.20332 | val_0_unsup_loss: 14.02866| 0:00:27s epoch 330| loss: 3.21631 | val_0_unsup_loss: 14.31985| 0:00:27s epoch 340| loss: 3.85526 | val_0_unsup_loss: 15.13815| 0:00:28s epoch 350| loss: 3.31001 | val_0_unsup_loss: 13.70876| 0:00:29s epoch 360| loss: 3.56261 | val_0_unsup_loss: 13.16991| 0:00:30s epoch 370| loss: 3.35176 | val_0_unsup_loss: 14.11328| 0:00:31s epoch 380| loss: 2.76765 | val_0_unsup_loss: 13.73672| 0:00:31s Early stopping occurred at epoch 382 with best_epoch = 282 and best_val_0_unsup_loss = 10.97403 Best weights from best epoch are automatically used! 事前学習の学習履歴を表示します。 import matplotlib.pyplot as plt for param in ['loss', 'lr', 'val_0_unsup_loss']: plt.plot(pretrainer.history[param]) plt.xlabel('epoch') plt.ylabel(param) plt.grid() plt.show() 事前学習した結果を from_unsupervised=pretrainer として利用して学習します。 import torch from pytorch_tabnet.tab_model import TabNetRegressor # from pytorch_tabnet.tab_model import TabNetClassifier model = TabNetRegressor(**tabnet_params) # model = TabNetClassifier() model.fit( X_train, y_train, eval_set=[(X_valid, y_valid)], max_epochs=5000, patience=100, eval_metric={'rmse'}, # 'rmsle', 'mse', 'mae' from_unsupervised=pretrainer ) Device used : cuda Loading weights from unsupervised pretraining epoch 0 | loss: 44.76851| val_0_rmse: 6.73764 | 0:00:00s epoch 10 | loss: 7.06438 | val_0_rmse: 1.96124 | 0:00:00s epoch 20 | loss: 1.31673 | val_0_rmse: 2.24009 | 0:00:01s epoch 30 | loss: 0.59232 | val_0_rmse: 0.97692 | 0:00:02s epoch 40 | loss: 0.49472 | val_0_rmse: 0.78751 | 0:00:03s epoch 50 | loss: 0.43891 | val_0_rmse: 0.93067 | 0:00:03s epoch 60 | loss: 0.40727 | val_0_rmse: 0.88366 | 0:00:04s epoch 70 | loss: 0.40231 | val_0_rmse: 0.83118 | 0:00:05s epoch 80 | loss: 0.39851 | val_0_rmse: 0.81392 | 0:00:05s epoch 90 | loss: 0.37589 | val_0_rmse: 0.7614 | 0:00:06s epoch 100| loss: 0.37226 | val_0_rmse: 0.74418 | 0:00:07s epoch 110| loss: 0.36799 | val_0_rmse: 0.74657 | 0:00:08s epoch 120| loss: 0.3517 | val_0_rmse: 0.71815 | 0:00:08s epoch 130| loss: 0.34294 | val_0_rmse: 0.70896 | 0:00:09s epoch 140| loss: 0.3428 | val_0_rmse: 0.69662 | 0:00:10s epoch 150| loss: 0.33453 | val_0_rmse: 0.69915 | 0:00:11s epoch 160| loss: 0.33938 | val_0_rmse: 0.70477 | 0:00:11s epoch 170| loss: 0.32963 | val_0_rmse: 0.71207 | 0:00:12s epoch 180| loss: 0.33767 | val_0_rmse: 0.71087 | 0:00:13s epoch 190| loss: 0.33722 | val_0_rmse: 0.70626 | 0:00:13s epoch 200| loss: 0.33723 | val_0_rmse: 0.70464 | 0:00:14s epoch 210| loss: 0.32091 | val_0_rmse: 0.70531 | 0:00:15s epoch 220| loss: 0.30413 | val_0_rmse: 0.7041 | 0:00:15s epoch 230| loss: 0.30876 | val_0_rmse: 0.70894 | 0:00:16s Early stopping occurred at epoch 239 with best_epoch = 139 and best_val_0_rmse = 0.69576 Best weights from best epoch are automatically used! その結果。 import matplotlib.pyplot as plt for param in ['loss', 'lr', 'val_0_rmse']: plt.plot(model.history[param], label=param) plt.xlabel('epoch') plt.grid() plt.legend() plt.show() 性能は向上したでしょうか。 from sklearn.metrics import mean_squared_error test_score = mean_squared_error(model.predict(X_test), y_test) print(f"BEST VALID SCORE: {model.best_cost}") print(f"FINAL TEST SCORE: {test_score}") BEST VALID SCORE: 0.6957614248635677 FINAL TEST SCORE: 0.4984989548147685 「今回は」性能が向上したようです。私の少ない経験上、train_test_split による分割が変化しても、random seed が変化しても、n_steps が変化しても、性能が向上するどころかむしろ悪化するケースが多いように思います。 for name, X, y in [["training", X_train, y_train], ["validation", X_valid, y_valid], ["test", X_test, y_test]]: plt.scatter(y, model.predict(X), alpha=0.5, label=name) plt.plot([3, 8], [3, 8]) plt.grid() plt.legend() plt.xlabel("True") plt.ylabel("Predicted") plt.show() 転移学習?半教師あり学習? ここまでは、赤ワインのデータのみを用いて、赤ワインの品質を予測しました。事前学習も、赤ワインのデータのみ(ラベルデータなし)を用いました。次は、試しに白ワインのデータ(ラベルデータなし)を事前学習に用いてみます。これって、転移学習と呼べるのかな?半教師あり学習と呼べるのかな?という疑問が浮かびましたがよく分かりません。 from sklearn.model_selection import train_test_split random_state = 53 X_train2, X_valid2, y_train2, y_valid2 = train_test_split(white_wine.iloc[:, :-1].values, white_wine.iloc[:, [-1]].values, test_size=.3, random_state=random_state) X_train2.shape, y_train2.shape ((3428, 11), (3428, 1)) X_valid2.shape, y_valid2.shape ((1470, 11), (1470, 1)) 事前学習用のデータを置き換えるだけで、それ以外は特に変わりませんね。 from pytorch_tabnet.pretraining import TabNetPretrainer import numpy as np pretrainer = TabNetPretrainer(**tabnet_params) pretrainer.fit( np.concatenate([X_train, X_train2]), eval_set=[np.concatenate([X_valid, X_valid2])], max_epochs=5000, patience=100, ) Device used : cuda epoch 0 | loss: 16660.33889| val_0_unsup_loss: 2446820.75| 0:00:00s epoch 10 | loss: 28.30764| val_0_unsup_loss: 613.03979| 0:00:04s epoch 20 | loss: 27.08781| val_0_unsup_loss: 283.35773| 0:00:07s epoch 30 | loss: 3.24114 | val_0_unsup_loss: 62.06253| 0:00:11s epoch 40 | loss: 7.27796 | val_0_unsup_loss: 91.33012| 0:00:15s epoch 50 | loss: 13.21588| val_0_unsup_loss: 15.54838| 0:00:18s epoch 60 | loss: 20.57722| val_0_unsup_loss: 32.31664| 0:00:22s epoch 70 | loss: 3.17627 | val_0_unsup_loss: 11.90612| 0:00:25s epoch 80 | loss: 1.67535 | val_0_unsup_loss: 39.38104| 0:00:29s epoch 90 | loss: 1.55993 | val_0_unsup_loss: 32.15377| 0:00:32s epoch 100| loss: 3.09699 | val_0_unsup_loss: 34.45182| 0:00:36s epoch 110| loss: 2.2177 | val_0_unsup_loss: 36.49228| 0:00:39s epoch 120| loss: 2.08958 | val_0_unsup_loss: 32.53637| 0:00:43s epoch 130| loss: 1.42668 | val_0_unsup_loss: 38.60402| 0:00:46s epoch 140| loss: 1.40155 | val_0_unsup_loss: 44.6946 | 0:00:50s epoch 150| loss: 1.37884 | val_0_unsup_loss: 40.0892 | 0:00:54s epoch 160| loss: 1.3745 | val_0_unsup_loss: 41.22863| 0:00:57s epoch 170| loss: 1.56642 | val_0_unsup_loss: 41.14534| 0:01:01s Early stopping occurred at epoch 170 with best_epoch = 70 and best_val_0_unsup_loss = 11.90612 Best weights from best epoch are automatically used! import matplotlib.pyplot as plt for param in ['loss', 'lr', 'val_0_unsup_loss']: plt.plot(pretrainer.history[param]) plt.xlabel('epoch') plt.ylabel(param) plt.grid() plt.show() 事前学習を終えて、本番の学習です。 import torch from pytorch_tabnet.tab_model import TabNetRegressor # from pytorch_tabnet.tab_model import TabNetClassifier model = TabNetRegressor(**tabnet_params) # model = TabNetClassifier() model.fit( X_train, y_train, eval_set=[(X_valid, y_valid)], max_epochs=5000, patience=100, eval_metric={'rmse'}, # 'rmsle', 'mse', 'mae' from_unsupervised=pretrainer ) Device used : cuda Loading weights from unsupervised pretraining epoch 0 | loss: 45.92977| val_0_rmse: 7.19955 | 0:00:00s epoch 10 | loss: 9.63374 | val_0_rmse: 2.01992 | 0:00:00s epoch 20 | loss: 2.10203 | val_0_rmse: 0.92411 | 0:00:01s epoch 30 | loss: 0.73812 | val_0_rmse: 0.98633 | 0:00:02s epoch 40 | loss: 0.55103 | val_0_rmse: 1.05893 | 0:00:03s epoch 50 | loss: 0.43789 | val_0_rmse: 0.9111 | 0:00:03s epoch 60 | loss: 0.42148 | val_0_rmse: 0.8362 | 0:00:04s epoch 70 | loss: 0.4075 | val_0_rmse: 0.8341 | 0:00:05s epoch 80 | loss: 0.42913 | val_0_rmse: 0.78552 | 0:00:05s epoch 90 | loss: 0.38573 | val_0_rmse: 0.76019 | 0:00:06s epoch 100| loss: 0.38899 | val_0_rmse: 0.74047 | 0:00:07s epoch 110| loss: 0.36617 | val_0_rmse: 0.73821 | 0:00:08s epoch 120| loss: 0.35307 | val_0_rmse: 0.715 | 0:00:08s epoch 130| loss: 0.34752 | val_0_rmse: 0.70871 | 0:00:09s epoch 140| loss: 0.33744 | val_0_rmse: 0.69098 | 0:00:10s epoch 150| loss: 0.34046 | val_0_rmse: 0.69176 | 0:00:11s epoch 160| loss: 0.31546 | val_0_rmse: 0.68321 | 0:00:11s epoch 170| loss: 0.32649 | val_0_rmse: 0.67995 | 0:00:12s epoch 180| loss: 0.32596 | val_0_rmse: 0.68038 | 0:00:13s epoch 190| loss: 0.30284 | val_0_rmse: 0.67161 | 0:00:13s epoch 200| loss: 0.31748 | val_0_rmse: 0.67932 | 0:00:14s epoch 210| loss: 0.30808 | val_0_rmse: 0.67495 | 0:00:15s epoch 220| loss: 0.30112 | val_0_rmse: 0.67347 | 0:00:15s epoch 230| loss: 0.29536 | val_0_rmse: 0.67413 | 0:00:16s epoch 240| loss: 0.29671 | val_0_rmse: 0.67068 | 0:00:17s epoch 250| loss: 0.28007 | val_0_rmse: 0.66754 | 0:00:18s epoch 260| loss: 0.2999 | val_0_rmse: 0.66688 | 0:00:18s epoch 270| loss: 0.29132 | val_0_rmse: 0.66692 | 0:00:19s epoch 280| loss: 0.28029 | val_0_rmse: 0.66665 | 0:00:20s epoch 290| loss: 0.278 | val_0_rmse: 0.66944 | 0:00:21s epoch 300| loss: 0.29261 | val_0_rmse: 0.66767 | 0:00:21s epoch 310| loss: 0.28728 | val_0_rmse: 0.66728 | 0:00:22s epoch 320| loss: 0.27489 | val_0_rmse: 0.66367 | 0:00:23s epoch 330| loss: 0.26925 | val_0_rmse: 0.66052 | 0:00:23s epoch 340| loss: 0.26379 | val_0_rmse: 0.65765 | 0:00:24s epoch 350| loss: 0.28442 | val_0_rmse: 0.65711 | 0:00:25s epoch 360| loss: 0.28069 | val_0_rmse: 0.65617 | 0:00:26s epoch 370| loss: 0.28303 | val_0_rmse: 0.65606 | 0:00:26s epoch 380| loss: 0.29653 | val_0_rmse: 0.65791 | 0:00:27s epoch 390| loss: 0.27669 | val_0_rmse: 0.65919 | 0:00:28s epoch 400| loss: 0.2771 | val_0_rmse: 0.66249 | 0:00:28s epoch 410| loss: 0.26686 | val_0_rmse: 0.66416 | 0:00:29s epoch 420| loss: 0.26393 | val_0_rmse: 0.66477 | 0:00:30s epoch 430| loss: 0.26517 | val_0_rmse: 0.66507 | 0:00:31s epoch 440| loss: 0.28231 | val_0_rmse: 0.66406 | 0:00:31s epoch 450| loss: 0.26679 | val_0_rmse: 0.66527 | 0:00:32s epoch 460| loss: 0.27933 | val_0_rmse: 0.66518 | 0:00:33s Early stopping occurred at epoch 461 with best_epoch = 361 and best_val_0_rmse = 0.6559 Best weights from best epoch are automatically used! import matplotlib.pyplot as plt for param in ['loss', 'lr', 'val_0_rmse']: plt.plot(model.history[param], label=param) plt.xlabel('epoch') plt.grid() plt.legend() plt.show() from sklearn.metrics import mean_squared_error test_score = mean_squared_error(model.predict(X_test), y_test) print(f"BEST VALID SCORE: {model.best_cost}") print(f"FINAL TEST SCORE: {test_score}") BEST VALID SCORE: 0.6558970337385635 FINAL TEST SCORE: 0.48485043537972694 おお、向上しましたね。今までで一番良い数字です。ですがこれも、私の少ない経験上、train_test_split による分割が変化しても、random seed が変化しても、n_steps が変化しても、性能が向上するどころかむしろ悪化するケースが多いように思います。 for name, X, y in [["training", X_train, y_train], ["validation", X_valid, y_valid], ["test", X_test, y_test]]: plt.scatter(y, model.predict(X), alpha=0.5, label=name) plt.plot([3, 8], [3, 8]) plt.grid() plt.legend() plt.xlabel("True") plt.ylabel("Predicted") plt.show() Feature importance (Global interpretability) TabNetの特徴として、RandomForestなどと類似した Feature importanceが算出できることが挙げられます。TabNetでは、Global interpretability とも呼ばれます。 plt.barh(list(red_wine.columns[:-1])[::-1], model.feature_importances_[::-1]) plt.grid() plt.show() Mask (Local interpretability) TabNetではそれに加えて、どの特徴量を使うか decision making するのに用いた mask というのを見ることができます。Local interpretability とも呼ばれます。mask は n_steps の数だけあります。ここでは、予測したデータの先頭 50 個についてのみ図示してみます。 explain_matrix, masks = model.explain(X_test) fig, axs = plt.subplots(N_STEPS, 1, figsize=(21, 3*N_STEPS)) for i in range(N_STEPS): axs[i].imshow(masks[i][:50].T) axs[i].set_title(f"mask {i}") axs[i].set_yticks(range(len(red_wine.columns[:-1]))) axs[i].set_yticklabels(list(red_wine.columns[:-1])) ScikitAllstarsと比較 ScikitAllstars は、scikit-learn の主要な教師あり機械学習モデルをひとまとめに oputuna でハイパラチューニングするツールです。上記と同じデータを予測して比較してみましょう。 # Optuna のインストール !pip install optuna # ScikitAllStars のインストール !pip install git+https://github.com/maskot1977/scikitallstars.git import pandas as pd red_wine = pd.read_csv('https://raw.githubusercontent.com/chemo-wakate/tutorial-6th/master/beginner/data/winequality-red.txt', sep='\t', index_col=0) red_wine fixed acidity volatile acidity citric acid residual sugar chlorides free sulfur dioxide total sulfur dioxide density pH sulphates alcohol quality 0 7.4 0.700 0.00 1.9 0.076 11.0 34.0 0.99780 3.51 0.56 9.4 5 1 7.8 0.880 0.00 2.6 0.098 25.0 67.0 0.99680 3.20 0.68 9.8 5 2 7.8 0.760 0.04 2.3 0.092 15.0 54.0 0.99700 3.26 0.65 9.8 5 3 11.2 0.280 0.56 1.9 0.075 17.0 60.0 0.99800 3.16 0.58 9.8 6 4 7.4 0.700 0.00 1.9 0.076 11.0 34.0 0.99780 3.51 0.56 9.4 5 ... ... ... ... ... ... ... ... ... ... ... ... ... 1594 6.2 0.600 0.08 2.0 0.090 32.0 44.0 0.99490 3.45 0.58 10.5 5 1595 5.9 0.550 0.10 2.2 0.062 39.0 51.0 0.99512 3.52 0.76 11.2 6 1596 6.3 0.510 0.13 2.3 0.076 29.0 40.0 0.99574 3.42 0.75 11.0 6 1597 5.9 0.645 0.12 2.0 0.075 32.0 44.0 0.99547 3.57 0.71 10.2 5 1598 6.0 0.310 0.47 3.6 0.067 18.0 42.0 0.99549 3.39 0.66 11.0 6 1599 rows × 12 columns from sklearn.model_selection import train_test_split random_state = 0 X_train, X_test, y_train, y_test = train_test_split(red_wine.iloc[:, :-1].values, red_wine.iloc[:, [-1]].values, test_size=.3, random_state=random_state) AllstarsModel の学習 from scikitallstars import allstars, depict allstars_model = allstars.fit(X_train, y_train, timeout=1000, n_trials=100, feature_selection=True) feature selection: X_train (1119, 11) -> (1119, 3) {'GradientBoosting': 0.4388699431816158, 'ExtraTrees': 0.49443573617340997, 'RandomForest': 0.4434120482153883, 'AdaBoost': 0.4073180139136409, 'MLP': 0.3670088611377368, 'SVR': 0.40403614655933495, 'kNN': 0.43064459007357375, 'Ridge': 0.39026600919071514, 'Lasso': 0.39172487228440867, 'PLS': 0.39819809406714757, 'LinearRegression': 0.4125666488108234} from sklearn.metrics import mean_squared_error test_score = mean_squared_error(allstars_model.predict(X_test), y_test) print(f"FINAL TEST SCORE: {test_score}") FINAL TEST SCORE: 0.42362855816765 import matplotlib.pyplot as plt for name, X, y in [["training", X_train, y_train], ["test", X_test, y_test]]: plt.scatter(y, allstars_model.predict(X), alpha=0.5, label=name) plt.plot([3, 8], [3, 8]) plt.grid() plt.legend() plt.xlabel("True") plt.ylabel("Predicted") plt.show() StackingModel の学習 stacking_model = allstars.get_best_stacking(allstars_model, X_train, y_train, timeout=1000, n_trials=100) from sklearn.metrics import mean_squared_error test_score = mean_squared_error(stacking_model.predict(X_test), y_test) print(f"FINAL TEST SCORE: {test_score}") FINAL TEST SCORE: 0.4301126301454623 import matplotlib.pyplot as plt for name, X, y in [["training", X_train, y_train], ["test", X_test, y_test]]: plt.scatter(y, stacking_model.predict(X), alpha=0.5, label=name) plt.plot([3, 8], [3, 8]) plt.grid() plt.legend() plt.xlabel("True") plt.ylabel("Predicted") plt.show() 結果 あれ? TabNet 負けちゃった。まあ、どんなデータでも勝てるわけじゃないんでしょうね。あるいは私の TabNet に対する理解が足りなくて、しょぼい使い方しかできてない可能性も。 今回は回帰モデルを作ってみましたが、そのうち分類とかもやります。そのうち。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Databrick REST APIによりWorkspaceオブジェクト(ノートブック・Experiments・フォルダ)の存在チェックを行う方法

概要 Databrick REST APIによりWorkspaceオブジェクト(ノートブック・Experiments・フォルダ)の存在チェックを行う方法を共有します。dbutilsの機能にはないため、REST APIで実施する必要があります。 詳細は下記のGithub pagesのページをご確認ください。 コードを実行したい方は、下記のdbcファイルを取り込んでください。 https://github.com/manabian-/databricks_tecks_for_qiita/blob/main/tecks/check_ws_obj_by_rest_api/dbc/check_ws_obj_by_rest_api.dbc 実行環境 databricks runtime: 8.3.x-cpu-ml-scala2.12 Python version: 3.8.8 pyspark version: 3.1.2.dev0 手順 1. シークレットにDatabricksトークンとDatabricks Workspace URLを格納して、変数にセット シークレットにDatabricksトークンとDatabricks Workspace URLを格納する方法は下記の記事を参考に実施してください。 Databrick REST APIによりDatabricksトークンを作成後にシークレットとして登録する方法 - Qiita scope_name = "databricks_mlops" # scope名をセット databricks_token = "databricks_token" # DatabricksトークンにおけるsecreatのKey名をセット databricks_url = "databricks_url" # DatabricksのURLをsecretsのKey名をセット # シークレットからトークンとDatabrikcs WorkspaceのURLをセット token = dbutils.secrets.get(scope_name, databricks_token) db_url = dbutils.secrets.get(scope_name, databricks_url) 2. 関数を定義 import requests def check_ws_obj_exist(path, token, db_url,raise_error='False'): """Databricks Workspaceにおけるオブジェクトの存在チェック Databricks Workspaceにおけるオブジェクトの存在チェックを、Databricks REST APIにより行う関数です。 Args: path (string): ノートブック等のWorkspaceオブジェクトのパスを指定 token (string): REST API実行する際に利用するDatabricksトークンを指定 db_url (string): REST API実行対象のDatabricks Workspace URLを指定 raise_error (boolean): 正常終了とする場合にはTrue、異常終了にする場合にはFalse Returns: None Raises: Exception: Notebook does not exist (raise_errorがTrueであり、オブジェクトが存在しない場合) Yields: None Examples: >>> chek_notebook_existence(path, False) Notebook does not exist >>> chek_notebook_existence(path, True) Exception: Notebook does not exist Note: Nothing """ response = requests.get( f'{db_url}/api/2.0/workspace/list', headers={'Authorization': f'Bearer {token}'}, json={ 'path': path, }, ) if response.status_code == 200: print(f'Workspace objects exist') elif response.status_code == 404: if response.json().get('error_code') == 'RESOURCE_DOES_NOT_EXIST': if raise_error == True: raise Exception(f'Workspace objects does not exist') else: print(f'Workspace objects does not exist') else: print(response.text) elif response.status_code == 403: print(response.text) else: print('Error geting the job: {0}: {1}'.format(response.json()['error_code'],response.json()['message'])) 3. 定義した関数によりDatabricks Workspaceオブジェクトの存在チェック(存在しなくても正常終了) # 存在チェックしたいノートブックのパスを指定 path = "/qiita/aaa" check_ws_obj_exist(path, token, db_url, False) 4. 定義した関数によりDatabricks Workspaceオブジェクトの存在チェック(存在しない場合に異常終了) # 存在チェックしたいノートブックのパスを指定 path = "/qiita/aaa" check_ws_obj_exist(path, token, db_url, True)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

朝飯前に学べる!便利なPythonのヒント100選【後編】

本記事は、Fatos Morina氏による「100 Helpful Python Tips You Can Learn Before Finishing Your Morning Coffee」(2021年5月10日公開)の和訳を、著者の許可を得て掲載しているものです。 朝飯前に学べる!便利なPythonのヒント100選【後編】 Photo by Jexo on Unsplash はじめに Pythonは、主にそのシンプルさと習得のしやすさから、最近では非常に人気があります。 データサイエンスや機械学習、ウェブ開発、スクリプト記述、自動化など、幅広い分野で利用することができます。 この記事はかなり長いので、すぐ始めましょう。 50. filter()は新しいオブジェクトを返す my_list = [1, 2, 3, 4] odd = filter(lambda x: x % 2 == 1, my_list) print(list(odd)) # [1, 3] print(my_list) # [1, 2, 3, 4] 51. map()は新しいオブジェクトを返す my_list = [1, 2, 3, 4] squared = map(lambda x: x ** 2, my_list) print(list(squared)) # [1, 4, 9, 16] print(my_list) # [1, 2, 3, 4] 52. range()にはあまり知られていないステップパラメータがある for number in range(1, 10, 3): print(number, end=" ") # 1 4 7 53. range()はデフォルトで0から始まる そのため、0を含める必要は全くありません。 def range_with_zero(number): for i in range(0, number): print(i, end=' ') def range_with_no_zero(number): for i in range(number): print(i, end=' ') range_with_zero(3) # 0 1 2 range_with_no_zero(3) # 0 1 2 54. 長さを0と比較する必要はない 長さが0より大きい場合、デフォルトでTrueなので、0と比較する必要はありません。 def get_element_with_comparison(my_list): if len(my_list) > 0: return my_list[0] def get_first_element(my_list): if len(my_list): return my_list[0] elements = [1, 2, 3, 4] first_result = get_element_with_comparison(elements) second_result = get_element_with_comparison(elements) print(first_result == second_result) # True 55. 同じスコープで同じメソッドを複数回定義できる ただし、前のものを上書きするため、最後のものだけが呼び出されます。 def get_address(): return "First address" def get_address(): return "Second address" def get_address(): return "Third address" print(get_address()) # Third address 56. 指定スコープ外のプライベートプロパティにもアクセスできる class Engineer: def __init__(self, name): self.name = name self.__starting_salary = 62000 dain = Engineer('Dain') print(dain._Engineer__starting_salary) # 62000 57. オブジェクトのメモリ使用量を調べる import sys print(sys.getsizeof("bitcoin")) # 56 58. パラメータを何個でも指定して呼び出せるメソッドを定義する def get_sum(*arguments): result = 0 for i in arguments: result += i return result print(get_sum(1, 2, 3)) # 6 print(get_sum(1, 2, 3, 4, 5)) # 15 print(get_sum(1, 2, 3, 4, 5, 6, 7)) # 28 59. super()または親クラス名を使用して、親クラスのイニシャライザを呼び出す super()を使用して、親クラスのイニシャライザを呼び出すことができます。 class Parent: def __init__(self, city, address): self.city = city self.address = address class Child(Parent): def __init__(self, city, address, university): super().__init__(city, address) self.university = university child = Child('Zürich', 'Rämistrasse 101', 'ETH Zürich') print(child.university) # ETH Zürich 親クラス名を使用して、親クラスを呼び出します。 class Parent: def __init__(self, city, address): self.city = city self.address = address class Child(Parent): def __init__(self, city, address, university): Parent.__init__(self, city, address) self.university = university child = Child('Zürich', 'Rämistrasse 101', 'ETH Zürich') print(child.university) # ETH Zürich なお、init()やsuper()を使用した親のイニシャライザの呼び出しは、子クラスのイニシャライザ内部だけで使用できます。 60. 自クラスで「+」演算子を再定義する 2つの整数型で「+」演算子を使用すると、その和を取得します。 2つの文字列型で使用すると、それらをマージします。 print(10 + 1) # Adding two integers using '+' print('first' + 'second') # Merging two strings '+' これが演算子のオーバーロードです。 自クラスでも使用できます。 class Expenses: def __init__(self, rent, groceries): self.rent = rent self.groceries = groceries def __add__(self, other): return Expenses(self.rent + other.rent, self.groceries + other.groceries) april_expenses = Expenses(1000, 200) may_expenses = Expenses(1000, 300) total_expenses = april_expenses + may_expenses print(total_expenses.rent) # 2000 print(total_expenses.groceries) # 500 61. 自クラスで「<」演算子および「==」演算子を再定義する 自分で定義できる演算子のオーバーロードの例です。 class Game: def __init__(self, score): self.score = score def __lt__(self, other): return self.score < other.score first = Game(1) second = Game(2) print(first < second) # True 先の2つと同じように、自分のニーズに基づいて、eq()関数を上書きできます。 class Journey: def __init__(self, location, destination, duration): self.location = location self.destination = destination self.duration = duration def __eq__(self, other): return ((self.location == other.location) and (self.destination == other.destination) and (self.duration == other.duration)) first = Journey('Location A', 'Destination A', '30min') second = Journey('Location B', 'Destination B', '30min') print(first == second) 次も同様に定義することもできます。 sub() 「-」 mul() 「*」 truediv() 「/」 ne() 「!=」 ge() 「>=」 gt() 「>」 62. クラスのオブジェクトのカスタム印刷可能なバージョンを定義する class Rectangle: def __init__(self, a, b): self.a = a self.b = b def __repr__(self): return repr('Rectangle with area=' + str(self.a * self.b)) print(Rectangle(3, 4)) # 'Rectangle with area=12' 63. 文字列の文字の大文字と小文字を入れ替える string = "This is just a sentence." result = string.swapcase() print(result) # tHIS IS JUST A SENTENCE. 64. 文字列のすべての文字が空白か調べる string = " " result = string.isspace() print(result) # True 65. 文字列のすべての文字がアルファベットまたは数字か調べる name = "Password" print(name.isalnum()) # True, because all characters are alphabets name = "Secure Password " print(name.isalnum()) # False, because it contains whitespaces name = "S3cur3P4ssw0rd" print(name.isalnum()) # True name = "133" print(name.isalnum()) # True, because all characters are numbers 66. 文字列のすべての文字がアルファベットか調べる string = "Name" print(string.isalpha()) # True string = "Firstname Lastname" print(string.isalpha()) # False, because it contains whitespace string = "P4ssw0rd" print(string.isalpha()) # False, because it contains numbers 67. 引数に基づいて、右から文字を削除する string = "This is a sentence with " # Remove trailing spaces from the right print(string.rstrip()) # "This is a sentence with " string = "this here is a sentence.....,,,,aaaaasd" print(string.rstrip(".,dsa")) # "this here is a sentence" 同じように、引数に基づいて、左から文字を削除することもできます。 string = "ffffffffFirst" print(string.lstrip("f")) # First 68. 文字列が数値か調べる string = "seven" print(string.isdigit()) # False string = "1337" print(string.isdigit()) # True string = "5a" print(string.isdigit()) # False, because it contains the character 'a' string = "2**5" print(string.isdigit()) # False 69. 文字列が漢数字か調べる # 42673 in Arabic numerals string = "四二六七三" print(string.isdigit()) # False print(string.isnumeric()) # True 70. 文字列のすべての単語が大文字で始まるか調べる string = "This is a sentence" print(string.istitle()) # False string = "10 Python Tips" print(string.istitle()) # True string = "How to Print A String in Python" # False, because of the first characters being lowercase in "to" and "in" print(string.istitle()) string = "PYTHON" print(string.istitle()) # False. It's titlelized version is "Python" 71. タプルでも負のインデックスを使用できる numbers = (1, 2, 3, 4) print(numbers[-1]) # 4 print(numbers[-4]) # 1 72. タプルにリストとタプルをネストする mixed_tuple = (("a"*10, 3, 4), ['first', 'second', 'third']) print(mixed_tuple[1]) # ['first', 'second', 'third'] print(mixed_tuple[0]) # ('aaaaaaaaaa', 3, 4) 73. リストに条件を満たす要素が出現する回数を簡単に数える names = ["Besim", "Albert", "Besim", "Fisnik", "Meriton"] print(names.count("Besim")) # 2 74. slice()を使用して、最後のn個の要素を簡単に取得する my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] slicing = slice(-4, None) # Getting the last 3 elements from the list print(my_list[slicing]) # [4, 5, 6] # Getting only the third element starting from the right print(my_list[-3]) # 4 次のような通常のスライスタスクにもslice()を使用できます。 string = "Data Science" # start = 1, stop = None (don't stop anywhere), step = 1 # contains 1, 3 and 5 indices slice_object = slice(5, None) print(string[slice_object]) # Science 75. タプルに要素が出現する回数を数える my_tuple = ('a', 1, 'f', 'a', 5, 'a') print(my_tuple.count('a')) # 3 76. タプルの要素のインデックスを取得する my_tuple = ('a', 1, 'f', 'a', 5, 'a') print(my_tuple.index('f')) # 2 77. ジャンプを使用してサブタプルを取得する my_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) print(my_tuple[::3]) # (1, 4, 7, 10) 78. インデックスから始まるサブタプルを取得する my_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) print(my_tuple[3:]) # (4, 5, 6, 7, 8, 9, 10) 79. リスト、集合、辞書からすべての要素を削除する my_list = [1, 2, 3, 4] my_list.clear() print(my_list) # [] my_set = {1, 2, 3} my_set.clear() print(my_set) # set() my_dict = {"a": 1, "b": 2} my_dict.clear() print(my_dict) # {} 80. 2つの集合を結合する 1つの方法は、union()メソッドを使用して、結合の結果として新しい集合を返します。 first_set = {4, 5, 6} second_set = {1, 2, 3} print(first_set.union(second_set)) # {1, 2, 3, 4, 5, 6} もう1つの方法は、update()メソッドを使用して、2 番目の集合の要素を 1 番目の集合に挿入します。 first_set = {4, 5, 6} second_set = {1, 2, 3} first_set.update(second_set) print(first_set) # {1, 2, 3, 4, 5, 6} 81. print関数の条件 def is_positive(number): print("Positive" if number > 0 else "Negative") # Positive is_positive(-3) 82. 1つのif文で複数条件を指定する math_points = 51 biology_points = 78 physics_points = 56 history_points = 72 my_conditions = [math_points > 50, biology_points > 50, physics_points > 50, history_points > 50] if all(my_conditions): print("Congratulations! You have passed all of the exams.") else: print("I am sorry, but it seems that you have to repeat at least one exam.") # Congratulations! You have passed all of the exams. 83. 1つのif文で、複数条件のうち少なくとも1つの条件を満たす math_points = 51 biology_points = 78 physics_points = 56 history_points = 72 my_conditions = [math_points > 50, biology_points > 50, physics_points > 50, history_points > 50] if any(my_conditions): print("Congratulations! You have passed all of the exams.") else: print("I am sorry, but it seems that you have to repeat at least one exam.") # Congratulations! You have passed all of the exams. 84. 空でない文字列をTrueと評価する print(bool("Non empty")) # True print(bool("")) # False 85. 空でないリスト、タプル、辞書をTrueと評価する print(bool([])) # False print(bool(set([]))) # False print(bool({})) # False print(bool({"a": 1})) # True 86. Falseと評価する値は、None、False、数値0である print(bool(False)) # False print(bool(None)) # False print(bool(0)) # False 87. 関数で言及するだけでは、グローバル変数の値を変更できない string = "string" def do_nothing(): string = "inside a method" do_nothing() print(string) # string アクセス修飾子 global も使用する必要があります。 string = "string" def do_nothing(): global string string = "inside a method" do_nothing() print(string) # inside a method 88. collectionsのCounterを使用して、文字列またはリストの要素数を数える from collections import Counter result = Counter("Banana") print(result) # Counter({'a': 3, 'n': 2, 'B': 1}) result = Counter([1, 2, 1, 3, 1, 4, 1, 5, 1, 6]) print(result) # Counter({1: 5, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1}) 89. Counter を使用して、2つの文字列がアナグラムか調べる from collections import Counter def check_if_anagram(first_string, second_string): first_string = first_string.lower() second_string = second_string.lower() return Counter(first_string) == Counter(second_string) print(check_if_anagram('testinG', 'Testing')) # True print(check_if_anagram('Here', 'Rehe')) # True print(check_if_anagram('Know', 'Now')) # False sorted()を使用して、2つの文字列がアナグラムか調べることもできます。 def check_if_anagram(first_word, second_word): first_word = first_word.lower() second_word = second_word.lower() return sorted(first_word) == sorted(second_word) print(check_if_anagram("testinG", "Testing")) # True print(check_if_anagram("Here", "Rehe")) # True print(check_if_anagram("Know", "Now")) # False 90. itertoolsのcountを使用して、要素数を数える from itertools import count my_vowels = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'] current_counter = count() string = "This is just a sentence." for i in string: if i in my_vowels: print(f"Current vowel: {i}") print(f"Number of vowels found so far: {next(current_counter)}") これがコンソールに出力される結果です。 Current vowel: i Number of vowels found so far: 0 Current vowel: i Number of vowels found so far: 1 Current vowel: u Number of vowels found so far: 2 Current vowel: a Number of vowels found so far: 3 Current vowel: e Number of vowels found so far: 4 Current vowel: e Number of vowels found so far: 5 Current vowel: e Number of vowels found so far: 6 91. 頻度に基づいて、文字列またはリストの要素をソートする collectionsモジュールのcounterは、デフォルトでは、頻度に基づいて要素をソートしません。 from collections import Counter result = Counter([1, 2, 3, 2, 2, 2, 2]) print(result) # Counter({2: 5, 1: 1, 3: 1}) print(result.most_common()) # [(2, 5), (1, 1), (3, 1)] 92. リストで最も頻度の高い要素を1行で取得する my_list = ['1', 1, 0, 'a', 'b', 2, 'a', 'c', 'a'] print(max(set(my_list), key=my_list.count)) # a 93. copy()とdeepcopy()の違い ドキュメントの説明によると 浅いコピーは、新しい複合オブジェクトを構築し、(可能な範囲で)元のオブジェクトへの参照を挿入します。 深いコピーは、新しい複合オブジェクトを構築し、再帰的に、元のオブジェクトにあるオブジェクトのコピーを挿入します。 より包括的な説明はこちら 浅いコピーは、新しいコレクションオブジェクトを構築し、元のオブジェクトにある子オブジェクトへの参照を挿入することです。基本的に、浅いコピーは1レベルの深さしかありません。コピー処理は再帰的に行わないため、子オブジェクト自体のコピーを作成しません。 深いコピーは、コピー処理を再帰的に行います。つまり、新しいコレクションオブジェクトを構築し、元のオブジェクトにある子オブジェクトのコピーを再帰的に挿入します。この方法でオブジェクトをコピーすると、オブジェクトツリー全体をウォークし、元のオブジェクトとそのすべての子オブジェクトの完全に独立したクローンを作成します。 copy()の例です。 first_list = [[1, 2, 3], ['a', 'b', 'c']] second_list = first_list.copy() first_list[0][2] = 831 print(first_list) # [[1, 2, 831], ['a', 'b', 'c']] print(second_list) # [[1, 2, 831], ['a', 'b', 'c']] deepcopy()の例です。 import copy first_list = [[1, 2, 3], ['a', 'b', 'c']] second_list = copy.deepcopy(first_list) first_list[0][2] = 831 print(first_list) # [[1, 2, 831], ['a', 'b', 'c']] print(second_list) # [[1, 2, 3], ['a', 'b', 'c']] 94. 辞書で存在しないキーにアクセスしようとした時のエラー発生を防ぐ 通常の辞書を使用していて、存在しないキーにアクセスしようとすると、エラーが発生します。 my_dictonary = {"name": "Name", "surname": "Surname"} print(my_dictonary["age"]) 送出されたエラーです。 KeyError: 'age' defaultdict()を使用して、このようなエラーを回避できます。 from collections import defaultdict my_dictonary = defaultdict(str) my_dictonary['name'] = "Name" my_dictonary['surname'] = "Surname" print(my_dictonary["age"]) 95. 独自イテレータを構築する class OddNumbers: def __iter__(self): self.a = 1 return self def __next__(self): x = self.a self.a += 2 return x odd_numbers_object = OddNumbers() iterator = iter(odd_numbers_object) print(next(iterator)) # 1 print(next(iterator)) # 3 print(next(iterator)) # 5 96. リストの重複を1行で削除する my_set = set([1, 2, 1, 2, 3, 4, 5]) print(list(my_set)) # [1, 2, 3, 4, 5] 97. モジュールの場所を出力する import torch print(torch) # <module 'torch' from '/Users/...' 98. not inを使用して、値がリストに含まれていないか調べる odd_numbers = [1, 3, 5, 7, 9] even_numbers = [] for i in range(9): if i not in odd_numbers: even_numbers.append(i) print(even_numbers) # [0, 2, 4, 6, 8] 99. sort()とsorted()の違い sort()は、元のリストをソートします。 sorted()は、ソートされた新しいリストを返します。 groceries = ['milk', 'bread', 'tea'] new_groceries = sorted(groceries) # new_groceries = ['bread', 'milk', 'tea'] print(new_groceries) # groceries = ['milk', 'bread', 'tea'] print(groceries) groceries.sort() # groceries = ['bread', 'milk', 'tea'] print(groceries) 100. uuidモジュールを使用して、一意のIDを生成する UUIDとは、Universally Unique Identifierの略です。 import uuid # Generate a UUID from a host ID, sequence number, and the current time print(uuid.uuid1()) # 308490b6-afe4-11eb-95f7-0c4de9a0c5af # Generate a random UUID print(uuid.uuid4()) # 93bc700b-253e-4081-a358-24b60591076a 101. (おまけ)Pythonでは、文字列はプリミティブ型である Java経験者なら、Javaでは文字列がオブジェクトを参照するため、非プリミティブ型であることを知っているでしょう。 Pythonでは、文字列はプリミティブ型です。 この記事がお役に立てれば幸いです。ハッピーコーディング! 「朝飯前に学べる!便利なPythonのヒント100選【前編】」もご覧ください。 翻訳協力 この記事は以下の方々のご協力により公開する事ができました。改めて感謝致します。 Original Author: Fatos Morina (https://www.linkedin.com/in/fatosimorina/) Original Article: 100 Helpful Python Tips You Can Learn Before Finishing Your Morning Coffee Thank you for letting us share your knowledge! 選定担当: @gracen 翻訳担当: @gracen 監査担当: - 公開担当: @gracen ご意見・ご感想をお待ちしております 今回の記事はいかがでしたか? ・こういう記事が読みたい ・こういうところが良かった ・こうした方が良いのではないか などなど、率直なご意見を募集しております。 頂いたお声は、今後の記事の質向上に役立たせて頂きますので、お気軽に コメント欄にてご投稿ください。Twitterでもご意見を受け付けております。 皆様のメッセージをお待ちしております。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

mediapipeを含んだファイルをexe化するときに発生するエラーの原因とその対策

エラーの発生 Google Mediapipeを使うプロジェクトをEXE化するとき、下記のようなエラーが発生します。 EXE化するときに、pyinstaller, py2exeのどれを使っても、同様なエラーが発生します。 #実行 pyinstaller --onefile GUI-mediapipe-app.py #エラー Traceback (most recent call last): File "GUI-mediapipe-app.py", line 26, in <module> File "mediapipe/python/solutions/selfie_segmentation.py", line 54, in __init__ File "mediapipe/python/solution_base.py", line 229, in __init__ FileNotFoundError: The path does not exist. [36342] Failed to execute script pose_edge エラーの原因  Mediapipeライブラリーは、プログラムが実行するとき、特定のファイルを必要とします。特定のファイルとは、主にTensorflowファイルで .tflite拡張子を持っているファイルです。これらのファイルは動的に読み込まれるため(Dynamically loaded)、PyinstallerなどのEXE化ソフトが、EXE化のコンパイル過程で、これらのファイルをdist フォルダに持ってくることも認識していませんん。 従って、上記のようにFileNotFoundError: The path does not exist.のエラーが必ず発生します。 エラーの対策 この問題を解決するためには Pyinsatllerの spec fileのdata属性に、参照するフォルダを指定します。 Python環境(ここではvenv)フォルダ下にある\\Lib\\site-packages\\mediapipe\\modulesがmediapipe\\modulesであることを教えます。 datas=[(venv\\Lib\\site-packages\\mediapipe\\modules', 'mediapipe\\modules'),] ここで私が作成したspec fileを掲載します。 これで問題が解決します。 # -*- mode: python ; coding: utf-8 -*- #https://github.com/google/mediapipe/issues/2162 block_cipher = None a = Analysis(['GUI-mediapipe-app.py'], pathex=['.'], binaries=[], datas=[(venv\\Lib\\site-packages\\mediapipe\\modules', 'mediapipe\\modules'),], hiddenimports=[], hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False) a.datas += [('favicon.ico', '.\\image\\favicon.ico', 'DATA')] pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE(pyz, a.scripts, [], exclude_binaries=True, name='Tokyo2020_pictogram_GUI', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=True, disable_windowed_traceback=False, target_arch=None, codesign_identity=None, entitlements_file=None ) coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, upx_exclude=[], name='Tokyo2020_pictogram_GUI') 実行結果 課題 Pyinstallerの場合、spec fileのdata属性に参照フォルダの情報を入れることで問題を解決しました。 しかし、py2exeの場合は、どうすればいいかまだ未確認です。py2exeでの、参照フォルダの指定する方法のご存知の方は、メモを残していただければと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

非エンジニアにseleniumでスクレイピングをやってもらうまでの軌跡(準備編)

はじめに 非エンジニアの方(プログラム一切勉強したことない&GUIしか触ったことないようなレベル)にpythonでスクレイピングが出来るように色々教えた流れをまとめた個人的備忘録です。今後他の人に教える際にも参考にできるかと思いここに残しておきます。 スクレイピングって何? 情報を取得して加工することです。今回はWEBページから情報を取得します。自動でWEBページからほしい情報をまとめられるようになったら便利ですよね。それを作ります。 VSCodeとPythonのインストール 【インストールしてほしいもの】 ・Visual Studio Code(VSCode) ・Python 以下のサイトを参考にVSCodeとPythonをインストールしましょう。上から順にサイト通りに進めていきましょう。ページ下部まで終わったらnextページに飛んで同様に進めてください。【次のステップ】というページが出てきたらインストールはおしまいです。 参考URL https://www.python.jp/python_vscode/windows/setup/config_explorer.html 【なにをしているのか】 色々なものを作るためのPyhonというプログラミング言語をあなたのパソコンで使えるようにしています。そのPythonを組み立てるのがVSCodeです。とても雑に例えると鉛筆(Python)とノート(VSCode)みたいなものです。 仮想環境作成 コマンドラインの触り方をまず勉強しましょう。progateで無料アカウントを利用してレッスンを受講してください https://prog-8.com/courses/commandline コマンドラインの操作が分かるようになったら以下のサイトを参考にvenvで仮想環境を作ってください。 参考URL https://hachian.com/2019/09/19/vscode_venv/ 参考URL https://qiita.com/enya314/items/0e62b68fe70f52a628bf 【なにをしているのか】 Pythonには様々なライブラリがあり、目的別にそれらをインストールして利用します。しかし何でもかんでもインストールしているとうまく動作しなくなったりと問題が多いので仮想環境というものを作って分けて管理します。例えるとキッチンと寝室を分けるみたいなイメージです。キッチン兼寝室はちょっと嫌ですよね・・・?じゃあ部屋(仮想環境)を目的別に作って使い分けたほうがいいよねって感じです。 Pythonの基礎を知ろう progateの無料講座を受けてください。決して丸投げではないです。15分調べてみてわからなかったらすぐ聞きましょう。 https://prog-8.com/courses/python スクレイピング実践編に続く!!!!! データを取ってきてスプレッドシートに書き込めたらゴールです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DjangoでWebサービスの枠を作るまで

Djangoプロジェクトの構造 Djangoプロジェクトは、プロジェクトという大枠があり、その中にアプリケーションがあるという構造です。 プロジェクトは自分が作成したWebサイトを例えると、Appはブログ、Wiki、フォームなどがあります。 以下はmysiteというDjangoプロジェクトを作成し、そのなかにblogというAppを作成してみます。 プロジェクトの作成 以下のコマンドを実行します。 django-admin startproject mysite 生成されたプロジェクト構造を見てみましょう。 mysite/ manage.py mysite/ __init__.py asgi.py wsgi.py settings.py urls.py manage.py プロジェクトを操作するためのコマンドラインユーティリティです。編集する必要がありません。 mysite/ プロジェクトディレクトリ __init__.py mysiteディレクトリをPythonモジュールとして扱うように指定する空ファイル asgi.py ASGI(Asynchronous Server Gateway Interface) 非同期のWebサーバーとアプリケーションとして実行するための設定です。 wsgi.py WSGI(Web Server Gateway Interface)アプリケーションとして実行するための設定です。 settings.py プロジェクトの設定です。デフォルトでは、SQLite3データベースを使用するという基本的な設定と、一般的なDjangoアプリケーションが使用するINSTALLED_APPSのリストが含まれています。 urls.py URLパターンの定義 続いてデータベースマイグレーションを行います。これで初期アプリケーション用のテーブルをデータベースに作成します。 cd mysite python manage.py migrate Djangoには軽量なWebサーバが付属していて、コードを素早く実行することができます。 python manage.py runserver http://127.0.0.1:8000/ をブラウザで開き、プロジェクトが正常に実行されているページを確認できます。 実行コマンドで、カスタムなホストやポートの指定や、特定の設定ファイルを読み込ませることが可能です。 python manage.py runserver 127.0.0.1:8001 \--settings=mysite.settings Djangoの開発サーバを実行すると、コードの変更をチェックし続けます。リロードは自動的に行われます。 アプリケーションの作成 以下のコマンドを実行します。 python manage.py startapp blog アプリケーションの構造が生成されます。 blog/ migrations/ __init__.py __init__.py admin.py apps.py models.py tests.py views.py migrations/ アプリケーションのデータベースマイグレーション admin.py Django管理サイトにモデルを登録できます。管理サイトの利用はオプションです。 apps.py アプリケーションの設定 models.py アプリケーションのデータモデル tests.py アプリケーションのテスト views.py アプリケーションのロジックで、各ビューはHTTPリクエストを受け取り、それを処理してレスポンスを返します。 以上でWebサービスの枠を作ってみました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Linux(Mint)でのOpenCVセットアップ

今回の記事は頻繁に環境をリセットします。 そのため、やや備忘録的な側面が強いです。 今回はLinux Mint でのOpenCVとPythonの環境構築に関しての記事です。 今回の構築した環境も示しておきます。 lenovo thinkpad x240 cpu : intel core i5 4200u mem : 4gb ssd : 128gb 早速ここからが本題ですね まずターミナルを起動します。 まずはPythonの環境構築を行います。 Python環境の設定 Pythoneのパッケージ管理システムをインストールします。 sudo apt install python3-pip これを行うことでPython3用のパッケージ管理システムpipのインストールが完了します。 OpenCVのインストール ここでは先程インストールしたpipを用いてOpenCVをインストールを行います。 sudo pip3 install opencv-python sudo pip3 install opencv-contrib-python ここで問題ながければOpenCV自体のインストールは完了です。 NumPy ここまでインストールを行ったついでにどうせ使うので機械学習などでよく使われているNumPyをインストールしておきましょう。 pip3 install numpy 確認 ここまで問題がなければいいのですが念の為確認も行いましょう。 ターミナル上で python3 を入力してください そうするとPytonのインタプリタが起動し入力ができるようになるはずです。 そこで >> import cv2 >> cv2.__version__ 問題がなければここでインポートエラーがなくバージョン情報が表示されるはずです。 もしここまででエラーが発生した場合はPipのアップデートなどを行い再度コマンドを入力してみてください 最後に ではでは拙い文章ですが見ていただいてありがとうございます。 またどこかでお会いしましょう。 バイバイ!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Databrick REST APIによりDatabricksトークンを作成後にシークレットとして登録する方法

概要 Databrick REST APIによりDatabricksトークンを作成後にシークレットとして登録する方法を共有します。 Databricksノートブックにて下記の流れを自動で実施することで、トークンを安全に利用する方法を提示します。 Databricksトークンを手動で作成して変数にセット REST APIによりDatabricksトークンを発行 DatabricksトークンをDatabricksシークレットとして登録 不要なDatabricksトークンを削除 詳細は下記のGithub pagesのページをご確認ください。 コードを実行したい方は、下記のdbcファイルを取り込んでください。 https://github.com/manabian-/databricks_tecks_for_qiita/blob/main/tecks/create_sercrets_by_rest_api/create_sercrets_by_rest_api.dbc 実行環境 databricks runtime: 8.3.x-cpu-ml-scala2.12 Python version: 3.8.8 pyspark version: 3.1.2.dev0 手順 1. Databricksトークンを手動で作成して変数にセット User Settingsにてtmpというコメントをつけたトークンを作成。 下記のコードのトークンの変数の値にトークンの値を設定。 import json scope_name = "databricks_mlops" # scope名をセット databricks_token = "databricks_token" # DatabricksトークンにおけるsecreatのKey名をセット databricks_url = "databricks_url" # DatabricksのURLをsecretsのKey名をセット # トークン ## 最初は下記にシークレットを格納 token = "dapi5c768bf24dbd3be15cbc728066cccccc" # 2回目からはDatabricksシークレットから取得 try: token = dbutils.secrets.get(scope_name, databricks_token) except Exception: pass # DatabricksのURL ## 下記についてはJobsから実行する際には適切に値を取得できないことに注意 browserhostname = json.loads(dbutils.notebook.entry_point .getDbutils() .notebook() .getContext() .toJson() )['tags']['browserHostName'] db_url = f'https://{browserhostname}' #3 2回目からはDatabricksシークレットから取得 try: db_url = dbutils.secrets.get(scope_name, databricks_url) except: pass 2. REST APIによりDatabricksトークンを発行 import requests # 秒×分×時間×1月当たりの日数×月 lifetime_seconds = 60*60*24*30*3 # トークンに設定するコメント。削除対象の判断で利用。 comment = "by Rest API" data = None response = requests.post( f'{db_url}/api/2.0/token/create', headers={'Authorization': f'Bearer {token}'}, json={ "lifetime_seconds": lifetime_seconds, "comment": comment, }, ) if response.status_code == 200: created_token_value = response.json()['token_value'] created_token_id = response.json()['token_info']['token_id'] elif response.status_code == 403: print(response.text) else: print("Error geting the job: {0}: {1}".format(response.json()["error_code"],response.json()["message"])) 3. DatabricksトークンをDatabricksシークレットとして登録 ## scopeを作成 import requests # scope名をセット scope_name = "databricks_mlops" response = requests.post( f'{db_url}/api/2.0/secrets/scopes/create', headers={'Authorization': f'Bearer {token}'}, json={ "scope": scope_name, }, ) if response.status_code == 200: print(f'Success:create scope "{scope_name}"') elif response.status_code == 400: # スコープが存在する場合の分岐 if response.json().get('error_code') == "RESOURCE_ALREADY_EXISTS": print(f'scope "{scope_name}" already exists') else: print(response.text) elif response.status_code == 403: print(response.text) else: print("Error geting the job: {0}: {1}".format(response.json()["error_code"],response.json()["message"])) # Databricksトークンをsecretsに登録 import requests response = requests.post( f'{db_url}/api/2.0/secrets/put', headers={'Authorization': f'Bearer {token}'}, json={ "scope": scope_name, "key": "databricks_secrets", "string_value": created_token_value, }, ) if response.status_code == 200: print(f'Success:create or replace secrets {scope_name}') elif response.status_code == 403: print(response.text) else: print("Error geting the job: {0}: {1}".format(response.json()["error_code"],response.json()["message"])) # DatabricksのURLをsecretsに登録 import requests response = requests.post( f'{db_url}/api/2.0/secrets/put', headers={'Authorization': f'Bearer {token}'}, json={ "scope": scope_name, "key": "databricks_url", "string_value": db_url, }, ) if response.status_code == 200: print(f'Success:create or replace secrets {scope_name}') elif response.status_code == 403: print(response.text) else: print("Error geting the job: {0}: {1}".format(response.json()["error_code"],response.json()["message"])) 4. 不要なDatabricksトークンを削除 # 本処理作成したトークン以外のリストを作成。 # ただし、`tmp`と`by Rest API`というコメントが設定さているトークンのみ対象 import requests response = requests.get( f'{db_url}/api/2.0/token/list', headers={'Authorization': f'Bearer {token}'}, ) if response.status_code == 200: input_dict = response.json() token_id_target_deletion = [] for i,x in enumerate(input_dict['token_infos']): if x['comment'] == 'tmp': token_id_target_deletion.append(x['token_id']) elif x['comment'] == comment and x['token_id'] != created_token_id: token_id_target_deletion.append(x['token_id']) elif response.status_code == 403: print(response.text) else: print("Error geting the job: {0}: {1}".format(response.json()["error_code"],response.json()["message"])) # トークンを削除する関数を定義 import requests def delte_databricks_token(token_id): response = requests.post( f'{db_url}/api/2.0/token/delete', headers={'Authorization': f'Bearer {token}'}, json={ "token_id": token_id, }, ) if response.status_code == 200: print(f'Success:delte token_id {token_id}') elif response.status_code == 403: print(response.text) else: print("Error geting the job: {0}: {1}".format(response.json()["error_code"],response.json()["message"])) # 不要なトークンを削除 for token_id in token_id_target_deletion: delte_databricks_token(token_id)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

カーネル密度推定(KDE: Kernel Density Estimation)をpython (numpy)で実装・整理してみる

KDEとは?  ”カーネル密度推定(カーネルみつどすいてい、英: kernel density estimation)は、統計学において、確率変数の確率密度関数を推定するノンパラメトリック手法のひとつ(Wikipedia)”とされており、機械学習などで様々に応用されています。KDEはscipyやseaborn、pandasに実装されている為、これらを使えば簡単にKDEをプロットすることができますが、実際のところ何をしてるのかイマイチよく分かっていないブラックボックスとして使ってしまっていました。本記事では、KDEを一から実装しつつ、パラメータの意味などについても整理してみたいと思います。 KDEの定義  ${x_1,x_2,...,x_n}$を独立かつ同一な分布に従うサンプルとして、KDEではこれらのサンプルの従う分布の確率密度関数fの近似$\hat{f_h(x)}$を以下の式によって推定します。 \hat{f_h(x)}=\frac{1}{nh}\sum_{i=1}^{n}K(\frac{x-x_i}{h})  ここで$h$はバンド幅、$K(v)$はカーネル関数と呼ばれます。カーネル関数としてガウス分布が有名ですが、他の確率密度関数を使うこともできます。pythonでの実装は非常にシンプルです。 KDE.py #sampleはKDEの対象データ def kde(x,sample,band_width,kernel): n=len(sample) return np.sum([1/(n*band_width)*kernel((x-sample[i])/band_width) for i in range(n)])  KDEの結果を確率密度関数として解釈できる理由としては、各カーネル関数が確率密度関数であることから理解できます。カーネル関数は非負なので、それらの和も非負になります。また、$\hat{f_h(x)}$の積分についても、以下に示す様に$1$に等しくなります(途中で置換積分と、確率密度関数の定義(全範囲での積分が$1$)を使っています)。 \int^{\infty}_{-\infty}\hat{f_h(x)}dx =\int^{\infty}_{-\infty}\frac{1}{nh}\sum_{i=1}^{n}K(\frac{x-x_i}{h})dx\\ =\frac{1}{nh}\sum_{i=1}^{n}\int^{\infty}_{-\infty}K(\frac{x-x_i}{h})dx =\frac{1}{nh}\sum_{i=1}^{n}\int^{\infty}_{-\infty}K(t)hdt\\ =\frac{1}{n}\sum_{i=1}^{n}1 =\frac{1}{n}*n =1  では、KDEは実際のところ何をやっているのでしょう…?KDEではカーネル関数の総和を確率密度関数の推定として採用します。その様子を見える為に、正規分布から発生させたサイズ$15$のサンプルについてKDEを行い、それぞれのカーネル関数の寄与を図示してみましょう。 KDE_contribute.py import numpy as np import matplotlib.pyplot as plt import scipy.stats as stats import random random.seed(10) np.random.seed(1) sample_size=15 mean=3 #サンプルを取る正規分布の平均 sigma=2 #サンプルを取る正規分布の分散 #正規分布の定義 def normal(x,mean,sigma): return 1/np.sqrt(2*np.pi*sigma**2)*np.exp(-((x-mean)/sigma)**2) #サンプルの発生 y=list(np.random.normal(loc=mean,scale=sigma,size=int(sample_size))) sample=sorted(y) fig,ax=plt.subplots(nrows=2,figsize=(20,15)) #サンプルを取った正規分布の描画 ax1=ax[0] x_kernel=np.linspace(np.min(y),np.max(y)) ax1.plot(x_kernel,[normal(x_kernel[i],mean,sigma) for i in range(len(x_kernel))],label='source',linewidth=5,color='cyan') #ガウスカーネル関数の定義 def normal_kernel(x): return 1/np.sqrt(2*np.pi)*np.exp(-x**2/2) #Scott's ruleによるバンド幅の設定(後述) band_width=np.sqrt(np.var(sample,ddof=1)*((sample_size)**(-1/5))**2) cmap=["#"+''.join([random.choice('0123456789ABCDEF') for j in range(6)]) for i in range(len(sample))] #各カーネル関数へ(x-x_i)/hを代入し、1/nhを掛けた関数の描画 output=[] for i in range(len(sample)): y_kernel=1/(sample_size*band_width)*normal_kernel((x_kernel-sample[i])/band_width) output.append(y_kernel) ax1.plot(x_kernel,y_kernel,color=cmap[i]) ax1.vlines(sample[i],0,0.1) #x_iの点の描画 ax1.legend(fontsize=30) ax2=ax[1] #それぞれのカーネル関数の寄与を描画 ax2.stackplot(x_kernel,output,colors=cmap) #KDEの結果を描画 x=np.linspace(np.min(sample),np.max(sample)) y=[kde(x[i],sample,band_width,normal_kernel) for i in range(len(x))] ax2.plot(x,y,color='k',linewidth=10,label='kde',linestyle='dashed') #サンプルを取った正規分布の描画 y=[normal(x[i],mean,sigma) for i in range(len(x))] ax2.plot(x,y,color='cyan',linewidth=10,linestyle='dashed',label='source') ax2.legend(fontsize=30)  若干見にくいですが、上の図からそれぞれのサンプル点の周囲に正規分布の形状のグラフが発生しており、下の図からこれらのグラフが集中している場所(元の正規分布の平均付近)ではより多くのグラフが寄与することで、KDEの結果に元の正規分布のピークが再現されていることが分かります。このことから、KDEは”データが集中しているところには、元の分布のピークがあったんだろう”というアイデアに基づいていると考えられます。 KDEのパラメータ(バンド幅・カーネル関数) バンド幅について  KDEではカーネル関数の変数へはある点$x$と、$i$番目のサンプル点$x_i$の差をバンド幅$h$で割ったものが代入されています。このことから、同じ$x-x_i$の値であっても、バンド幅が大きい程カーネル関数へと代入される値は小さくなることが分かります。ガウス分布に代表されるカーネル関数は原点($v=0$、すなわち$x=x_i$の点)から離れるほど値が小さくなることから、バンド幅を大きくすることで、$x_i$から離れた値が効いてくる様になります。最終的にこれらのカーネル関数の総和がKDEによる確率密度関数の推定結果となることから、大きなバンド幅はより滑らかな推定になることが期待できます。バンド幅を変化させた時の$\frac{1}{nh}K(\frac{x-x_i}{h})$の様子を見てみましょう。 kernel_band_width.py #3種類のバンド幅のオプション h=[0.05,0.3,1] #サンプル数5 sample_size=5 y=list(np.random.normal(loc=mean,scale=sigma,size=int(sample_size))) sample=sorted(y) x_kernel=np.linspace(np.min(y)-1,np.max(y)+1,500) cmap=["#"+''.join([random.choice('0123456789ABCDEF') for j in range(6)]) for i in range(len(sample))] fig,ax=plt.subplots(nrows=3,figsize=(20,15)) #それぞれのバンド幅についてグラフを描く for k in range(3): h_k=h[k] ax_k=ax[k] for i in range(len(sample)): y_kernel=[1/(sample_size*h_k)*normal_kernel((x_kernel[j]-sample[i])/h_k) for j in range(len(x_kernel))] ax_k.plot(x_kernel,y_kernel,color=cmap[i]) ax_k.vlines(sample[i],0,np.max(y_kernel)*1.1) ax_k.set_title(f'bandwidth={h_k}',fontsize=20)  これらのグラフより、バンド幅が広いほどより個々のカーネル関数の重なりが大きくなり、これらの総和で表現されるKDEの結果も滑らかなものとなると考えられます。では、適切なバンド幅ははどの様に設定すればよいのでしょうか?scipyでも使われている"Rule-of-thumb"として、Scott's-ruleとSilverman's-ruleが挙げられます。こちらのサイトを参考とさせて頂いたところ、一次元データの場合はそれぞれのルールに基づいてバンド幅は以下の様に推定されます。 Scott's\quad rule\\ h=n^{\frac{-1}{5}}*\sqrt{\hat{\sigma}}\\ Silverman's\quad rule\\ h=(\frac{3}{4}n)^{-\frac{1}{5}}*\sqrt{\hat{\sigma}}\\ *\hat{\sigma}は対象データの不偏分散、nは対象データの数  これらのルールに基づいて決定したバンド幅を使用した場合と使用しない場合のそれぞれについて、KDEの結果を比較してみましょう。 bandwidth_rule.py #Scott's ruleによるバンド幅 h_scott=np.sqrt(np.var(sample,ddof=1)*((sample_size)**(-1/5))**2) #Silverman's ruleによるバンド幅 h_silverman=np.sqrt(np.var(sample,ddof=1)*((3/4*sample_size)**(-1/5))**2) h=[0.05,0.3,3] sample_size=300 y=list(np.random.normal(loc=mean,scale=sigma,size=int(sample_size))) sample=sorted(y) x=np.linspace(np.min(y)-1,np.max(y)+1,100) fig,ax=plt.subplots(nrows=5,figsize=(20,20)) for k in range(3): h_k=h[k] ax_k=ax[k] for i in range(len(sample)): y_kde=[kde(x[i],sample,h_k,normal_kernel) for i in range(len(x))] ax_k.plot(x,y_kde,color='red') y=[normal(x[i],mean,sigma) for i in range(len(x))] ax_k.plot(x,y,color='k') ax_k.set_title(f'bandwidth={h_k}',fontsize=20) #Scott's ruleによるKDEの描画 ax[3].plot(x,[kde(x[i],sample,h_scott,normal_kernel) for i in range(len(x))]) ax[3].plot(x,[normal(x[i],mean,sigma) for i in range(len(x))],color='k') ax[3].set_title(f'Scott: {h_scott:3f}',fontsize=20) #Silverman's ruleによるKDEの描画 ax[4].plot(x,[kde(x[i],sample,h_silverman,normal_kernel) for i in range(len(x))]) ax[4].plot(x,[normal(x[i],mean,sigma) for i in range(len(x))],color='k') ax[4].set_title(f'Silverman: {h_silverman:3f}',fontsize=20)  バンド幅が小さい場合にはギザギザとした近似であり、バンド幅が大きすぎると滑らかな近似になりすぎてしまうことが分かります。また、Scott's rule、Silverman's ruleのいずれについても、それなりに良い近似を与えていることが観察できます。 カーネル関数について  ガウスカーネルは広く使われており、scipyのKDEではgaussian_kdeとして実装されています。しかしながら、他にも利用可能なカーネル関数はいくつかあることから、これらについて比較・検討してみたいと思います。サンプルデータとして、正規分布の混合分布を用います。 sample_data.py mean1=3 mean2=15 sigma1=2 sigma2=4 sample_size=3000 def normal(x,mean,sigma): return 1/np.sqrt(2*np.pi*sigma**2)*np.exp(-((x-mean)/sigma)**2) def normal_kernel(x): return 1/np.sqrt(2*np.pi)*np.exp(-x**2/2) sample=[] for i in range(sample_size): idx=np.random.randint(1,3) if idx==1: sample.append(np.random.normal(loc=mean1,scale=sigma1)) else: sample.append(np.random.normal(loc=mean2,scale=sigma2)) sample=sorted(sample) fig,ax=plt.subplots() ax.hist(sample,density=True,bins=100) ax.set_xlim(np.min(sample),np.max(sample)) x=np.linspace(0,np.max(sample)) ax.plot(x,0.5*normal(x,mean1,sigma1)+0.5*normal(x,mean2,sigma2)) ガウスカーネル  非常によく知られた標準正規分布をカーネル関数に用いるものです。scipyのgaussian_kdeによるKDEの結果と、実装したKDEの結果を比較してみましょう。 compare.py #Scott's ruleによるバンド幅の設定 band_width=np.sqrt(np.var(sample,ddof=1)*((sample_size)**(-1/5))**2) #実装したKDEの結果 x=sorted(np.linspace(np.min(sample),np.max(sample),200)) y=[kde(x[i],sample,band_width,normal_kernel) for i in range(len(x))] #ScipyによるKDEの結果 kernel_scipy=stats.gaussian_kde(sample) y_scipy=kernel_scipy(sample) fig,ax=plt.subplots(figsize=(10,7)) ax.plot(x,y,label='kde') ax.plot(sample,y_scipy,linestyle='dashed',label='scipy') ax.legend(fontsize=15)  どうやらほぼ一致している様です。カーネル関数の形と、もともとの確率密度関数の形状を比較してみましょう。 normal_kernel.py fig,ax=plt.subplots(nrows=2,figsize=(15,10)) #ガウスカーネルの描画 ax1=ax[0] x=np.linspace(-5,5) y=normal_kernel(x) ax1.plot(x,y) ax2=ax[1] x=np.linspace(0,np.max(sample),200) band_width=np.sqrt(np.var(sample,ddof=1)*((sample_size)**(-1/5))**2) y=[kde(x[i],sample,band_width,normal_kernel) for i in range(len(x))] ax2.plot(x,y,label='kde') ax2.plot(x,0.5*normal(x,mean1,sigma1)+0.5*normal(x,mean2,sigma2),label='source') ax2.legend(fontsize=15)  ピークの位置は上手く拾えていますが、広がりについてはもう一声という雰囲気ですね。 2.Top-hatカーネル  一様分布を採用したものです。カーネル関数の形がシルクハット(top hat)に似ていることから、この名前がついていると思われます。 tophat_kernel.py def tophat_kernel(x): if -1<x<1: return 0.5 else: return 0 fig,ax=plt.subplots(nrows=2,figsize=(15,10)) ax1=ax[0] x=np.linspace(-5,5,200) y=[tophat_kernel(x[i]) for i in range(len(x))] ax1.plot(x,y) ax2=ax[1] x=np.linspace(0,np.max(sample),200) band_width=np.sqrt(np.var(sample,ddof=1)*((sample_size)**(-1/5))**2) y=[kde(x[i],sample,band_width,tophat_kernel) for i in range(len(x))] ax2.plot(x,y,label='kde') ax2.plot(x,0.5*normal(x,mean1,sigma1)+0.5*normal(x,mean2,sigma2),label='source') ax2.legend(fontsize=15)  ガウスカーネルと比べてギザギザとしていますが、ピークの高さと位置はよく合っていそうな雰囲気です。 3.Linearカーネル  線形な関数をカーネル関数へと採用したものです。 linear_kernel.py def linear_kernel(x): if 0<abs(x)<1: return 1-abs(x) else: return 0 fig,ax=plt.subplots(nrows=2,figsize=(15,10)) ax1=ax[0] x=np.linspace(-5,5,200) y=[linear_kernel(x[i]) for i in range(len(x))] ax1.plot(x,y) ax2=ax[1] x=np.linspace(0,np.max(sample),200) band_width=np.sqrt(np.var(sample,ddof=1)*((sample_size)**(-1/5))**2) y=[kde(x[i],sample,band_width,linear_kernel) for i in range(len(x))] ax2.plot(x,y,label='kde') ax2.plot(x,0.5*normal(x,mean1,sigma1)+0.5*normal(x,mean2,sigma2),label='source') ax2.legend(fontsize=15)  Top-hatより滑らかですし、ガウスカーネルと比べて高さの合致も良いので、個人的には試したカーネルの中で一番良さそうな雰囲気を受けました。 4.Exponentialカーネル  指数関数を採用したものです。 exponential_kernel.py def exponential_kernel(x): return 0.5*np.exp(-abs(x)) fig,ax=plt.subplots(nrows=2,figsize=(15,10)) ax1=ax[0] x=np.linspace(-5,5,200) y=[exponential_kernel(x[i]) for i in range(len(x))] ax1.plot(x,y) ax2=ax[1] x=np.linspace(0,np.max(sample),200) band_width=np.sqrt(np.var(sample,ddof=1)*((sample_size)**(-1/5))**2) y=[kde(x[i],sample,band_width,exponential_kernel) for i in range(len(x))] ax2.plot(x,y,label='kde') ax2.plot(x,0.5*normal(x,mean1,sigma1)+0.5*normal(x,mean2,sigma2),label='source') ax2.legend(fontsize=15)  ガウスカーネルにソックリですね。正直違いが分かりませんでした。 5.Epanechnikovカーネル  この論文でカーネル関数の例として扱われています。定義は以下の様になっています。 K(v)=\frac{3}{4\sqrt{5}}(1-\frac{x^2}{5}) \quad (|x| \leq\sqrt{5}) epanechnikov_kernel.py def epanechnikov_kernel(x): if 0<abs(x)<np.sqrt(5): return (3/(4*np.sqrt(5)))*(1-(x**2)/5) else: return 0 fig,ax=plt.subplots(nrows=2,figsize=(15,10)) ax1=ax[0] x=np.linspace(-5,5,200) y=[epanechnikov_kernel(x[i]) for i in range(len(x))] ax1.plot(x,y) ax2=ax[1] x=np.linspace(0,np.max(sample),200) band_width=np.sqrt(np.var(sample,ddof=1)*((sample_size)**(-1/5))**2) y=[kde(x[i],sample,band_width,exponential_kernel) for i in range(len(x))] ax2.plot(x,y,label='kde') ax2.plot(x,0.5*normal(x,mean1,sigma1)+0.5*normal(x,mean2,sigma2),label='source') ax2.legend(fontsize=15)  これもガウスカーネルと違いがよく分かりませんでした。何か数学上便利な性質はありそうですが。 おわりに  本記事ではKDEについてnumypyを使って実装し、その中身やパラメータの意味について整理してみました。バンド幅については経験則的な方法で十分と思われますが、カーネル関数はガウスカーネルとほぼ変わらない挙動を示すもの(Exponentinal、Epanechnikov)、ガウスカーネルと異なった挙動を示すもの(Top-hat、Linear)があったことから、ガウスカーネルで望ましい結果が得られない場合には異なる種類のカーネル関数を試すのも良いかもしれません。ここまでお読みいただき、ありがとうございました。何か誤り等ございましたら、コメントにてお伝え頂けますと幸いです。よろしくお願いいたします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ParlAIで英会話を楽しむ

1、概要  Facebook AI Researchは、2021年7月下旬に会話の内容を知識として蓄えつつ、同時にネット検索をして知識をアップデートする機能を備えたAIチャットボット「BlenderBot 2.0」をオープンソースで公開したことを発表しました。(リンクはこちら) 残念ながら、私の環境ではまだ「BlenderBot 2.0」は動作していませんが、前身である「BlenderBot 1.0」を利用したAIチャットボットを作成してみましたので、紹介します。 作成したものは、Browser上でキーボード入力あるいは音声入力で英会話(音声出力も有り)を楽しむことが出来ます。 2、動作環境  本チャットボットは、「Python Script」と「HTML」、「Javascript」で作られており、動作環境は次の通りです。 Windows10 64-bit Visual Studio Code (VS Code) Python 3.9.4 64-bit Browser: Microsoft Edge or Google Chrome 3、デモ画面 4、動作方法  VS Code上でPythonを動作させたい方は、「Visual Studio CodeでPythonプログラミングを始める(Windows編)」や「Visual Studio CodeにPython環境を」を参考に導入して下さい。 なお、私は上記の環境でしか動作確認をしておりませんので悪しからず! 4-1、準備 (1) ファイルのDownloadとUnzip  次のURLでそれぞれの緑ボタン「Code」からZipファイルをダウンロードし、解凍して下さい。 次に解凍したフォルダーをシステム・パスが通った場所に移動させて下さい。(VS CodeでPython Scriptファイルを開き、「ターミナル(T)」から「新しいターミナル」を開くとパスが通っている場所が分かると思います。) https://github.com/facebookresearch/ParlAI: facebookresearch/ParlAI https://github.com/To-Fujita/ChatBot_with_ParlAI: Chat bot with ParlAI (2) Pythonへのライブラリ・インストール  次のPythonライブラリをインストールして下さい。 ParlAI: pip install parlai Python-Aiml: pip install python-aiml Flask: pip install Flask 4-2、いくつかのParlAI_Agent/Modelの動作確認  ダウンロードした「ChatBot_with_ParlAI-main」フォルダーを開き、次のファイルをVS Codeで開いて下さい。 VS Codeで「実行(R)」⇒「デバックの開始」あるいは「デバックなしで実行」を選択すると、それぞれのAgent/Modelとターミナル上での会話が出来ると思います。 confirm_Alice.py: The ALICE bot is a strong rule-based bot uing AIML. confirm_All_Tasks_mt.py: One of Dodeca models in Zoo, please refer to Model Zoo confirm_Blender_90M.py: Blended Skill Talk models in Zoo, please refer to Model Zoo confirm_Blender_400M.py: Large size of Blended Skill Talk models in Zoo.  上記Python Scriptが上手く動作しない場合には、パス設定を確認して下さい。 なお、それぞれのScriptファイル内でもパス設定の追加が可能です。 また、「Alice」以外の動作では数百メガから数ギガの容量のファイルをダウンロードしますので、時間を要します。 もちろん、それなりのCPUパワーも必要なようです。 4-3、ChatBotでの英会話  上記と同様に次のファイルをVS Codeで開き、「実行(R)」⇒「デバックの開始」あるいは「デバックなしで実行」を選択して下さい。 その後、ブラウザを開き「http://127.0.0.1:5000」 と入力することで、チャットボットとの会話が出来ます。 main_Alice.py main_All_Tasks_mt.py main_Blender_90M.py main_Blender_400M.py  このチャットボットは、マン/マシン・インターフェースをHTML/Javascriptで会話の内容をPythonで作成する構成にしています。 HTMLでは、「Dialog Element」を使用していますので、まだ「Dialog Element」に対応していない「Safari」や「Firefox」では上手く動作しないと思います。 5、Reference [Facebookresearch/ParlAI]開始ttps://github.com/facebookresearch/ParlAI): A framework for training and evaluating AI models on a variety of openly available dialogue datasets. ChatBot_with_ParlAI: Chat bot based on the ParlAI by Facebook. Visual Studio Code: コードを Azure に簡単にデプロイできる統合ツールを備えた強力で軽量な無料コード エディター Welcome to Python.org: Python is a programming language that lets you work more quickly and integrate your systems more effectively. 無料の音声合成・音声認識を使用して簡易人工無脳と会話する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ディープラーニングを 15分でさらりと理解 - Neural Network Console 編-

ソニー社が提供するNeural Network Consoleを15分で体験!投資家エンジニアのマットです。 https://standbyme.online 今日皆さんに紹介するのは、ソニー社が提供するプログラミング不要の、ニューラル ネットワーク コンソール(長!!)と呼ばれるクラウドサイトです。ではまずは15分でAIを無料で試しましょう! ニューラルネットワークとは、人間の脳内神経細胞(ニューロン)とその神経回路網を人工的に数式モデル。機械学習(マシーンラーニング)と呼ばれる手法のひとつ。 目次 その1) Neural Network Consoleでサインイン その2) 雛形を選んで、文字認識の学習するよ その3) 学習結果から文字認識(推論)しよう! その4) 文字認識の結果を見よう! まとめ その1) Neural Network Consoleでサインイン なまえと最低限の情報でOK。 最初のページはダッシュボード。プロジェクトを選択して雛形を見よう。 その2) 雛形を選んで、文字認識の学習するよ サンプルプロジェクトはたくさんあるよ。目的やカテゴリ、又はデータセット(アルゴリズム別)でも選択できるよ。 今回はとってもシンプルな文字認識「01_logistic_regression.sdcproj 」のサンプルを選んだよ。 その3) 学習結果から文字認識(推論)しよう! サンプルプロジェクトが読み込まれたね。グラフィカルでわかりやすい画面だね。簡単に言うと手書き文字認識データセットの1x28x28のモノクロ手書き文字画像(4と9の画像)が読み込まれるよ。その手書き文字が「9」かどうかの判別を行うためのネットワーク(Sigmoid)が読み込まれていることを確認。 画面右上のコントローラ「実行」を押すと「学習」が始まるよ。 PS: AIの「学習」とは、人間が勉強するのと同じで、たくさん「4」や「9」を読み込ませるよ。「9」と覚えることでコンピュータが「判別(推論)」ができるようになるよ。 学習が終わるとTRAININGタブにて、学習の進捗状況が学習曲線と共に表示。クラウド(CPU実行)上で3分ほどかかったよ。 PS:複雑な学習や、たくさんの画像や音声を取り込みたいときは「コントローラ」のNVIDIA**等を有料で使えるよ。 難しい説明はさておき、学習曲線(グラフ)の横軸(Epoch)は最適化の繰り返した世代だね。深いとError(ミス)が減るよ、でも時間もかかるよ。縦軸(Cost)は最適化段階で学習データ、評価データそれぞれにおけるロスした値を示しめしているよ。要は図のように右に移動(世代数の増加)するにつれて、従いCost、Errorの値が下がっているので、正しく最適化(文字認識)が出来ているね。 その4) 文字認識の結果を見よう! 次に画面左上の「評価」タブを選択し、「実行」ボタンをクリック。数分で学習データから文字認識(推論・評価)結果がでるよ。 無事「9」と「4」を評価値(無関係0.0 ~そっくり1.0の数値)でコンピュータが答えをだしているね。枠線の画像は「0.9955」「0.9705」「0.9906」など「そっくり1.0」に近いね。反対に「4」の画像は、「0.0024」など数値が低いね。 最後に「評価」タブの「混同行列」を選択して、精度を見てみましょう。 「Accuracy」が精度「そっくり1.0」だね。 ニューラルネットワークの仕組みと構造  一つひとつの人工ニューロンはシンプルだよ。それを多数組み合わせて複雑な近似するのが、ニューラルネットワークの特徴。一般的に、分類や回帰ができない事象では、従来型の機械学習手法ではうまくいかないケースも。そんなケースには、ディープラーニング手法がマッチ。ディープラーニングは、従来の機械学習に比べて飛躍的に認識精度が向上するケースもあるよ。 まとめ ソニー社のAIクラウドサービスの特徴は以下を解決するサービスだよ。 - Pythonや数式を学ばないといけない - ネットワーク構造やパラメータを変更,コーディングで試行錯誤 - 学習した何十種類ものニューラルネットワークの管理に苦労 - ニューラルネットワークのチューニングを自動化したい - 開発環境の構築に手間と費用がかかる 尚無償は10時間だけなので、時間が取れる日に試してね! では、良い一日を! 他にも記事を書いているので、みてください。 プログラミング記事:https://standbyme.online/stepup/ note記事: https://note.com/matt2cents サイト:https://standbyme.online by 投資家エンジニア マット
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CodeBuildを使ってみた

初めに 業務で利用しているので簡単にまとめてみた 前提 CodeCommitでソースコードをアップロード済み 概要 プロジェクト名はコンソールから変更できないので注意。 基本的には以下の流れ。 ソースコードのトップにbuildspec.ymlファイルを作成 その中に設定を書き込んでソースコードをzip化 S3にzip化したファイルをアップロード 注意することは、S3にアップロードする際の権限くらい CodeBuildにロールを付与するときに、S3FullAccessを付けておくと良い buildspec.yml YAMLファイルの名称はオプションで変更することが可能。(オプショナル) サンプルファイル 以下は、Python前提としたテンプレ。 その中に設定を書き込んでソースコードをzip化 S3にzip化したファイルをアップロード version: 0.2 phases: install: runtime-versions: python: 3.8 build: commands: - zip -r xxx.zip ./ - aws s3 cp xxx.zip s3://xxx/ version: 0.2は最新バージョンでおまじないと思えば良い。 Reference 公式リファレンス Build specification reference for CodeBuild
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Django 外部からのアクセス許可方法

設定 settings.py # ALLOWED_HOSTS = [] # もとはこうなっている ALLOWED_HOSTS = ['*'] ※プロジェクト名と同じフォルダ内にsettings.pyがある。 起動 python manage.py runserver 192.168.1.10:8000 ※IPアドレスはサーバ起動しているPCまたはサーバのIPアドレス
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Seriesの生成

概要 Pabdasのデータ構造の一つで、1次元の配列の配列のように扱う事が可能。 pandasをインポートし、pandas.Series(辞書型のリスト)とする事でSeriesを作成する。 また、pandas.Series(データ配列, index=インデックス配列)の様にデータとそれに関連付けたインデックスを指定する事でもSeriesを作成可能。 Seriesを出力した際にdtype: int64と出力されるのは、Seriesに格納されている値が int64という型であること を示している。 dtypeとはData typeの事でデータ型の事。(データが整数であればint、小数があればfloat) pandas.Series(辞書型のリスト) import pandas as pd fruits = {"banana": 3, "orange": 2} print(pd.Series(fruits)) pandas.Series(データ配列, index=インデックス配列) import pandas as pd fruits = ["apple", "orange", "banana", "straberry", "kiwifruit"] data = [10, 5, 1, 2, 3] series = pd.Series(data, index = fruits) print(series)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

オブジェクト指向プログラミングとは

はじめに どのプログラミング言語から勉強するにしても、共通して「コードはどう書くべきか」、つまり「どのようにソフトウェアを設計するべきか」という課題に直面するときがあると思います。私自身それについて考える機会があり、「オブジェクト指向プログラミング」というソフトウェアの設計手法に改めて向き合ってみました。考え方など、自身の中に落とし込むことに苦労したため、理解のプロセスを備忘録として残してみました。この記事はプログラミングの基礎をある程度理解している人であれば、全く問題なく読み進められるように作りましたので、是非最後まで読んでみてください。(コード解説はPythonを使用しました) コードはどう書くべきなのか 私たちは何か作りたいものがあるときに、コードを書き、実装していくと思いますが、特にチームを組んで開発するような大規模なプロダクトに関わるときには「綺麗な、読みやすい」コードを書くことが求められます。つまりプロダクトに関して、コードを書いた本人でなくとも、修正しやすい、新しい機能を追加しやすいといった「効率性」を目的としています。ではコードを書くときは、どのようなことを意識するべきなのでしょうか。大きく分けて答えは、「flexibility(柔軟性)」と「scalability(拡張性)」です。「flexibility(柔軟性)」は、修正したい箇所があるときに柔軟に対応できるのかを表し、「scalability(拡張性)」は、新しく要素や機能を追加したいときに、その規模に関係なく対応できるのかを表します。コードを修正するにしろ、追加するにしろ、コードは誰が読んでも理解しやすいものでなくてはならないため、以上の2つを意識します。そこでオブジェクト指向プログラミングという概念が出てきます。 オブジェクト指向プログラミングとは **オブジェクト指向プログラミング 互いに密接な関連性を持つデータとコードをひとつにまとめてオブジェクトとし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定義と、それらオブジェクトを相互に作用させる様々なプロセスの設定を通して、プログラム全体を構築するソフトウェア開発手法である。(引用:wikipedia) オブジェクトとは、文字列やリストのようなデータ型のことです。つまり「データとコードをひとつにまとめてオブジェクトとし...」という文言がありますが、これは新しいデータ型を作ることを表します。したがってオブジェクト指向プログラミングを用いることで、アプリケーションの機能ごとに新しいデータ型を作成し、処理を分かりやすく分離することができるため、前述した「flexibility(柔軟性)」と「scalability(拡張性)」のあるプログラムを構築することができます。続けてより分かりやすく説明するために実際にオブジェクト指向プログラミングを用いて、今回はあるゲームを実装していきます。 開発する上で意識すべきこと 実際にオブジェクト(新しいデータ型)を作成していく上で意識することは、「機能ごとにどう処理を分けていくか」です。どのように機能ごとに処理を分けるかは、下の図で示しています。下の図はチャットボットを開発する際に、オブジェクト指向プログラミングを用いている場合と、いない場合の処理の分け方を表したものです。チャットボット1つをとっても、「メッセージの受信」、「応答メッセージの作成」など機能ごとに分類することができます。 オブジェクト指向を用いることで、何か新しい機能を追加したいとき、既にある機能を修正したいときに、どこのプログラムに手を加えれば良いのか一目で分かるため、余計な箇所を触る心配もなく、予期せぬエラーを防ぐことができます。オブジェクト指向プログラミングを用いて実装する上で意識するポイントを確認したところで、実例を用いてオブジェクト指向プログラミングがいかにソフトウェアの設計に有用か説明します。 オブジェクト指向プログラミングによる実装 オブジェクト指向プログラミングを用いて実装していく上で、今回はあるゲームを実例として扱います。シンプルに好きな果物が何なのか当てるゲーム(Guessing Game)です。流れとしては、まずユーザーに果物の名前を入力してもらい、アルファベットで入力されているか確認、正解であるappleが入力されていれば処理が完了するようなプログラムとしました。このゲームを、オブジェクト指向プログラミングを用いずに実装すると下記のコードのようになるかと思います。 オブジェクト指向なし guessing_game.py guess = 0 while True: fruit = input("What do you think is my favorite fruit? : ") if not fruit.isascii(): print("Please enter in English.") continue if fruit != "apple": guess += 1 print("Thats not it!") else: print(f"You got it! You missed {guess}.") break とりあえず果物当てゲームを実装することを優先して考えると、上記のguessing_game.pyでも問題ないのですが、このプログラムでは「flexibility(柔軟性)」と「scalability(拡張性)」を満たしてはいません。具体的には、このゲームに新しく「5回以上間違えたらヒントを与える」というような機能を追加しようとしたときはどうでしょうか。上のコード例では、どこをどのように書き換え、新しいコードを追加するべきか一目では分かりにくいと思います。これがオブジェクト指向プログラミングを用いずに開発されたソフトウェアの問題です。では次にオブジェクト指向プログラミングを用いて、同じゲームを実装してみましょう。 オブジェクト指向あり object_oriented.py class GuessFruit: def __init__(self, fruit): self.fruit = fruit self.guess = 0 def valid_fruit(self, en_fruit): if en_fruit.isascii(): return en_fruit else: return False def get_guess(self): fruit_guessed = input("What do you think is my favorite fruit? : ") if self.valid_fruit(fruit_guessed): return fruit_guessed else: print("Please enter in English.") return self.get_guess() def play(self): while True: answer = self.get_guess() if answer != self.fruit: self.guess += 1 print("Thats not it!") else: break print(f"You got it! You missed {self.guess}.") game = GuessFruit("apple") game.play() コード量自体は、オブジェクト指向を用いない場合と比較して長くなってしまいますが、機能ごとに関数が定義されているので、どこに何が書かれているのかが分かりやすいと思います。加えて先ほどの課題であった新しく「5回以上間違えたらヒントを与える」機能の追加も、オブジェクト指向の考えを用いた上記のコード例では容易なはずです。新しい機能を追加したいのなら、新しい関数を定義してしまえば良いのです。 新機能を追加 object_oriented_2.py class GuessFruit: # 追加 def __init__(self, fruit, h_words, h_criteria=5): self.fruit = fruit self.guess = 0 self.h_words = h_words self.h_criteria = h_criteria def valid_fruit(self, en_fruit): if en_fruit.isascii(): return en_fruit else: return False def get_guess(self): fruit_guessed = input("What do you think is my favorite fruit? : ") if self.valid_fruit(fruit_guessed): return fruit_guessed else: print("Please enter in English.") return self.get_guess() # 追加 def give_hint(self): if self.guess >= self.h_criteria: return self.h_words else: return False def play(self): while True: answer = self.get_guess() if answer != self.fruit: self.guess += 1 print("Thats not it!") # 追加 if self.give_hint(): print(f"Hint: {self.h_words} / Think again!") else: break print(f"You got it! You missed {self.guess}.") game = GuessFruit("apple", "The fruit's color is red.") game.play() このようにクラスの中に新しい関数を作成するだけで、機能を追加することができます。またオブジェクト指向プログラミングのポイントは、どのデータを外部から扱えるようにするかです。今回の例で考えれば、ゲームによっては「正解の果物の名前」、「ヒントの文」、「何回間違えたらヒントを与えるか」などのデータを変更したい場合も考えられるため、インスタンス化をする際に自由に値を決められるようにどのデータを引数として設定するかもポイントです。以上のようにオブジェクト指向プログラミングを用いて実装することで、コードを条件ごとに書き換える必要はなく、インスタンス化時に引数を指定してあげるだけで、多様な条件を持つプログラムを開発することができます。 まとめ 実例を通して示した通り、オブジェクト指向プログラミングは非常に有用な開発手法です。加えて、クラスを最小単位としてプログラムを設計する方法論とも呼ばれるように、大規模なプロジェクトになるほど真価を発揮する開発手法でもあります。プロジェクトが大規模になればなるほどクラスの数は増えて、パッケージ、ライブラリのように複雑化していきます。ただオブジェクト指向プログラミングを用いて実装されたソフトウェアは分解していくと最後は必ずクラスに辿り着きます。クラスに辿り着けば、誰であっても読みやすく、機能が追加しやすく、修正しやすいようなプログラムを見ることができるため、プロジェクトが大規模化、複雑化しても理解に苦しむことは少なくなります。 おわりに ここまで読んでいただきありがとうございます。私がオブジェクト指向プログラミングに関して調べ、感じたことをそのまま書いているので、一部誤りがある可能性もあります。誤字、修正すべき箇所がありましたら、お手数ですがコメント等でご連絡していただければと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Databricks Connect: アプリケーション、マイクロサービスにApache Spark™の機能を

Databricks Connect: Bringing the capabilities of hosted Apache Spark™ to applications and microservices - The Databricks Blogの翻訳です。 この記事では、あらゆるノートブックIDEやカスタムアプリケーションからネイティブのApache Spark APIを利用できる新たなライブラリであるDatabricks Connectをご紹介します。 概要 過去数年にわたって、Apache Spark向けに多くのカスタムアプリケーションコネクターが開発されました。これには、spark-submitやRESTジョブサーバー、ノートブックゲートウェイなどのツールが含まれます。これらには以下のような制限がありました。 これらは様々なケースに対応できるものではありませんでした:多くは特定のIDEやノートブック向けのものでした。 お使いのアプリケーションをSparkクラスターで実行する必要がありました。 Sparkの上に別のプログラミングインタフェースを統合する必要がありました。 クラスターを再起動することなしに、ライブラリの依存関係を変更することができませんでした。 これを、単純にライブラリウィインポートしてサーバーにアクセスする、SQLデータベースサービスへの接続方法を比較してみましょう。 Python import pymysql conn = pymysql.connect(<connection_conf>) conn.execute("SELECT date, product FROM sales") Sparkの構造化データAPIで同様のことを行う場合には、以下のようになります。 Python from pyspark.sql import SparkSession spark = SparkSession.builder.config(<connection_conf>).getOrCreate() spark.table("sales").selectExpr("date", "product").show() しかし、Databricks Connect以前では、上記のスニペットはシングルノードのSparkクラスターでのみ動作し、複数ノードへの容易なスケーリングや、spark-submitのような追加のツールなしにはクラウドにスケーリングすることができませんでした。 Databricks Connectクライアント Databricks Connectは普遍的なSparkライブラリを提供することで、このSparkコネクターのストーリーを完結させます。これによって、ノートブックのアプリケーション (例:Jupyter、Zeppelin、CoLab)、IDE(例:Eclipse、PyCharm、Intellij、RStudio)、カスタムのPython / JavaアプリケーションからSparkジョブを実行できます。 このことは、あなたはどこからでも"import pyspark"や"import org.apache.spark"を実行でき、Databricksクラスターに対してシームレスに大規模ジョブを実行できることを意味します。例として、Databricks Connectを用いてCoLabノートブックからSparkジョブをリモートで実行する様子をお見せします。ここでは、アプリケーション固有のインテグレーションが不要であることに注意してください。単にdatabricks-connectライブラリをインストールしてインポートするだけです。また、ここではGCPからS3のデータセットを読み込んでいますが、SparkクラスターがAWSにホストされているので実現可能となっています。 Databricks Connectから起動されたジョブは、分散処理を活用し、Databricks Spark UIでモニタリングできるように、リモートでDatabricksクラスター上で実行されます。 カスタマーユースケース 現時点(2019/6)で数百以上のお客様がアクティブにDatabricks Connectを利用しています。特筆すべきユースケースには以下のようなものがあります。 開発およびCI/CD Databricksクラスターを利用しつつも、ローカルのIDEでコードをデバッグ。 運用環境におけるCI/CDパイプラインにおいて、Sparkアプリケーションをテスト。 インタラクティブな分析 慣れ親しんでいるシェル(Jupyter、bash)やスタジオ環境(RStudio)を使いつつも、Databricksクラスターで処理を行えるように、多くのユーザーがDatabricks Connectを活用。 アプリケーション開発 ヘルスケア業界の大手のお客様は、インタラクティブなユーザークエリーを提供するPythonベースのマイクロサービスをデプロイするためにDatabricks Connectを使用。クエリーサービスは、1日あたり数千のクエリーに対応するために、リモートで複数のDatabricksクラスター上でSparkジョブを実行、このためにDatabricks Connectライブラリを使用。 Databricks Connectの動作原理 普遍的なクライアントライブラリを作るためには、以下の要件を満たす必要がありました。 アプリケーション観点では、クライアントライブラリは完全なSparkとして動作(例:SQL、データフレームなどを利用できること)する必要があります。 物理計画や実行などのヘビーウェイトなオペレーションはクラウド上のサーバーで実行されるべきです。さもないと、クライアントがクラスターに近い場所になく、広域ネットワーク越しにデータを読み込む際に多大なるオーバーヘッドを引き起こすことになります。 これらの要件に適合するために、アプリケーションがSpark APIを利用する際には、Databricks Connectライブラリは、Sparkと全く同じように分析フェーズに至るジョブの計画を実行します(要件1)。ジョブの実行準備が整った際には、Databricks Connectは論理的クエリープランを、実際の物理的処理実行とIOが発生するサーバーに送信します(要件2)。 図1. Databricks ConnectはSparkジョブのライフタイムを、論理的分析までを含むクライアントフェーズ、リモートクラスターにおける処理実行を含むサーバーフェーズに分割します。 Databricks Connectクライアントは、様々なユースケースに対応できるように設計されています。プラットフォームのAPIトークンを通じて分かりやすい認証、承認ができるように、REST経由でサーバーと通信を行います。セキュアかつ同時実行性の高い共有クラスターにおいても、複数ユーザーのセッションは分離されます。高いパフォーマンスを実現するために結果は効率的なバイナリーフォーマットで返却されます。使用されるプロトコルはステートレスなので、対障害性のあるアプリケーションを容易に構築でき、クラスターが再起動されたとしても作業状態を失うことはありません。 利用方法 Databricks ConnectはDBR 5.4のリリースからGAとなっており、Python、Scala、Java、Rをサポートしています。"pip install databricks-connect"を実行することで、すべての言語に対するライブラリをPyPIから取得できます。Databricks Connectのドキュメントにはこちらからアクセスできます。 Databricks 無料トライアル Databricks 無料トライアル
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DjangoでWebアプリ開発環境の構築(その②)

はじめに Webシステム開発をPythonでするために、新たにDjangoを学んでいる。 前回の記事では、インストールや起動の仕方など簡単なところをまとめたので、今回はその続きとして素材ファイルの配置やDB連携などについてまとめておく。 実行環境 【ローカルPC環境-OS】   ・Windows 10 Pro  【ソフト・パッケージ情報】   ・Python3.9系 + Django3.2 手順 前提として、【DjangoでWebアプリ開発環境の構築(その①)】の記事より、以下を完了していること。 仮想環境を作成してDjangoをインストール Djangoの起動 サンプルアプリの起動 本記事では、以下の使い方を整理する。 1.STATICファイルの配置 2.DB連携 3.管理者画面からのDB操作 1.STATICファイルの配置 CSSやイメージファイルなどを配置しておく場所と、そのファイルなどの呼び出し方 上位の【プロジェクト名】フォルダの直下に、以下の様にフォルダを作成し、適当なjpgファイルを格納 manage.py 【プロジェクト名】フォルダ 【test_app】フォルダ  ※python manage.py startapp で作成した任意なアプリ名 【temp】フォルダ 【static_files】 ← 今回作成したフォルダ 【images】 ← 今回作成したフォルダ sample_image.jpg ← 今回適当に置いたファイル [プロジェクト名]\settings.py # 省略-------------------------- # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent TEMP_DIR = os.path.join(BASE_DIR, 'temp')) STATIC_DIR = os.path.join(BASE_DIR, 'static_files')) # 前回記事(その①)からの追記部分 # 省略--------------------------- STATIC_URL = '/static/' STATICFILES_DIRS = [ # 前回記事(その①)からの追記部分 STATIC_DIR, ] アクセス確認  python manage.py runserverでDjangoを起動後、ブラウザで以下のURLにアクセスして画像が表示されればOK。   ・http://localhost:8000/static/images/sample_image.jpg 試しにindex.htmlに埋め込み tempフォルダのindex.html に以下の様に追記。 index.html <!DOCTYPE html> {% load static %} <!-- 前回記事(その①)からの追記部分 --> <html> <head> <meta charset="utf-8"> <title>テストタイトル</title> </head> <body> <h1>見出し1</h1> {{ temp_str }} <br> <img src="{% static "images/sample_image.jpg" %}" alt="イマージファイルが存在しません!"> <!-- 前回記事(その①)からの追記部分 --> </body> </html> アクセス確認  python manage.py runserverでDjangoを起動後、ブラウザで以下のURLにアクセスして画像が表示されればOK。   ・http://localhost:8000/    ※画像へのパスが間違っている場合、altに設定の値が表示される。 CSSなどの場合も同様に、以下の流れでできる。  ・static_filesの直下にcssフォルダを作成  ・cssフォルダ内に適当なcssファイルを作成  ・index.html に以下の様な行を追記。    <link rel="stylesheet" href="{% static "css/【イメージファイル名】" %}"> 2.DB連携 DjangoでDBとの連携を試したい場合、デフォルトではPythonに標準で組み込まれているSQLiteが設定されている。 接続先DBを別のものに切り替える設定は後述するとして、SQLiteを使ったDB連携を試してみる。 【アプリ名】/models.pyを編集する。  ※DBの設計を models.py で行っているイメージ。 test_app/models.py from django.db import models # Create your models here. class Member(models.Model): member_name = models.CharField(max_length=256, verbose_name="ユーザーリスト", unique=True) sex = models.CharField(max_length=1) def __str__(self): return self.member_name class SiteAccessCount(models.Model): site = models.URLField(unique=True) count = models.IntegerField() date = models.DateField() def __str__(self): return str(self.date) # DATE型なのでキャストしている。 class Bloginfo(models.Model): blog_id = models.IntegerField() blog_title = models.CharField(max_length=256) name = models.ForeignKey(Member, on_delete=models.CASCADE) url = models.ForeignKey(SiteAccessCount, on_delete=models.CASCADE) def __str__(self): return self.blog_title SQLに置き換えて考えると、以下の様なイメージで良さそう。  class ⇒ テーブル  class内の変数 ⇒ テーブル内のカラム定義  class内のdef _str_ ⇒ テーブルを参照した時の返り値(別のテーブルから参照したい場合、分かりやすくなる) Modelsの使い方はこちらの記事が参考になった。  https://qiita.com/kotayanagi/items/3cfadae951c407ac044a DBのマイグレーション python manage.py makemigrations temp_app コマンドより、モデルの移行情報を作成する。 ⇒ <【アプリ名】/migrations/> 内に作成される。 python manage.py migrate コマンドより、上記のモデル以降情報を元にDBモデルを構築する ⇒ 初回の場合 db.sqlite3 というファイルができる。ここにテーブル設定やデータが格納されていると想定。  ※djangoのマイグレーションについて補足   https://note.crohaco.net/2018/django-migration/   https://hodalog.com/how-to-reset-migrations/ adminサイトにDBモデルの登録 test_app/admin.py from django.contrib import admin # 以下追記部分 from first_app.models import Member, SiteAccessCount, Bloginfo # Register your models here. admin.site.register(Member) admin.site.register(SiteAccessCount) admin.site.register(Bloginfo) adminサイトに入るためのスーパーユーザー作成 python manage.py createsuperuser その後、ユーザー名、Email、パスワードなどを対話式に設定する。 python manage.py runserver で再度起動した状態で、ブラウザで下記のURLに接続して認証を通過できればOK!  ・http://localhost:8000/admin 3.管理者画面からのDB操作 管理者画面からテーブルをいじってみる。 試しに Memberテーブル にユーザーを追加してみる。 上記の様な感じで、GUIベースで色々と操作ができる。 上の段の Groups と Users はDBのアカウントやグループ。 管理者画面に入れるアカウントを増やす場合などは、ここに追加する感じ。 <おまけ> DB連携先の切り替え設定 今回の記事ではデフォルト設定のSQLiteを使ったが、連携先のDBを変える場合は、setting.pyを以下の様に編集する。  ※下記の設定は、事前にローカルにPostgreSQLを入れてDBを作成している   [プロジェクト名]\settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'DB_NAME', 'USER': 'USER_NAME', 'PASSWORD': 'PASSWORD', 'HOST': 'localhost', 'PORT': 'ポート番号', } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ニューラルネットワークの初歩について学習

今回の記事では、ニューラルネットワークについて、Udemyの講座にて学習した内容を要約する。なお、本記事に掲載しているコードは、すべて下記URLに掲載しているUdemy講座から抜粋している Udemy講座URL みんなのAI講座 ゼロからPythonで学ぶ人工知能と機械学習 【2021年最新版】 目次 1.ニューラルネットワークの概要 2.単純ニューロンの実装 3.外部データの導入 4.ニューラルネットワークの実装 1-ニューラルネットワークの概要 ニューロン(神経細胞)を模したネットワーク (人工)ニューロン:複数の入力データをニューロンで変換し、出力する 各入力データとそれぞれの重みで積和演算を行う 求めた値に対して更にバイアス値を追加する 合計値を活性化関数で変換する ニューラルネットワーク:複数の単純ニューロンの組み合わせ 2-単純ニューロンの実装 入力:[1.0, 2.0 ,3.0]のリストを用意する 重み:[1.5, 0.75, -1.0] バイアス : 1.0 活性化関数 : シグモイド関数を使用 出力データを0~1の範囲に変換する シグモイド関数については前回の記事にて記載 シグモイド関数は2値分類を行う際に使用される 多値分類を行う際はソフトマックス関数が使用されることが多い 各クラスのinitメソッド インスタンスを生成する際に自動で実行される。 neural_network = NeuralNetwork() の行の実行時にインスタンスを生成する #ニューロン class Neuron: def __init__(self): # 初期設定 self.input_sum = 0.0 # 入力データ合計値格納用変数 self.output = 0.0 # 出力用変数 def set_input(self, inp): # 入力データを足し合わせる self.input_sum += inp print("Input_sum : " + str(self.input_sum)) # デバッグ用 def get_output(self): self.output = sigmoid(self.input_sum) #入力データの合計値を活性化関数を用いて変換 return self.output # ニューラルネットワーク class NeuralNetwork: def __init__(self): # 初期設定 self.neuron = Neuron() # ニューロンのインスタンス self.w = [1.5, 0.75, -1.0] # 重み self.bias = 1.0 # バイアス def commit(self, input_data): # 実行 self.neuron.set_input(input_data[0] * self.w[0]) self.neuron.set_input(input_data[1] * self.w[1]) self.neuron.set_input(input_data[2] * self.w[2]) self.neuron.set_input(self.bias) return self.neuron.get_output() # ニューラルネットワークのインスタンス neural_network = NeuralNetwork() # 実行 input_data = [1.0, 2.0 ,3.0] print("Output : " + str(neural_network.commit(input_data))) 出力結果は下記の通り Input_sum : 1.5 Input_sum : 3.0 Input_sum : 0.0 Input_sum : 1.0 Output : 0.7310585786300049 3-外部データの導入 3.1 外部データの確認 今回は Iris dataset を導入する 3品種、各50個の花のデータで構成 0: Setosa 1: Versicolor 2: Versinica 4つの測定値 Sepal length(cm) Sepal width(cm) Petal length(cm) Petal width(cm) scikit-learn ライブラリから Iris dataset を導入 以下のコードで Iris dataset の中身を確認 import numpy as np import matplotlib.pyplot as plt from sklearn import datasets # Irisデータの読み込み iris = datasets.load_iris() # 各花のサイズ iris_data = iris.data print(iris_data.shape) # 形状 print(iris_data) 実行結果から、50 × 3品種 のデータを確認できる (150, 4) [[5.1 3.5 1.4 0.2] [4.9 3. 1.4 0.2] [4.7 3.2 1.3 0.2] *****省略******** [6.3 2.5 5. 1.9] [6.5 3. 5.2 2. ] [6.2 3.4 5.4 2.3] [5.9 3. 5.1 1.8]] 散布図でSepal のデータを確認する # Setosa st_data = iris_data[:50] # Versicolor vc_data = iris_data[50:100] # Versinica vn_data = iris_data[100:150] # Setosa Sepal length(cm)・Sepal width(cm) plt.scatter(st_data[:,0],st_data[:,1],label="Setosa") # Versicolor Sepal length(cm)・Sepal width(cm) plt.scatter(vc_data[:,0],vc_data[:,1],label="Versicolor") # Versinica Sepal length(cm)・Sepal width(cm) plt.scatter(vn_data[:,0],vn_data[:,1],label="Versinica") plt.legend() plt.xlabel("Sepal length(cm)") plt.ylabel("Sepal width(cm)") plt.show() 出力された散布図から、Setosaとその他2品種には明確な境界線が確認できる 同様にPetal のデータを散布図で確認する 3.2 単一ニューロンの実装 今回はSetosaとVersicolorをSepal length/width のデータを用いて分類する SetosaとVersicolor の2種類の分類を行う理由は、活性化関数としてシグモイド関数を用いているため 以下のコードで入力データを作成している 入力データの平均値を0に設定する ニューラルネットワークの入力が偏ると、学習が進まない、あるいは学習に時間がかかるリスクがある 偏りをなくすために平均値を0にする。 import numpy as np import matplotlib.pyplot as plt from sklearn import datasets iris = datasets.load_iris() iris_data = iris.data sl_data = iris_data[:100, 0] # SetosaとVersicolor、Sepal length sw_data = iris_data[:100, 1] # SetosaとVersicolor、Sepal width # 平均値を0に sl_ave = np.average(sl_data) # Sepal length 平均値 sl_data -= sl_ave # Sepal length 平均値を引く sw_ave = np.average(sw_data) # Sepal width 平均値 sw_data -= sw_ave # Sepal width 平均値を引く # 入力をリストに格納 input_data = [] for i in range(100): input_data.append([sl_data[i], sw_data[i]]) 単一ニューロン実装は以前の章にて説明済 入力データが Sepal length と Sepal width の2次元のため、以下の変更が必要 ニューラルネットワーククラスの初期設定時の重み ニューラルネットワーククラスのcommitのset_inputの回数 入力データが Setosa と Versicolor で合計100個あるため、入力データ・出力データそれぞれリセットする機能が必要 リセット機能を追加しなければ前回の結果が残ったまま足し合わせてしまう。 リセットをコメントアウトすると総和が極端な値になり、いつも同じ分類結果になってしまう。 # ニューラルネットワーク class NeuralNetwork: def __init__(self): # 初期設定 self.neuron = Neuron() # ニューロンのインスタンス self.w = [0.5, -0.2] # 重み self.bias = 0.0 # バイアス def commit(self, input_data): # 実行 self.neuron.reset() # input_sum と output をリセット self.neuron.set_input(input_data[0] * self.w[0]) # Sepal length self.neuron.set_input(input_data[1] * self.w[1]) # Sepal width self.neuron.set_input(self.bias) return self.neuron.get_output() 出力結果が0.5を閾値として、SetosaとVersicolorを予測する シグモイド関数の出力の範囲は0~1であり、中央値である0.5を閾値として設定する 0.5を閾値とすることにより50%ずつ等確率の2クラス分類ができる # 実行 st_predicted = [[], []] # Setosa x軸:length y軸:width vc_predicted = [[], []] # Versicolor x軸:length y軸:width for data in input_data: predict_result = neural_network.commit(data) print("Output : " + str(predict_result)) # デバッグ用 if predict_result < 0.5: st_predicted[0].append(data[0]+sl_ave) st_predicted[1].append(data[1]+sw_ave) else: vc_predicted[0].append(data[0]+sl_ave) vc_predicted[1].append(data[1]+sw_ave) 散布図で予測結果(predict)を元のデータ(Original)と比較する 4-ニューラルネットワークの実装 前章で使用した Iris dataset を用いてニューラルネットワークを実装する 入力層:2 中間層:2 出力層:1 ニューラルネットワーククラスの変更が必要 # ニューラルネットワーク class NeuralNetwork: def __init__(self): # 初期設定 self.w_im = [[4.0, 4.0], [4.0, 4.0]] # 入力層-中間層 入力:2、ニューロン:2 self.w_mo = [[1.0, -1.0]] # 中間層-出力層 入力:2、ニューロン:1 # バイアス self.b_m = [2.0,-2.0] # 入力層-中間層 ニューロン数:2 self.b_o = [-0.5] # 中間層-出力層 ニューロン数:1 # 各層の宣言 self.input_layer = [0.0, 0.0] # 入力層 self.middle_layer = [Neuron(), Neuron()] # 中間層 self.output_layer = [Neuron()] # 出力層 def commit(self, input_data): # 実行 # 各層のリセット self.input_layer[0] = input_data[0] # 入力層は値を受け取るのみ self.input_layer[1] = input_data[1] self.middle_layer[0].reset() self.middle_layer[1].reset() self.output_layer[0].reset() # 入力層(2)→中間層(2) self.middle_layer[0].set_input(self.input_layer[0] * self.w_im[0][0]) # Sepal length self.middle_layer[0].set_input(self.input_layer[1] * self.w_im[0][1]) # Sepal width self.middle_layer[0].set_input(self.b_m[0]) self.middle_layer[1].set_input(self.input_layer[0] * self.w_im[1][0]) # Sepal length self.middle_layer[1].set_input(self.input_layer[1] * self.w_im[1][1]) # Sepal width self.middle_layer[1].set_input(self.b_m[1]) #中間層(2)→出力層(1) self.output_layer[0].set_input(self.middle_layer[0].get_output() * self.w_mo[0][0]) self.output_layer[0].set_input(self.middle_layer[1].get_output() * self.w_mo[0][1]) self.output_layer[0].set_input(self.b_o[0]) return self.output_layer[0].get_output() また、中間層を3つに増やした場合、表現力が上がっていることが確認できる ただしOriginalと比較して予測精度が上がったとは言えない その場合、重みやバイアスを見直す必要がある 参考文献 みんなのAI講座 ゼロからPythonで学ぶ人工知能と機械学習 【2021年最新版】
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む