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

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

今回は子供の日という事で
ステレオグラムで遊んでみました。

解説動画はこちら



ステレオグラムとは(立体画)


立体図は、立体的印象をもつように描かれた
平面に描かれた図や絵あるいは写真のことで

目の焦点を意図的に前後にずらして合わせることで
左右の絵を別々の目で見ることにより
立体的に見ることができる画像です。


今回はドットのパターンを用意して
そこに浮かび上がらせる画像を組み合わせて作っています。

見方は、黒いドットが3つになるように
重ね合わせて目の焦点を合わしていくと
見る事ができると思います。



ステレオグラムを作成するコード

import numpy as np
import matplotlib.pyplot as plt
import cv2
import warnings
warnings.simplefilter("ignore")
%matplotlib inline

def make_dots(shape=(16, 16), levels=64):
    return np.random.randint(0, levels - 1, shape) / levels

def make_text_img(text='A', shape=(400, 600)):
    font = cv2.FONT_HERSHEY_SIMPLEX
    (text_width, text_height), _ = cv2.getTextSize(text, font, 5, 30)
    img = np.zeros((text_height + 50, text_width + 200), dtype=np.float)
    cv2.putText(img, text, (100, text_height+10), font, 5, (255, 255, 255), 30, cv2.LINE_AA)
    img_resized = cv2.resize(img, shape[::-1], interpolation=cv2.INTER_AREA)
    return img_resized

def normalize(depthmap):
    if depthmap.max() > depthmap.min():
        return (depthmap - depthmap.min()) / (depthmap.max() - depthmap.min())
    else:
        return depthmap

def make_autostereogram(text, shift_amplitude=0.1, invert=False):
    depthmap = make_text_img(text=text)
    pattern = make_dots(shape=(64, 64))
    depthmap = normalize(depthmap)
    if invert:
        depthmap = 1 - depthmap
    autostereogram = np.zeros_like(depthmap, dtype=pattern.dtype)
    for r in np.arange(autostereogram.shape[0]):
        for c in np.arange(autostereogram.shape[1]):
            if c < pattern.shape[1]:
                autostereogram[r, c] = pattern[r % pattern.shape[0], c]
            else:
                shift = int(depthmap[r, c] * shift_amplitude * pattern.shape[1])
                autostereogram[r, c] = autostereogram[r, c - pattern.shape[1] + shift]
    autostereogram[48:53, 248:253] = 0
    autostereogram[48:53, 348:353] = 0
    return autostereogram

実行する際は浮かび上がらせる画像を
テキストとして文字列を変更します。
autostereogram = make_autostereogram(text='A')
plt.figure(figsize=(8,8))
plt.imshow(autostereogram, cmap='gray')
plt.axis("off")
plt.show()
download

この画像の上にある黒い点が
4つになるようにぼんやり見た後に
点が3つになるように焦点をずらします。

そうすると A という文字が
浮かび上がって見えると思います。


問題

さっきの練習を少し難しくした3文字です。
g1





新宿の掲示板に書いてある3文字です。
g2




自分の大好きな5文字です。
g3





見えましたか?


見えない方は
努力が足りていないです!!!!!!!!

見えた方は
今日の1日がとても
すこやかに過ごせるでしょう!!!

色々画像を作って遊んでみて下さい。

それでは。

今回はMLB2023の大谷投手の
全投球データを見てみることとしました。

解説動画はこちら




データの入手先

今回取り扱っているデータは
Baseball Savantというサイトから入手できます。

Baseball Savant


画面の「Pitchers」に名前を入力して「Search」
結果画面の右側にある
「Download Data as Comma Separated Values File」を
クリックするとCSVがダウンロードできます。




データの読み込み

Google Colabでデータを見る際は
事前にダウンロードしたデータを
ファイル置き場にアップロードしておいて下さい。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv('savant_data.csv')
print(df.shape)
df.head()




ピッチャー大谷選手のスタッツ


全球種
name_data=[
  ['Sweeper','スィーパー','スライダーよりも横曲がりの大きいボール'],
  ['4-Seam Fastball','直球','直線的な豪速球(縫い目:シームが4回見える)'],
  ['Cutter','カット・ファスト・ボール','直球とほぼ同じ球速で小さく鋭く変化するボール'],
  ['Split-Finger','フォーク','打者の近くで落下する変化球'],
  ['Sinker','シンカー','投手の利き腕方向に曲がりながら落ちる球種'],
  ['Curveball','カーブ','比較的遅い球速で大きく曲がる球'],
  ['Slider','スライダー','ブレーキがかかった大きく曲がる球'],
  ]
name_df = pd.DataFrame(name_data,columns=["pitch_name","球種名","説明"])
pitch_df = pd.DataFrame(df.pitch_name.value_counts()).reset_index()
pd.merge(pitch_df,name_df,on='pitch_name', how='left')


投球結果
stats_df = pd.DataFrame(df.description.value_counts()).reset_index()
stats_df


ストライクの投球
plt.figure(figsize=(10, 6))
x = df['plate_x']
z = df['plate_z']
d = df['description']
cs = ['blue' if 'strike' in c else 'grey' for c in d]
plt.scatter(x, z, c=cs)
plt.xlim(-10,10)
plt.ylim(-2, 6)
plt.show()
download-2





球種による変化量
plt.figure(figsize=(10, 6))
pitchtypes = ['Sweeper', '4-Seam Fastball', 'Cutter', 
'Split-Finger', 'Sinker', 'Curveball', 'Slider'] colors = ['red', 'brown', 'orange', 'aqua', 'olive', 'magenta', 'lime'] s = set() for index, row in df.iterrows(): x = row['pfx_x'] * (-30.48) # センチ換算(逆方向) z = row['pfx_z'] * ( 30.48) # センチ換算 n = pitchtypes.index(row['pitch_name']) if n not in s: s.add(n) plt.scatter(x, z, color=colors[n], label=row['pitch_name']) else: plt.scatter(x, z, color=colors[n]) plt.legend(loc="upper left", fontsize=12) plt.xlim(-100,100) plt.ylim(-60, 60) plt.show()
download





この様な感じで
投球データを色々な角度から
分析する事ができるデータになっています。

今回紹介した以外にも
たくさんのデータが存在するので
色々遊ぶ事ができると思います。

あそびたい方は
是非データをダウンロードして
こねくりまわしてみて下さい。

それでは。

今回は、犬の名前ランキングの
TOP10の名前の犬に
出会えるまで帰れないロケの
検証シミュレーションです。


解説動画はこちら


 
動画作ってた時は思い出せなかったですが
「スクール革命」という番組で
芸人の「ちゃんぴょんず」が
このロケをしてました。

犬の名前ランキング
トップ10の犬に全部出会うというロケです。

街を歩く犬を散歩している人に声をかけて
何匹出会ったら、全部出会えるのか
プログラムで検証してみましょう。


犬の名前ランキング

まずは犬の名前ランキングです

毎年アンケート調査されている様で
そこのデータを引用します。

import pandas as pd
import numpy as np

df = pd.read_html("https://www.anicom-sompo.co.jp/news-release/2023/20231019/")[0]
df

順位 名前 頭数
0 1位(1) ムギ 1264
1 2位(2) ココ 1091
2 3位(4) ソラ 812
3 4位(3) モカ 786
4 5位(5) マロン 732
5 6位(6) レオ 714
6 7位(8) モコ 676
7 8位(13) ラテ 642
8 9位(7) モモ 641
9 10位(12) チョコ 631


犬の名前ランキングは
こんな感じになっている様です。


シミュレーション

犬は全体で何頭いるか不明なので
TOP10が全体の20%だと仮定します。

まずはこのTOP10をデータ化します。
top_data = []
for i, row in df[["名前","頭数"]].iterrows():
    name = row["名前"]
    num = row["頭数"]
    top_data += [name] * num

print(len(top_data))
7989

残りの80%はハズレですね。
top_num = df["頭数"].sum()
h_num = top_num * 4
h_data = ["ハズレ"] * h_num
print(len(h_data))
31956

data = top_data + h_data
print(len(data))
39945


全体で4万頭ほどのデータになります。

ランダムでシャッフルしてあげると
こんな感じのデータになります。
tmp = data.copy()
np.random.shuffle(tmp)
print(tmp[0:10])
['ハズレ', 'ハズレ', 'ムギ', 'モモ', 'ハズレ', 'ハズレ', 'ムギ', 'ハズレ', 'ハズレ', 'ハズレ']


あとはTOP10の名前に
全部出会えるまで会うだけです。

シミュレーションするプログラムは
こんな感じです。
res = {n:0 for n in df["名前"].values}
count = 0
for name in tmp:
    count+=1
    if "ハズレ"!=name:
        res[name]+=1
        # TOP10全部会ってるか判定
        if all([t>0 for t in res.values()]):
            break
print(count)
210

あとは1回の試行では結果がばらつくので
1万回ほど試行してあげれば
どれくらいの回数で見つかるのかが
分かるはずです。

# 回数チェック関数
def check_count(tmp):
    res = {n:0 for n in df["名前"].values}
    count = 0
    for name in tmp:
        count+=1
        if "ハズレ"!=name:
            res[name]+=1
            # TOP10全部会ってるか判定
            if all([t>0 for t in res.values()]):
                break
    return count

calc_data = []
for i in range(10000):
    tmp = data.copy()
    np.random.shuffle(tmp)
    c = check_count(tmp)
    calc_data.append(c)

calc_df = pd.DataFrame(calc_data,columns=["count"])
calc_df.hist(bins=100)
output_23_1


結果はこんな感じになりました。

大体平均160回くらいで
出会いきれる事になりそうです。

運が良いと数十頭
運が悪いと数百頭

そんな結果でした。

このように、テレビのロケであっても
おおよそのシミュレーションが出来るので

事前にシミュレーションしておくと
諸々の調整がスムーズに行く気がします。

プログラミングでの効率化が
オススメです!!!!

今回はテレビ番組の
ロケをシミュレーションしてみました。

それでは。

このページのトップヘ