乙Py先生のプログラミング教室

乙Py先生のプログラミング教室
初学者のためのプログラミング学習サイト

今回はPythonの使いやすさと
C言語のパフォーマンスを併せ持つ
新プログラミング言語「Mojo」が
Colabで使える様になったので試してみました

解説動画はこちら


 
Mojoについて

MojoはPythonのスーパーセットとなる
新しい言語で、Pythonに比べて
パフォーマンスとメモリの安全性が向上しています

コンパイル言語になるので
少しだけやることは増えますが
Pythonの構文はサポートされていて
慣れればPython言語と同じように
コードを書き進める事が
出来るんじゃないかと思います



MojoのSDKライセンス取得

Mojoを始めるにはライセンスが必要です

と言っても、メアドを登録するくらいです

「Get Started」から
Mojoのサイトからメールアドレス等で
登録を行います

Mojo



Mojoのインストール

ライセンス登録すると
インストールコマンドが記載された
ページに飛ばされます

WindowsやMacなど、環境ごとの
コマンドが記載されていますので
Google Colabで動かす場合は
「Linux」を選びましょう

次のコマンドがライブラリ取得のコマンドです
!curl https://get.modular.com | \
  MODULAR_AUTH= <自分のMODULAR_ID> \
  sh -

実行の際には各個人事にIDが変わるので
自身のコマンドを手に入れて実行して下さい


ライブラリ取得できたら
次はインストールコマンドです
!modular install mojo

普通に実行すれば
問題なくインストール出来るかと思います

インストールが終わったかどうかは
確認コマンドで確認できます
!export MODULAR_HOME="/root/.modular" && \
export PATH="/root/.modular/pkg/packages.modular.com_mojo/bin:$PATH" && \
mojo --version
mojo 0.3.1 (a3eed7c8)


MojoとPythonの速度比較


さて、それではPythonとMojoで
同じコードでの速度を比較検証してみましょう

3重ループでカウントするだけの
すごくシンプルな関数を実行して
時間を測るというコードになっています

・Pythonのコード
# サンプルコード
import time

def test_def(n):
    count = 0.0
    for i in range(n):
        for j in range(n):
            for k in range(n):
                count += 1.0
    return count


# Pythonでの実行時間
start_time = time.time()
n=500
print(test_def(n))
elapsed_time = time.time() - start_time
print(f"{elapsed_time}s")
125000000.0
7.398502826690674s


1億2千5百万回計算して
7-8秒ほど掛かる様です


・Mojoのコード

Mojoの場合は一度ファイルとして
作成しないといけません

ソースコードをそのままファイル化します

Mojoファイルの作成コマンド
%%writefile main.mojo

from time import now

def sample_def(n):
    var count: Float64 = 0.0
    for i in range(n):
        for j in range(n):
            for k in range(n):
                count += 1.0
    return count

def main():
    let start_time = now()

    let n: Int64 = 500
    count = sample_def(n)
    print(count)

    let end_time = now()
    let execution_time = Float64(end_time - start_time) / 1000_000_000
    print(execution_time)

これを実行するとGoogle Colabのファイル置き場に
main.mojoが作成されるハズです

このファイルをコマンドで動かします
mojoファイルを実行するコマンドはこれです
# Mojoの実行
!export MODULAR_HOME="/root/.modular" && \
export PATH="/root/.modular/pkg/packages.modular.com_mojo/bin:$PATH" && \
mojo main.mojo
125000000.0
0.18964049799999999


先ほどのPython実行は7-8秒ほどになるので
単純計算で40倍くらいは速くなっているようです

単純だけども、時間の掛かる計算をやらなければ
いけない場合に、一部をmojoに書き換えておけば
その分格段に速くなりそうですね

複雑なものだとコードの差異が大きいので
大変そうですが、簡単なアルゴリズムの
書き換え程度なら、実用出来かなと思いました

今後は機械学習系の実装も
徐々にMojoに置き換わって行くのかなと
推測します

速くなる分には
何のデメリットも無いですもんね
今後の動きを期待したいです

今回はMojoをGoogle Colabで試してみました
それでは

たまには真面目に
数学の問題を解いてみましょう

2023年度の東大の数学の問題です


解説動画はこちら



今回は数学の問題です

手で解いたら解法が分からず
すごく時間が掛かってしまう問題も
プログラミングの力を使えば
近似解を簡単に求める事ができます

という訳で
東大の数学の問題を解いてみましょう





2023年度東大数学文系第3問

問題:
黒玉3個、赤玉4個、白玉5個が入っている袋から
玉を1個ずつ取り出し、取り出した玉を順に1列に12個並べる
ただし、袋から個々の玉が取り出される確率は等しいものとする

(1) どの赤玉も隣り合わない確率 p を求めよ
(2) どの赤玉も隣り合わないとき
どの黒玉も隣り合わない条件付確率 q を求めよ


12個の順列の問題ですね
プログラミングの力を使えば
こういうのもシミュレーション出来ます


考え方

まずは石を用意しましょう
次にその石の並びで隣同士なのかどうかを
チェックする方法を考えてみましょう

次のようなやり方で
石のデータと判定方法を
考える事ができます
# 12個の玉を作って試してみる
import numpy as np

data = ["b"]*3 + ["r"]*4 + ["w"]*5
np.random.shuffle(data)

# リストを結合して文字列にする
st = "".join(data)

# 赤玉が隣り合わないかどうか
res1 = "rr" not in st
# 上記のに加えて黒玉が隣り合わないかどうか
res2 = res1 & ("bb" not in st)

print(st)
print(res1)
print(res2)
rwrwwbbrbwwr
True
False

データは文字列やリスト型で定義しておくと
後で計算しやすいです

これを元にして
計算を行ってみましょう



順列を生成してチェックする方法



今回は12個の中から12個を取り出してつくる
順列になるので、その総個数は
import math

math.factorial(12)
479001600


順列は itertools ライブラリの
permutations で作る事ができます

チェック機構では判定式を返し
Trueを1、Falseを0として
条件にあった個数を返していきます

最終的に条件にあった個数と
元の順列の個数を組み合わせれば
確率が求められます
import itertools

def num_check(data):
    st = "".join(data)
    res1 = "rr" not in st
    res2 = res1 & ("bb" not in st)
    return res1, res2

data = ["b"]*3 + ["r"]*4 + ["w"]*5

ans1, ans2 = 0, 0
for t in itertools.permutations(data):
    t1,t2 = num_check(t)
    ans1+=t1
    ans2+=t2

# 総当たりの個数(順列の個数)
permutations_num = math.factorial(12)

print("1の答え : {0}".format(ans1/permutations_num))
print("2の答え : {0}".format(ans2/ans1))
1の答え : 0.2545454545454545
2の答え : 0.6130952380952381




シミュレーションしてみる


総当たりの方法が思いつかなくても
シミュレーションで近似解を求める事ができます

先ほどは順列を作って繰り返しを行っていましたが
単純に回数を指定して、ランダムに並び替えた後に
チェックを行えば、順列の際の近似が求められます

チェック関数は先ほどのを用いるとして
次のような計算でシミュレーションできます

import numpy as np

N = 100000000

ans2_1, ans2_2 = 0, 0
for i in range(N):
    data = ["b"]*3 + ["r"]*4 + ["w"]*5
    np.random.shuffle(data)
    t1,t2 = num_check(data)
    ans2_1+=t1
    ans2_2+=t2

print("1の答え : {0}".format(ans2_1/N))
print("2の答え : {0}".format(ans2_2/ans2_1))
1の答え : 0.25452006
2の答え : 0.613167347202417


小数点第3位くらいまでは
同じ数字になりますね

近似解だと点数は貰えないかもしれませんが
点数関係ない、仕事上の計算であれば
こういったシミュレーションが行えるのが
プログラミングの役に立つポイントです

確率が分からなくても
それっぽい確率を算出する事ができるので
いろいろ便利ですねえ

色々なシミュレーションを行えるので
仕事がめちゃくちゃ捗ります

プログラミング出来ない方は
是非、この機会に覚えてみて下さい


今回は数学の問題を解く
プログラミングでのシミュレーションでした
それでは
 

今回は米の重さのサンプルデータから
母平均の信頼区間を求めてみました

解説動画はこちら



VIVANT


TBSの日曜9時のドラマ「VIVANT」の第8話

日本の秘密組織とされる別班メンバーである
主人公「乃木」がテロ組織「テント」に潜入

テントの活動を調査している最中に
支援団体の給食提供シーンがあり
一人当たり「150gの米」を炊いて提供

しかし主人公は違和感を抱いた・・・


この違和感が正しいのかどうか
検証してみましょう



米の重さ

ドラマでは200人程度の人数分を提供していたと見られ
その中からランダムサンプリングされた10皿のデータが
描かれていました

kome

手での配給なのでばらつくよと犯人
150gの米は、炊くと2.2倍の330gになるらしい・・・

このデータから本来推定される
母集団の平均の信頼区間を求めてみましょう



信頼区間を求める

母集団の平均が分からない時に
サンプルデータから母集団を推定する方法です

計算方法としては次のような式があります

kome2


次の手順で求めてみましょう
1.標本平均と不偏分散をもとめる

2.統計量tを計算する

3.信頼区間を推定する


必要なものはサンプルの平均値と不偏分散
統計量tの値となります


1.標本平均と不偏分散をもとめる

Pythonではこう言った計算を行うための
ライブラリが用意されています

読みこんでおいて、お米もデータ化しておきます
import math
from scipy import stats

# 米の重さ
kome = [302,296,298,304,300,301,303,305,295,297]


平均は次のように求められます
# 標本平均 (合計 / 個数)
mean = sum(kome) / len(kome)
print(mean) 
300.1


分散は偏差の2乗の合計値を個数で割った値です
不偏分散は個数の代わりに 個数-1 で割ります
不偏分散は stats.tvar で求める事ができます
# 不偏分散( 偏差の二乗の合計 / (個数-1) )
var = stats.tvar(kome )
print(var)
12.1


ライブラリなしでも
不偏分散は求める事ができます
# 不偏分散( 偏差の二乗の合計 / (個数-1) )
sum([(c - mean)**2 for c in kome]) /(len(kome) - 1)


2.統計量tを計算する


統計量tは
stats.t.interval(信頼度, df=自由度) で求める事ができます

今回は信頼度95%(0.95)で行ってみるとして
他に自由度が必要です

自由度は 個数-1 で求められます

#自由度(個数 - 1)
dof = len(kome) - 1
print(dof)

# stats.t.interval(0.95, df=9)
_ , t = stats.t.interval(0.95, df=dof)
print(t)
9
2.2622157


3.信頼区間を推定する

先ほどの式に求めた値を当てはめてみましょう

下限の値は サンプルの平均 - 統計量t * 平方根(不偏分散/個数)
上限の値は サンプルの平均 + 統計量t * 平方根(不偏分散/個数)
bottom = mean - t * math.sqrt(var/len(kome))
up = mean + t * math.sqrt(var/len(kome))

print(bottom)
print(up)
297.61162
302.58837


これが95%の信頼区間となります
99%区間はもう少し広くなります

実測から求めた母平均の信頼区間が
おそよ 296g - 303g なので

平均330gになるように米をよそったら
この値には到達しないですね

1割減の300g平均でよそったと見るべきでしょう
不正はバレバレですね

このあたりの追求はまるで
「半沢直樹」のようでした



まとめ

Scipyモジュール を使うと
色々な統計分析を行う事ができます

検査とかで誤差が正しいのかどうかを
検証できたりもするのですごく便利です

Pythonを使えばこういう分析も
簡単に行えるので、スキルアップには丁度良いですよ

是非覚えてみて下さい

それでは




このページのトップヘ