isatoの活動日記

管理人isatoが毎日の生活で気になったこと、勉強になったことを書いています。

python3 文字列操作:分割

python3での文字列の分割にはsplit関数を使います。 使い方は以下の通りです。

string = "abc.def.ghi"

splist = string.split(".")

print(splist)

# => ['abc', 'def', 'ghi']


split関数の引数に分割文字を指定することで、文字列を分割することができます。 結構使えますので、覚えておきたいですね。

python3 アノテーションについて

アノテーションとは要は注釈のことです。

コメントでつけてもいいんですが、関数の引数と戻り値に関しては正式な書き方があるので、そちらを使ったほうが良いでしょう。

以下のように使います。

def multi(x :int , y :int) -> str:
    return f'{x*y}'


このようにすることで、一目で入出力が分かりますね!

可読性を高めるためにも積極的に使っていきましょう〜

虚二次体とオイラーの素数生成多項式

オイラー素数生成多項式の不思議について以前の記事で紹介しましたが、少し研究されていて、ある性質が見つかっていたようです。

 

以下のページで紹介されています。

 

tsujimotter.hatenablog.com

 

めちゃくちゃ面白いと思いました。

でも、整数論が難しくてなかなか理解できません笑。私の独自研究を進めてくれる情報だと思っているのですが...。

 

まずは整数論から勉強しないとですね。

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 アンパックについて

皆さんアンパックってご存知ですか。僕は最近知りました。

アンパックとはリストや辞書を展開して、中身を取り出すことです。

アンパックによって以下のようなことができます。

  1. *によるリストのアンパック
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)の理想的な定義は、状態s_tと行動a_tを渡すと時刻t以降で得られる報酬rの総和を返してくれるものです。

つまりざっくり式で表すと

$$ Q(s_t,a_t) = r_t + r_{t+1} + r_{t+2} + r_{t+3} + ・・・\;\;\;\;\;\;\;\;(1)$$

のようになってほしいわけです。

ですがこの定義だと、(報酬が常に同符号だと仮定すると)値が無限に発散してしまいます。 また、行動a_tが大きな影響を与えるのは報酬r_tであって、報酬r_{t+T}に大きな影響を与えるのは行動a_{t+T}です。にもかかわらず全てのrが同列に扱われているのは不適切であると考えられます。

そこで割引率\gammaというものを導入します。\gammaは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)のようにしますと、両辺の情報が時刻tと時刻t+1のみで構成されているため、容易に集めることができます。

そして、あらゆる状態行動の組み合わせで式(3)の等号が満たされるなら、実質的に式(2)が満たされているとみなすことができます。

Q(s_t,a_t) を作るために学習しているのに、学習中にQ(s_t,a_t) を使ってもいいのか?と思われる方もいらっしゃるかと思います。

これが強化学習の特徴的な部分で、教師信号も学習していくということです。

分かりづらかったかもしれませんが、ざっくりとはこんな感じです。

もう少し勉強します~。