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

プログラミング

たまには真面目に
仕事で使えそうなプログラミングをしてみましょう


解説動画はこちら


 

1.WEB上にあるCSVファイルを開く

今回はWEB上にあるファイルを
ダウンロードせず、直接開いてみましょう。


読み込みするファイルは、総務省かどっかが出している
E-statのデータです。

男女別人口-全国,都道府県(大正9年~平成27年)
file_url ='https://www.e-stat.go.jp/stat-search/file-download?statInfId=000031524010&fileKind=1'

これを読み込みするには
Pandasライブラリを使います。
import pandas as pd
import warnings
warnings.simplefilter('ignore')

df = pd.read_csv(file_url , encoding='cp932')

df
スクリーンショット 2022-08-06 17.20.11

読み込みは出来ましたが
最後の方にゴミが載っています。


政府が用意しているデータは
リテラシーが低く、ゴミなので
そのままだと使えないことが多いです。

いらない部分を読み飛ばしてみましょう

skipfooter = 最後尾の行数
を加えるといらない部分を飛ばして読み込み出来ます。

df = pd.read_csv(file_url , encoding='cp932', engine="python" , skipfooter=2)

df
スクリーンショット 2022-08-06 17.20.42




Pandasライブラリを用いないで読み込みする場合は
urllibが使えます。

urllib.request.urlopenで開いたファイルは
http.client.HTTPResponseオブジェクトになります

オブジェクト.decode()で
strオブジェクトに変換できます。

import urllib

# そのままurlopenで開いた場合
with urllib.request.urlopen(file_url) as _f:
    for row in _f:
        print(row)
        break
b'"\x93s\x93\xb9\x95{\x8c\xa7\x83R\x81[\x83h","\x93s\x93\xb9\x95{\x8c\xa7\x96\xbc","\x8c\xb3\x8d\x86","\x98a\x97\xef\x81i\x94N\x81j","\x90\xbc\x97\xef\x81i\x94N\x81j","\x92\x8d","\x90l\x8c\xfb\x81i\x91\x8d\x90\x94\x81j","\x90l\x8c\xfb\x81i\x92j\x81j","\x90l\x8c\xfb\x81i\x8f\x97\x81j"\r\n'
# urlopenで開いてdecodeした場合
with urllib.request.urlopen(file_url) as _f:
    for row in _f:
        print(row.decode('cp932'))
        break
"都道府県コード","都道府県名","元号","和暦(年)","西暦(年)","注","人口(総数)","人口(男)","人口(女)"


リストでまとめて読み込んでしまう場合は
次のように書けばいけます。
# urlopenで開いてlist化する
with urllib.request.urlopen(file_url) as _f:
    # 改行コードで分割する
    lines = _f.read().decode('cp932').split('\r\n')
    
lines
['"都道府県コード","都道府県名","元号","和暦(年)","西暦(年)","注","人口(総数)","人口(男)","人口(女)"', '"00","全国","大正",9,1920,"",55963053,28044185,27918868',・・・

ゴミデータが最後の3個に入ってしまっているので
リストのスライス参照で取り除くと良いでしょう。
lines[970:-3]

これでpandasでは難しい1行単位での
データ操作を行えます。



2.データを見る

さて、ファイルが読み込めたので
次は中身を細かくみてみましょう。

ファイルはこんな感じになっています。
スクリーンショット 2022-08-06 17.29.16




全国の人口だけを見る
df[df['都道府県名']=='全国'][['西暦(年)','人口(総数)']]
スクリーンショット 2022-08-06 17.29.33

Pandasのデータフレームでは
条件抽出が行えるので
該当する部分だけを抜き出すことができます。



最近のものだけを見る(2010 , 2015)
df[df['西暦(年)'].isin([2010,2015])][['西暦(年)','都道府県名','人口(総数)']]
スクリーンショット 2022-08-06 17.29.52

isin で値を複数指定して
条件抽出ができます。



2010 , 2015の差分を見る
# 該当年のデータを抽出
df_2010 = df[df['西暦(年)']==2010][['西暦(年)','都道府県名','人口(総数)']]
df_2015 = df[df['西暦(年)']==2015][['西暦(年)','都道府県名','人口(総数)']]

# インデックスのリセット
df_2010.reset_index( inplace=True , drop=True)
df_2015.reset_index( inplace=True , drop=True)

# データフレームの結合
df_concat = pd.concat([df_2010 , df_2015[['人口(総数)']]],axis=1)
df_concat.columns = ['西暦(年)', '都道府県名', '2010_人口(総数)', '2015_人口(総数)']

# 差分の計算
df_concat['差分'] = df_concat['2015_人口(総数)'].astype(int) - df_concat['2010_人口(総数)'].astype(int)
df_concat['増減'] = df_concat['差分'].apply(lambda x: '減少' if x <=0 else '増加')

# 人口が増加した都道府県は?
df_concat[df_concat['増減']=='増加']
スクリーンショット 2022-08-06 17.32.34

差分を見るには
まずはデータフレームとして該当するデータを
年ごとに作成しておき
それを列方向に結合させます。

のちに数値化して差分を計算することができます。

2010 - 2015で
人口が増えた都道府県は8個しか無いようですね
2020年度のデータがなかったようですが
人口は減る傾向にあります



東京都の人口推移
df_plot = df[df['都道府県名']=='東京都'][['西暦(年)','人口(総数)']]
df_plot.reset_index( inplace=True , drop=True)

df_plot['人口(総数)'] = df_plot['人口(総数)'].astype(int)
df_plot['西暦(年)'] = df_plot['西暦(年)'].astype(str)

df_plot.plot(kind='line',x='西暦(年)')
スクリーンショット 2022-08-06 17.32.44
最後に東京都だけを抜き出して
人口推移を見ます

データフレームをそのまま
折れ線グラフに描画することが出来ます

東京都の人口は100年前は400万人弱
1945年に大きく減り
そこから猛烈な勢いで1970年頃までは急成長

1995年以降また増え続けています
こういうのをささっと作ることができるのが
Pythonの強みですね




まとめ

Google Colabなどを使えば
Pythonをインストールしなくても
PC上からファイル操作を行えます

エクセルなどで開けない
ファイルが有るときは
是非Pythonを活用してみましょう。

それでは

本日はロシュの限界について
考えてみることにしました。

解説動画はこちら



さて、ロシュの限界とは
惑星や衛星が潮汐力に破壊されずに
近づける限界距離の事で

ロシュ限界より内側に入ると
その天体は潮汐力により破壊されてしまうようです

つまり、質量の大きな天体同士が近づくと
一方が粉々になってしまうことになります

一般的には質量の小さい方が
バラバラにされてしまうようですね

ロシュの限界は次のような計算式で
求めることができるようです

ただし、惑星や衛星などの性質として
剛体であるか流体であるかで
計算式がちょっと変わってくるようです

剛体の場合
スクリーンショット 2022-07-30 12.47.37


流体の場合

スクリーンショット 2022-07-30 12.47.46

流体の場合は限界が少し伸びるようです


さて、ここからは
月を地球に落とそうとしたら、どこで限界を迎えるか
を考えてみましょう

まるでSF映画のようですが
昨日、ローランド・エメリッヒ監督作品
「ムーンフォール」が公開されたので
ちょうど良い題材ですね


一応先程の計算式で計算できるようです

地球の半径6370𝑘𝑚
地球の密度5.52𝑔/𝑐𝑚3
月の密度は3.34𝑔/𝑐𝑚3


これを先程の計算式にぶち込むと・・・


月に流動性がないと考えた場合
r = 6370
s = 5.52
b = 3.34

R = (2 *s/b) ** (1/3) * r
print(R)
9488.851161893317


月に流動性がある場合
r = 6370
s = 5.52
b = 3.34

R = 2.423 * r * (s/b) ** (1/3)
print(R)
18248.35482126908

結果はkmで
こんな感じで求められました


地球の性質を考えると
1万kmから1万8千kmあたりで
ロシュの限界を迎えるっぽいです

地球 - 月の距離は約38万kmなので
月を破壊したければ
この距離内に近づければ良いことになりますが
結構大変ですねー


その昔
自分がロシュの限界を知った作品に
スプリガンmk2(1992)があります。

pc-engineのシューティングゲームなので
知っている人は少なそうですが
月に空間駆動エンジンを取り付けて
地球軌道に向かわせぶつけて
地球人を滅ぼそうとする設定でした

まあ、その前にロシュの限界を迎えるから
地球にはそのままは当たらないんだけどね
なんて台詞あるので、結構覚えてます

PS5画質で復活しないかなー

本日はそんな
SFによく出てくる
ロシュの限界の計算方法について
解説してみました

それでは。

本日は最強のそうめんが何か
レシピサイトの投稿データから
考えてみることにしました。

解説動画はこちら




さて、とあるレシピ投稿サイトから
データを引っ張ってきました。

一応のデータはこんな感じになっています。
スクリーンショット 2022-07-23 13.40.35

293件のそうめんレシピがあって
点数がついているものもありました。

分布を見てみると
download
こんな感じで
点がついていないものは0にしました。

5点満点だとすると
4.5点以上が良いレシピなんではないかと思います。

これで絞り込んでみると
32件が該当しました。

別途食材のデータも取っています。
スクリーンショット 2022-07-23 13.43.46

これを併せて良い点が付いたレシピの
食材を集計してみました。

結果はこんな感じです。

そうめん 31
水 19
ごま油 16
酒 11
しょうゆ 9
めんつゆ[3倍濃縮] 9
大葉 7
おろししょうが 7
塩 6
白いりごま 6
めんつゆ(3倍濃縮) 5
みょうが 5
おろしにんにく 5
豚バラ薄切り肉 4
きゅうり 4
マヨネーズ 4
白すりごま 4
トマト 4
みりん 3
かつお節 3
細ねぎ(刻み) 3
ミニトマト 3
こしょう 3
長ねぎ 3
塩こしょう 3


この中の食材を使えば
大概はおいしいそうめんが出来上がると思います。

ということでレシピを考案してみました。

案1:さっぱりそうめん
具材料:トマト、刻みネギ(少々)、大葉(お好みで)
調味料:ごま油、めんつゆ、塩、胡椒
酢、おろしにんにく、白いりゴマ

案2:シンプルそうめん
具材料:ミョウガ、大葉、かつお節
調味料:めんつゆ

案3:スタミナそうめん
具材料:豚バラ肉、刻みネギ(少々)、大葉(お好みで)
調味料:めんつゆ、おろしニンニク、塩胡椒、ごま油


こんな感じでした。

まとめると
めんつゆと大葉があればうまい
なのかなと


今回はそうめんのレシピを
投稿サイトのデータから考えてみました

困ったときは
スクレイピングが役立ちますねー

それでは。




さて今回は辞書データを調べて
日本語の単語の数がどうなっているかを
調べてみました。

解説動画はこちら



さて今回使用する辞書データは
こちらのものです
naist-jdic.csv(Mecab用の辞書データ)
(奈良先端科学技術大学院大学 : Nara Institute of Science and Technology)

調べたい方は検索してみてください。

早速これを読み込みします。

import pandas as pd
import codecs

tmp = codecs.open('naist-jdic.csv', 'r', 'euc_jp', 'ignore')
df = pd.read_csv(tmp)
df.shape
(485862, 16)


48万行ほどあるので
結構な数の単語が載っていますね。

1文字目を取り出して集計してみます。
df['行'] = df[' .2'].str[0:1]
df2 = pd.DataFrame(df['行'].value_counts())

for i , row in df2[df2['行']>=10].iterrows():
    print(i,row['行'])
カ 30723
シ 25156
オ 23427
ア 18293
ト 17947
・・・

「か」で始まる単語が多そうですね。

次はこれを行で数えてみます。

dc1={
    'ア':['ア','イ','ウ','エ','オ','ヴ'],
    'カ':['カ','キ','ク','ケ','コ','ガ','ギ','グ','ゲ','ゴ'],
    'サ':['サ','シ','ス','セ','ソ','ザ','ジ','ズ','ゼ','ゾ'],
    'タ':['タ','チ','ツ','テ','ト','ダ','ヂ','ヅ','デ','ド','ッ'],
    'ナ':['ナ','ニ','ヌ','ネ','ノ'],
    'ハ':['ハ','ヒ','フ','ヘ','ホ','バ','ビ','ブ','ベ','ボ','パ','ピ','プ','ペ','ポ'],
    'マ':['マ','ミ','ム','メ','モ'],
    'ヤ':['ヤ','ユ','ヨ','',''],
    'ラ':['ラ','リ','ル','レ','ロ'],
    'ワ':['ワ','ヲ','ン']}
dc2 = {k:{v2:0 for v2 in v} for k,v in dc1.items() }
for i , row in df2[df2['行']>=10].iterrows():
    for k,v in dc2.items():
        if i in v:
            dc2[k][i]=row['行']
            break
for k,v in dc2.items():
    print(k,sum([v2 for k2 , v2 in v.items()]))

結果は・・・

ア 77966
カ 88527
サ 72447
タ 69555
ナ 35274
ハ 65386
マ 41391
ヤ 22425
ラ 7263
ワ 5477

カ行の単語が一番多く
次いでア行、サ行でした。

前半の方に単語が多く載っていそうです。

ラ行やワ行の言葉は
かなり少ないですね。

何でこんなに偏るのか
日本語の成り立ちが気になっちゃいました。

今回は辞書データを調べて
どの行の単語が多いのか
調べてみました。

それでは。

とあるビルに卵が投げつけられたそうなので
検証してみることとしました


解説動画はこちら



さて、この事件のように階下の道から卵を投げて
このような状況になるのか検証してみました。

とあるビルを再現するかのような画像が
twitterにあったのでそちらを参考にすると

卵はビルの三階、柵際10cmあたりの所に着弾

現場のビルの状況は
近場を歩いている人の身長を1.6mと仮定すると
3階の柵まで7.6m , 3階の天井が8.9m

3階の柵の高さを1m、柵の厚みを5cmで
設定してみました

ビルを可視化してみるとこんな感じですかね

# 状況を再現してみる
from matplotlib import pyplot as plt
from math import pi, cos, sin,atan,sqrt
%matplotlib inline

ax = plt.gca()

# 壁
plt.hlines(    0   ,       -2 , 2 , color="gray")
plt.hlines(8.9   , 0.1    , 2 , color="gray")
plt.hlines(7.6   , 0.1    , 0.15 , color="gray")
plt.hlines(6.6   , 0.15 , 2 , color="gray")
plt.vlines(2   , 6.6    , 8.9 , color="gray")
plt.vlines(0.1   ,       0 , 7.6 , color="gray")
plt.vlines(0.15 ,     0 , 7.6 , color="gray")

plt.xlim(-2,10)
plt.ylim(-1,10)
plt.show()
download


ここからは卵を投げることを考えてみましょう。

卵は一般的なLサイズ(重量60g , 断面積12.5cm2)
発射場所はビルの壁際の道から投下するものとします
変数に用意しておきましょう

# '発射時高度 [m] : '
ht = 0
# '質量 [g] : '
mas = 60
# '断面積[cm2] : '
area = 12.5


卵の弾道計算には関数を設定します

これは以前ライフルの弾道計算に用いたものです
[Pythonプログラミング]2km先の敵を狙撃するために弾道計算してみよう


## 弾道計算関数
 
# 固定値
dt = 0.1# 時間刻み[s]
gr = 9.80665 # 重力定数 [m/s2]  初期値 9.80665
cd = 0.3 # 空気抵抗係数(Cd)
airRho =  1.22 # 空気密度 [kg/m3]  初期値 1.22 (1atm , 摂氏15, 湿度50%)
w0 = 0 # 風速(地上) [m/s]
w1 = 0 # 風速(毎100m) [m/s]
 
# 微分計算用関数
def dvx( vx, vy, w, k):
    return -k * (vx - w) * sqrt((vx - w) * (vx - w) + vy*vy)
 
def dvy( vx, vy, w, k, g):
    return -g - k * vy * sqrt((vx - w) * (vx - w) + vy*vy)
 
# 弾道計算関数
def ballistic_calc(mas,area,deg0,vo,ht):
    deg = deg0  / 180 * pi # 角度 [ラジアン]
    _S = area / 10000 # 断面積 [m2]
    _K = 0.5 * _S * cd * airRho / mas *1000 # 抵抗力係数
    _T , _X , _Y , _v = 0 , 0 , ht , vo
    _vx , _vy , _W = _v * cos( deg ) , _v * sin( deg ) , w0 + w1 * (_Y / 100)
    _y_max , _t_max = _Y , 0
    k_x1, k_x2, k_x3, k_x4, k_y1, k_y2, k_y3, k_y4 = 0,0,0,0,0,0,0,0
    vx_2 , vy_2 , x_n2 , y_n2 = 0,0,0,0
    result_x , result_y = [0],[0]
    for i in range(1,101):
        k_x1 = dt * dvx( _vx, _vy, _W, _K )
        k_y1 = dt * dvy( _vx, _vy, _W, _K, gr )
        k_x2 = dt * dvx( _vx + k_x1 / 2, _vy + k_y1 / 2, _W, _K )
        k_y2 = dt * dvy( _vx + k_x1 / 2, _vy + k_y1 / 2, _W, _K, gr )
        k_x3 = dt * dvx( _vx + k_x2 / 2, _vy + k_y2 / 2, _W, _K )
        k_y3 = dt * dvy( _vx + k_x2 / 2, _vy + k_y2 / 2, _W, _K, gr )
        k_x4 = dt * dvx( _vx + k_x3, _vy + k_y3, _W, _K )
        k_y4 = dt * dvy( _vx + k_x3, _vy + k_y3, _W, _K, gr )
        vx_2 = _vx + (k_x1 + 2 * k_x2 + 2 * k_x3 + k_x4) / 6
        vy_2 = _vy + (k_y1 + 2 * k_y2 + 2 * k_y3 + k_y4) / 6
        x_n2 = _X + ( _vx + vx_2 ) / 2 * dt
        y_n2 = _Y + ( _vy + vy_2 ) / 2 * dt
        #print('経過秒数 : {0:.2} , 飛距離 : {1:.05}m , 到達高度 : {2:.05}m'.format(i*dt,x_n2 , y_n2) )
        result_x.append(x_n2)
        result_y.append(y_n2)
        if y_n2<0:  
            #print('break')
            break
        _T = i * dt
        _vx , _vy = vx_2 , vy_2
        _X , _Y = x_n2 , y_n2
        _v = sqrt( _vx * _vx + _vy * _vy )
        deg = atan ( _vy / _vx )
        _W = w0 + w1 * (_Y / 100)
    return result_x , result_y
次に描画用の関数を設定します
def egg_throw_viewer(mas,area,deg0,vo,ht,xlmi,xlmx,ylmi,ylmx):
    ax = plt.gca()
    bx,by = ballistic_calc(mas,area,deg0,vo/3600,ht)
    print('経過秒数 : {0:.2} , 飛距離 : {1:.05}m , 到達最高度 : {2:.05}m'.format((len(bx) - 1)*0.1 , bx[-1] , max(by)))
    print('時速 : {0}km , 角度 : {1:.05}°'.format(vo / 1000 , deg0))

    plt.plot(bx , by , linestyle = "dashed")
    plt.hlines(max(by) , 0 ,1,color="green")

    # 壁
    plt.hlines(    0   ,       -2 , 2 , color="gray")
    plt.hlines(8.9   , 0.1    , 2 , color="gray")
    plt.hlines(7.6   , 0.1    , 0.15 , color="gray")
    plt.hlines(6.6   , 0.15 , 2 , color="gray")
    plt.vlines(2   , 6.6    , 8.9 , color="gray")
    plt.vlines(0.1   ,       0 , 7.6 , color="gray")
    plt.vlines(0.15 ,     0 , 7.6 , color="gray")

    plt.xlim(xlmi,xlmx)
    plt.ylim(ylmi,ylmx)
    plt.show()


用意ができたところで
軽く投げてみましょう。
# 打揚角度 [°]
deg0 = 89.5
# 初速 [km] 
vo = 100000

egg_throw_viewer(mas,area,deg0,vo,ht,-1,1,-1,10)

download-1


めちゃめちゃ上の方に向かって投げますが
角度が浅いとしたの壁に
速度が早すぎると天井や上の壁にぶつかります。


成功パターンはこれでした。
# 打揚角度 [°]
deg0 = 89.6
# 初速 [km] 
vo = 48400

egg_throw_viewer(mas,area,deg0,vo,ht,-1,1,-1,10)
download-2

これならギリ成功できます。


まとめ

卵は一般的なLサイズ(重量60g , 断面積12.5cm2)
壁際から時速 : 48.4km , 角度 : 89.6°で投げると
天井にもぶつからず、柵際10cmあたりの場所に
投げ込むことが出来ました。

1投げで成功させたのは神の領域のコントロール
正に「奇跡」を呼ぶ「軌跡」
だったんでしょうねーーーーーーーーー

きっと1000卵ほど投げて練習したんでしょう
きっとスーパーから卵が無くなりますね
そんなスーパーに近くに住んでいる人が
犯人なんでしょうwwwwwwww

真実は一つです。

それでは。

このページのトップヘ