python3 enumerateについて
pythonではリストの要素と要素番号を同時に取得することができます。
以下のようにします。
list = ['a', 'b', 'c'] for i, cont in enumerate(list): print(f'{i} : {cont}') # => 0 : a 1 : b 2 : c
enumerateを使わなくても実現できますが、使った方がスマートに書けますね!
python3 アンパックについて
皆さんアンパックってご存知ですか。僕は最近知りました。
アンパックとはリストや辞書を展開して、中身を取り出すことです。
アンパックによって以下のようなことができます。
- *によるリストのアンパック
def myprint(a, b, c): print(f'a={a} b={b} c={c}') list = [1, 2, 3] myprint(*list) # => a=1 b=2 c=3
このように、リストの中身を関数に渡すことができます。
辞書は以下のようにします。
2. **による辞書のアンパック
def myprint(a, b, c): print(f'a={a} b={b} c={c}') dict = {'a':1, 'c':3, 'b':2} myprint(**dict) # => a=1 b=2 c=3
結構使えそうですね!
効率的にプログラムを書くための思考
最近どうやったらもっと効率よくプログラムが書けるかを考えていました。ここで言う「効率がよい」とは、問題を解こうとしてから解くまでにかかる時間についてです。
結論から言いますと、「解きたい問題を、自分の能力で解ける問題に素早く分解すること」が重要だと考えました。
少し話を変えます。
自分の知らない分野の論文の理解が難しいのはなぜでしょう。それは著者が基礎知識を知っている人を対象に書いているからです。そうしないと、膨大な分量になってしまいますからね。
人は話すときもこのような「飛躍」をよく使っています。若い人と年配の人で話が通じないのはこれが一つの原因です。
今までの話は人同士のコミュニケーションでした。これを人と機械のコミュニケーションに置き換えてみましょう。
機械はプログラミング言語という言葉のネイティブスピーカーだと思ってください。
ある問題Aを解いてほしいとき、機械にどう伝えますか?
「A解いといて!」
これで伝わったら話は早いですね。でもこう返されるかもしれません。
「Aって何?」
上で述べたようにお互いが、ある情報を同じ意味として共有しているからこそ、話が通じるわけです。
ではこうしてみましょう。
「BをしてCをしたらAをしたことになるから、お願い!」
このようにすれば、機械がBとCを知っていれば、Aを実現できますね。しかし、このように言うためには人側もBとCを知っていなければなりません。
人側がBとCを知らなければ、このようにしないといけないかもしれません。
「1と2をするとBができるからよろしく。
あと3、4、5を順にすればCもできるよ。
それができたら、BとCでAを解いてね。」
長いからダメと思われるかもしれませんが、Aが解けたことに変わりないので僕は全く問題ないと考えます。問題はこの文章がすぐに思いつくかどうかです。
BとCを知っていれば、より早く思いつくかもしれませんね。
つまり、「解きたい問題を、自分の能力で解ける簡単な問題に素早く落とし込めるかどうか」がプログラムを書く効率に影響を与えるということです。
また、自分で解ける問題が多ければ多いほど、プログラムを書く効率は上がっていくでしょう。
まとめるとこのようになります。
・自分の能力を把握しておいて、その能力で解ける問題に素早く分解する。
・常に勉強して自分で解ける問題を増やす。
まだまだ勉強します。
強化学習の行動価値関数について
強化学習ではある状態に対してどのような行動をとれば、その後に得られる総報酬が最大化されるかを学習していきます。
強化学習ではこの指標を「行動価値」とよび、「行動価値関数」というもので表現しています。
行動価値関数の理想的な定義は、状態と行動を渡すと時刻以降で得られる報酬の総和を返してくれるものです。
つまりざっくり式で表すと
$$ Q(s_t,a_t) = r_t + r_{t+1} + r_{t+2} + r_{t+3} + ・・・\;\;\;\;\;\;\;\;(1)$$
のようになってほしいわけです。
ですがこの定義だと、(報酬が常に同符号だと仮定すると)値が無限に発散してしまいます。 また、行動が大きな影響を与えるのは報酬であって、報酬に大きな影響を与えるのは行動です。にもかかわらず全てのが同列に扱われているのは不適切であると考えられます。
そこで割引率というものを導入します。は0~1の値で、経過時間に応じて報酬に乗算していきます。
式(1)に割引率を適用すると以下のようになります。
$$ Q(s_t,a_t) = r_t +\color{red}{\gamma}・r_{t+1} + \color{red}{{\gamma}^2}・r_{t+2} + \color{red}{{\gamma}^3}・r_{t+3} + ・・・\;\;\;\;\;\;\;\;(2)$$
これによって行動価値はある一定値に定まります。
さて、行動価値関数の定義ができたところで、これを実際に学習していきたいわけです。
機械学習では、目標となる数式の両辺の情報が手に入れば、教師あり学習として学習できます。
ということで情報を集めていきたいわけですが、式(2)の右辺が無限和になっていて、全て集めるのは困難です。
そこで、式(2)を少し工夫します。
$$ Q(s_t,a_t) = r_t +{\gamma}・r_{t+1} + {{\gamma}^2}・r_{t+2} + {{\gamma}^3}・r_{t+3} + ・・・$$ $$ \;\;\;\;\;\;\;\;\;\;\;\;\;\;= r_t +{\gamma}・(r_{t+1} + {{\gamma}}・r_{t+2} + {{\gamma}^2}・r_{t+3} + ・・・)$$ $$ \;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;= r_t +{\gamma}・Q(s_{t+1},a_{t+1})\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;(3)$$
式(3)のようにしますと、両辺の情報が時刻と時刻のみで構成されているため、容易に集めることができます。
そして、あらゆる状態行動の組み合わせで式(3)の等号が満たされるなら、実質的に式(2)が満たされているとみなすことができます。
を作るために学習しているのに、学習中にを使ってもいいのか?と思われる方もいらっしゃるかと思います。
これが強化学習の特徴的な部分で、教師信号も学習していくということです。
分かりづらかったかもしれませんが、ざっくりとはこんな感じです。
もう少し勉強します~。
python3 pickleで簡易データベース
プログラム内で使った変数などの各種情報を一旦外部に保存しておきたいことってありますよね。
MySQLなどしっかりしたデータベースが使えればいいんですけど、SQL文を覚えたりしないといけないので割と敷居が高いです。
そこで、MySQLを使わずに簡易的にデータベースを作る方法を紹介します。
・データ保存
import pickle data = ~~~ with open("filename","wb") as f pickle.dump(data,f)
wbはバイト形式で書き込むということです。 dataの型はなんでも大丈夫みたいです(ちゃんと検証してはいない)。
listを保存しておけば簡易的なデータベースとして使えますね!
・データ読み込み
import pickle with open("filename","rb") as f data = pickle.load(f)
これでdataの内容が復元できます。
pickleを使えばデータを外部に保存できるので、プログラムが終了した後に、別のプログラムで再利用することが可能になります。
ただファイルに落とすだけですのでセキュリティ面は保証できません。 重要なデータには使わないようにしましょう。
オイラー素数が楕円の格子点と関係していた件
オイラー素数とはオイラーの素数生成式で表される素数のことです。
この式が非常の多くの素数を生成することは以前の記事で紹介しました。単純な二次多項式がこのような振る舞いをするのには, 何か理由があるはずだと考えられていますが, 今のところよくわかっていません。
そこで, 私自身少々気になって色々調べてみることにしました。
そしてわかったことは, 素数生成式で表現される合成数には規則があるということです。
自然数列では合成数が一次関数(2n, 3n…)で現れるのに対し, 素数生成式では二次関数で現れることがわかりました。
その式を変形していくと以下のような楕円の式が導かれました。
$$ x^2+(4a-1)y^2-(4b+2)y-1=0 $$
この楕円上の格子点がの素数性, もっと言えば約数の個数に関係していることがわかりました。
Youtubeに内容の一部を公開しています!
何か知ってる方いらっしゃいましたらぜひご教授ください!
python3 文字列内の変数展開
文字列内に変数の値を組み込みたいことってよくありますよね。
そんなときに使える方法4つをまとめます。
1.f-stringsを使う
name = "isato" age = 23 print(f"私は{name}です。{age}歳です。") # => 私はisatoです。23歳です。
2.str.format()を使う
name = "isato" age = 23 print("私は{0}です。{1}歳です。".format(name,age)) # => 私はisatoです。23歳です。
3.%演算子を使う
name = "isato" age = 23 print("私は%sです。%d歳です。" %(name,age)) # => 私はisatoです。23歳です。
4.+演算子を使う
name = "isato" age = 23 print("私は"+name+"です。"+str(age)+"歳です。") # => 私はisatoです。23歳です。
f-stringが使いやすくていいと思います!
他のやり方も覚えておいて損はないでしょう。