RでProject Euler(随時更新)
Project Eulerはプログラムで解く数学の問題集です。
https://projecteuler.net/about
(日本語訳→http://odz.sakura.ne.jp/projecteuler/)
頭の体操のためにR言語でProject Eulerを解いていきます。
縛りは、基本のbaseパッケージのみとします。
低頻度ですが、随時更新していきます。
pandasのSeriesよりDataFrameの方が保存サイズが小さくなる
1列のpandasのデータをpickleで保存する場合。
そのとき、なぜかSeriesで保存するよりDataFrameで保存した方がサイズが小さくなることを確認した。
ちょっと条件いろいろ試して実験しメモ。
続きを読む新しい活性化関数「Mish」を使ってみた。
kerasのoptimizerの状態を保存する
背景
新規データに対して逐次的に毎日学習するkerasのモデルを考える。
シンプルなモデルであればmodel.save()とload_model()を使えばなんの問題もない。
参考: Kerasのノウハウ覚え書き
しかし、Lambda層が入るとmodel.save()ができなくなる。
参考: KerasのLambda層でreshapeしたとき、保存に失敗する(場合がある)話
追加の学習はせず予測のためだけに使うモデルなら、save_weights()とかで重みだけ保存しておけばよいが、毎日新規データを学習したいため微妙。
というのは、optimizerがmomentumなどの状態を持っている場合、それも保存しておかなければならない。
以下の記事を参考に、optimizerの状態の保存と読み込みを行って、各種実験をしてみる。
参考: python - Save and load model optimizer state - Stack Overflow
実験
準備
必要なライブラリのインポート
from sklearn import datasets from sklearn import preprocessing from keras.models import Model from keras.layers import Input, Dense from keras.utils import np_utils from keras.optimizers import SGD from keras import backend as K
データの準備
iris = datasets.load_iris() X = iris.data Y = iris.target X = preprocessing.scale(X) Y = np_utils.to_categorical(Y)
モデルを作ってコンパイルする関数
def make_model(momentum=0.0, decay=0.0, nesterov=False): inputs = Input(shape=(4,)) outputs = Dense(3, activation="softmax", kernel_initializer="ones", bias_initializer="ones", name="output_layer")(inputs) model = Model(inputs=inputs, outputs=outputs) model.compile(optimizer=SGD(lr=0.01, momentum=momentum, decay=decay, nesterov=nesterov), loss='categorical_crossentropy') return model
実験1
optimizerの状態がない場合の学習。
model = make_model() model.fit(X, Y, epochs=10, verbose=2, batch_size=200)
- 0s - loss: 1.0986 Epoch 2/10 - 0s - loss: 1.0890 Epoch 3/10 - 0s - loss: 1.0796 Epoch 4/10 - 0s - loss: 1.0704 Epoch 5/10 - 0s - loss: 1.0613 Epoch 6/10 - 0s - loss: 1.0524 Epoch 7/10 - 0s - loss: 1.0437 Epoch 8/10 - 0s - loss: 1.0351 Epoch 9/10 - 0s - loss: 1.0267 Epoch 10/10 - 0s - loss: 1.0185
実験2
optimizerの状態がない場合の学習。
epochs=1の学習をfor文で回す。
実験1と同じ結果。
model = make_model() for i in range(10): model.fit(X, Y, epochs=1, verbose=2, batch_size=200)
Epoch 1/1 - 0s - loss: 1.0986 Epoch 1/1 - 0s - loss: 1.0890 Epoch 1/1 - 0s - loss: 1.0796 Epoch 1/1 - 0s - loss: 1.0704 Epoch 1/1 - 0s - loss: 1.0613 Epoch 1/1 - 0s - loss: 1.0524 Epoch 1/1 - 0s - loss: 1.0437 Epoch 1/1 - 0s - loss: 1.0351 Epoch 1/1 - 0s - loss: 1.0267 Epoch 1/1 - 0s - loss: 1.0185
実験3
optimizerの状態がある場合の学習。
model = make_model(momentum=1, decay=1, nesterov=True) model.fit(X, Y, epochs=10, verbose=2, batch_size=200)
Epoch 1/10 - 0s - loss: 1.0986 Epoch 2/10 - 0s - loss: 1.0795 Epoch 3/10 - 0s - loss: 1.0610 Epoch 4/10 - 0s - loss: 1.0414 Epoch 5/10 - 0s - loss: 1.0209 Epoch 6/10 - 0s - loss: 0.9997 Epoch 7/10 - 0s - loss: 0.9781 Epoch 8/10 - 0s - loss: 0.9563 Epoch 9/10 - 0s - loss: 0.9343 Epoch 10/10 - 0s - loss: 0.9125
実験4
optimizerの状態がある場合の学習。
epochs=1の学習をfor文で回す。
実験3と同じ結果。
modelがoptimizerの状態を保持している。
model = make_model(momentum=1, decay=1, nesterov=True) for i in range(10): model.fit(X, Y, epochs=1, verbose=2, batch_size=200)
Epoch 1/1 - 0s - loss: 1.0986 Epoch 1/1 - 0s - loss: 1.0795 Epoch 1/1 - 0s - loss: 1.0610 Epoch 1/1 - 0s - loss: 1.0414 Epoch 1/1 - 0s - loss: 1.0209 Epoch 1/1 - 0s - loss: 0.9997 Epoch 1/1 - 0s - loss: 0.9781 Epoch 1/1 - 0s - loss: 0.9563 Epoch 1/1 - 0s - loss: 0.9343 Epoch 1/1 - 0s - loss: 0.9125
実験5
optimizerの状態がない場合の学習。
モデルの作成と学習を繰り返す。
lossが変化しない。
for i in range(10): model = make_model() model.fit(X, Y, epochs=1, verbose=2, batch_size=200)
Epoch 1/1 - 0s - loss: 1.0986 Epoch 1/1 - 0s - loss: 1.0986 Epoch 1/1 - 0s - loss: 1.0986 Epoch 1/1 - 0s - loss: 1.0986 Epoch 1/1 - 0s - loss: 1.0986 Epoch 1/1 - 0s - loss: 1.0986 Epoch 1/1 - 1s - loss: 1.0986 Epoch 1/1 - 1s - loss: 1.0986 Epoch 1/1 - 1s - loss: 1.0986 Epoch 1/1 - 1s - loss: 1.0986
実験6
optimizerの状態がある場合の学習。
モデルの作成と学習を繰り返す。
実験5と同様にlossが変化しない。
for i in range(10): model = make_model(momentum=1, decay=1, nesterov=True) model.fit(X, Y, epochs=1, verbose=2, batch_size=200)
Epoch 1/1 - 1s - loss: 1.0986 Epoch 1/1 - 1s - loss: 1.0986 Epoch 1/1 - 1s - loss: 1.0986 Epoch 1/1 - 1s - loss: 1.0986 Epoch 1/1 - 1s - loss: 1.0986 Epoch 1/1 - 1s - loss: 1.0986 Epoch 1/1 - 1s - loss: 1.0986 Epoch 1/1 - 1s - loss: 1.0986 Epoch 1/1 - 1s - loss: 1.0986 Epoch 1/1 - 1s - loss: 1.0986
実験7
optimizerの状態がない場合の学習。
モデルの作成と学習を繰り返す。
モデル作成後に重みを読み込む。
実験1や実験2と同じ結果。
for i in range(10): model = make_model() if i != 0: model.get_layer("output_layer").set_weights(weights_dense) model.fit(X, Y, epochs=1, verbose=2, batch_size=200) weights_dense = model.get_layer("output_layer").get_weights()
Epoch 1/1 - 1s - loss: 1.0986 Epoch 1/1 - 1s - loss: 1.0890 Epoch 1/1 - 1s - loss: 1.0796 Epoch 1/1 - 1s - loss: 1.0704 Epoch 1/1 - 1s - loss: 1.0613 Epoch 1/1 - 1s - loss: 1.0524 Epoch 1/1 - 1s - loss: 1.0437 Epoch 1/1 - 1s - loss: 1.0351 Epoch 1/1 - 2s - loss: 1.0267 Epoch 1/1 - 2s - loss: 1.0185
実験8
optimizerの状態がある場合の学習。
モデルの作成と学習を繰り返す。
モデル作成後に重みを読み込む。
optimizerの状態の違いのため、実験3や実験4と異なる結果。
for i in range(10): model = make_model(momentum=1, decay=1, nesterov=True) if i != 0: model.get_layer("output_layer").set_weights(weights_dense) model.fit(X, Y, epochs=1, verbose=2, batch_size=200) weights_dense = model.get_layer("output_layer").get_weights()
Epoch 1/1 - 2s - loss: 1.0986 Epoch 1/1 - 2s - loss: 1.0795 Epoch 1/1 - 2s - loss: 1.0703 Epoch 1/1 - 2s - loss: 1.0612 Epoch 1/1 - 2s - loss: 1.0523 Epoch 1/1 - 2s - loss: 1.0350 Epoch 1/1 - 2s - loss: 1.0266 Epoch 1/1 - 2s - loss: 1.0183 Epoch 1/1 - 2s - loss: 1.0102 Epoch 1/1 - 2s - loss: 1.0023
実験9
optimizerの状態がある場合の学習。
モデルの作成と学習を繰り返す。
モデル作成後に重みとoptimizerの状態を読み込む。
実験3や実験4と同じ結果。
for i in range(10): model = make_model(momentum=1, decay=1, nesterov=True) model._make_train_function() if i != 0: model.get_layer("output_layer").set_weights(weights_dense) model.optimizer.set_weights(weights_optimizer) model.fit(X, Y, epochs=1, verbose=2, batch_size=200) weights_dense = model.get_layer("output_layer").get_weights() weights_optimizer = model.optimizer.get_weights()
Epoch 1/1 - 2s - loss: 1.0986 Epoch 1/1 - 0s - loss: 1.0795 Epoch 1/1 - 0s - loss: 1.0610 Epoch 1/1 - 0s - loss: 1.0414 Epoch 1/1 - 0s - loss: 1.0209 Epoch 1/1 - 0s - loss: 0.9997 Epoch 1/1 - 0s - loss: 0.9781 Epoch 1/1 - 0s - loss: 0.9563 Epoch 1/1 - 0s - loss: 0.9343 Epoch 1/1 - 0s - loss: 0.9125
まとめ
model.save()が使える場合
->model.save()を使えば良い。model.save()が使えない場合- 再学習しない場合
-> モデルの重みのみ保存すれば良い。 - 再学習する必要がある場合
-> モデルの重みとoptimizerの状態を保存すれば良い。
- 再学習しない場合
ちなみに、weights_denseとweights_optimizerの中身は以下。
weights_dense
[array([[0.9180371 , 1.00887 , 1.0730928 ],
[1.0696087 , 0.94541067, 0.9849805 ],
[0.8941715 , 1.0231149 , 1.0827136 ],
[0.8982664 , 1.0132247 , 1.0885084 ]], dtype=float32),
array([0.9999076, 1.000105 , 0.9999874], dtype=float32)]
weights_optimizer
[10, array([[-0.00934379, 0.00099744, 0.00834635],
[ 0.00797938, -0.0062994 , -0.00167998],
[-0.01209093, 0.00263835, 0.00945257],
[-0.01162081, 0.00148986, 0.01013095]], dtype=float32),
array([-2.1416694e-05, 2.4464378e-05, -3.0475137e-06], dtype=float32)]
なので、pickleとかで保存すれば良い。
model._make_train_function()は何をしているかわからない。
けど、それがないとmodel.optimizer.set_weights(weights_optimizer)でエラーになる。
競艇や競馬の買い目最適化(ケリー基準の一般化)
問題設定
特定のレースの特定の券種で、確定オッズ(以下オッズ)と的中確率は所与とします。
そのうち、期待値がを超える券が
枚あるとします。
枚の券のうち、
番目の券の、オッズを
、的中確率を
とします。
それぞれの券の期待値がを超えるので、
です。
さて、このときそれぞれの券にいくらずつかけるのが最適ですか?という問題です。
ただし、何レースでも購入でき、オッズは低下せず、少数金額も購入できるとします。
(他にも条件あるかもしれませんが、このくらいで。)
最適化
番目の券を所持金の
倍購入するとします。
いま、枚の券はすべて同じ券種であるため、互いに排反な事象となります。なので、的中してもどれか1枚です。
(※券種は複勝や拡連複ではないとして、さらに同着や返還等も考えません。)
なので、レースが終わったときの結果の事象としては、
枚の券のうちどれか1枚が的中するか、全部外れるかです。
したがって、ケリー基準を導出する際と同様に考えて、
この関数を最大化します。
ただし、です。
また、の
は、あらゆる
の組み合わせ的な感じです。
なぜこの関数を最大化するのかは、上記参考サイトに任せますが、
イメージとしては、
枚全部外れる確率は
で、そのとき所持金は
倍になる。
番目の券が的中する確率は
で、そのとき所持金は
倍になる。
それらの期待値のような感じです。
掛け算や指数があれなので、最適化の常套手段である対数変換をします。
ベクトルで偏微分とか苦手なので、地道にいきます。
上式を、番目の券の購入割合
で偏微分してイコール
とおくことで、
となります。
ここで、第1項と第2項はによらず一定です。
なので、別の番目の券の購入割合
で偏微分した場合は、
第3項だけが変わるので、
が成り立ちます。
変形して、
となります。
この式により、偏微分した式の第2項の総和の中身のインデックスを
オッズの比をかけることで、変換できるようになります。
第2項の総和の中身のインデックスを
に変換します。
とおいて、さらに変形をつづけます。
上式はすべてのについて成り立ちます。
ここまでくるともう少しですね。
いま求めたいのは、ですけど、
線形になっているので、解けますね。
具体的には、
次元縦ベクトル
、
の行列
、
次元縦ベクトル
とすると、
が成り立ちますので、最適なは、
と求まりました。
の場合について考えて、ケリー基準と一致するか確認してみます。
のとき、
なので、
となります。
ここで、
なので、
となり、普通のケリー基準の式と一致します。
(参考サイトや一般的に紹介されているケリー基準と違うのはオッズの置き方によるもの。本質的には全く同じ。)
数値シミュレーション
求めた解が正しいか、数値シミュレーションで確認します。
現実ではありえないかもしれませんがで、
という状況を考えます。
期待値はそれぞれ順にとなります。
番目の券が一番期待値高いです。
番目と
番目の券は期待値同じです。
最適なを求めると、
となりました。
番目と
番目の券を比較すると期待値は同じですが、
確率は番目の券の方が高いため、購入金額の割合は大きいです。
番目の券が一番期待値高いですが、一番購入金額は低くなりました。
的中確率が小さいためですね。
では、この設定で5000レースシミュレーションしてみます。
また、最適なに、
定数を掛けた場合も同時に示します。


横軸はレース数、縦軸は所持金で対数グラフです。初期所持金はとしました。
どうやら、求めたものは正しかったようですね。
最適なより小さいと、資産の増え方は下がりばらつきが抑えられます。
一方最適なより大きいと、資産の増え方は下がりばらつきが増えます。
レース数が少ないとき、一時的に資産が最適なのときの資産を上回る可能性はありますが、長期的にみるといいことないですね。
なので、ハーフケリーとかの方法があるんですかね。
おわりに
今回は、的中確率とオッズが所与のときの買い目を最適化しました。
今後の課題としては、
- 複数種類の券種がある場合どうなるか
- 的中確率やオッズが確立変数として与えられたときどうなるか
です。気になります。
のちのち考えていきます。
Rコード
library(ggplot2) p=c(0.1,0.2,0.3) o=c(15,6,4) N=length(p) p0=1-sum(p) o0=1-sum(1/o) f=solve(matrix(p0-p*o*o0,ncol=N,nrow=N)-diag(N)*p0*o)%*%(p0-p*o*o0) p*o f R=5000 flg=sample(1:(N+1),R,prob=c(p,p0),replace=TRUE) ff=f data=data.frame(R=1:R,w=cumprod(c(1+ff*o-sum(ff),1-sum(ff))[flg])) g=ggplot()+geom_line(data=data,aes(x=R,y=w),color=2)+scale_y_log10() for(i in seq(0.2,0.8,by=0.2)){ ff=f*i data=data.frame(R=1:R,w=cumprod(c(1+ff*o-sum(ff),1-sum(ff))[flg])) g=g+geom_line(data=data,aes(x=R,y=w)) } g ff=f data=data.frame(R=1:R,w=cumprod(c(1+ff*o-sum(ff),1-sum(ff))[flg])) g=ggplot()+geom_line(data=data,aes(x=R,y=w),color=2)+scale_y_log10() for(i in seq(1.2,1.8,by=0.2)){ ff=f*i data=data.frame(R=1:R,w=cumprod(c(1+ff*o-sum(ff),1-sum(ff))[flg])) g=g+geom_line(data=data,aes(x=R,y=w)) } g
変なユニバーサル基板を作ってみた。
ブログを1年以上放置していました。
何かしら発信しようと思い、雑な記事ですけど投稿します。
これからちょっとずつ投稿しようと思います。
作ったもの

3方向に挿すことができる2.54mmピッチのユニバーサル基板です。
作ったといっても2年くらい前なのですが、画像が出てきましたので。
作ってみたものの、使ってみると使いにくくどうしようもなかったです。