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

可視化

前回作った関数を進化させてみました。


解説動画はこちら




前回はこちら
動くおっぱい関数

さて
Python言語ではmatplotlibというライブラリで
作図、可視化を行うことができます。

ということなので
曲線を描くことなどが出来てしまうわけです。

前回は黒い曲線で可視化しましたが
それだと味気ないので
色を塗ってみました。

ただし、これは静止画ではありません。
動くんです!!!

なので毎回色ぬりする範囲を
計算しないといけません。

うまく塗る範囲を考えてみました。

出来上がった関数はこちら
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from ipywidgets import interact, FloatSlider, IntSlider
import warnings
warnings.simplefilter('ignore')
%matplotlib inline

def oppai(y,t):
    x_1 = (1.5 * np.exp((0.12*np.sin(t)-0.5) * (y + 0.16 *np.sin(t)) ** 2)) / (1 + np.exp(-20 * (5 * y + np.sin(t))))
    x_2 = ((1.5 + 0.8 * (y + 0.2*np.sin(t)) ** 3) * (1 + np.exp(20 * (5 * y +np.sin(t)))) ** -1)
    x_3 = (1+np.exp(-(100*(y+1)+16*np.sin(t))))
    x_4 = (0.2 * (np.exp(-(y + 1) ** 2) + 1)) / (1 + np.exp(100 * (y + 1) + 16*np.sin(t)))
    x_5 = (0.1 / np.exp(2 * (10 * y + 1.2*(2+np.sin(t))*np.sin(t)) ** 4))
    x = x_1 + (x_2 / x_3) + x_4 + x_5
    return x
 
t = FloatSlider(min=0.1, max=5.0, step=0.1, value=0)
y = np.arange(-3, 3.01, 0.01)
 
@interact(t=t)
def plot_oppai(t):
    x = oppai(y,t)
    plt.figure(figsize=(10,9))
    plt.axes().set_aspect('equal', 'datalim')
    plt.grid()
    b_chiku = (0.1 / np.exp(2 * (10 * y + 1.2*(2+np.sin(t))*np.sin(t)) ** 4))
    b_index = [i for i ,n in enumerate(b_chiku>3.08361524e-003) if n]
    x_2,y_2 = x[b_index],y[b_index]
    plt.axes().set_aspect('equal', 'datalim')
    plt.plot(x, y, '#F5D1B7')
    plt.fill_between(x, y, facecolor='#F5D1B7', alpha=1)
    plt.plot(x_2, y_2, '#F8ABA6')
    plt.fill_between(x_2, y_2, facecolor='#F8ABA6', alpha=1)
    plt.show()
スクリーンショット 2020-07-18 14.54.46

いやー素晴らしい曲線ですよね。

x,y座標に描く曲線
これは前回と一緒です。

色ぬりの指定は
#F5D1B7
のように16進数のwebカラー表記で
書いて指定します。

デフォルトは黒いようなので
肌色を指定しています。

webで検索すれば好みの色に該当する
数値がわかるはずです。

次のポイントは
色ぬりの範囲指定です。

plt.fill_between

これで色ぬりができるんですが
範囲はxの最小値からxの最大値のようですね。

まず全体を肌色で塗り込みます。

後はB地区の計算です。

B地区の範囲を計算している部分は
def oppaiのx_5を計算している部分です。

これが曲線全体における
一番の盛り上がりの部分を
計算しているところです。

このdef oppaiではyの値を元に
x座標を計算して出力していますので
盛り上がり部分の数値がわかれば
塗る範囲も決まります。

この数値を計算すると盛り上がり部分が
ある一定の数以上の値になる部分でした。

ここを
x,yそれぞれをインデックスで取り
その部分だけピンク色を指定して
塗っています。

ようやく完成です。

tの値を変えると
プルンプルン動きます。
タイトルなし

いやー今年一番の感動です。
暇でよかった!!!!

matplotlibであれば
あなたの夢も可視化できるかもしれませんね

今回はこれまでです
それでは。

米失業保険申請者数のデータがあったので
可視化してみました。


解説動画はこちら



データはここにあります。

データソース:2020年03/28までの統計データ

米国労働省:

https://www.dol.gov/ui/data.pdf

アメリカ合衆国 労働省雇用管理局

https://oui.doleta.gov/unemploy/wkclaims/report.asp

これをcsvファイルにしておきます。
列は「N.S.A(日付)」「S.F.(申請数)」の2列分を用意します。




pandas を使ってデータを読み込みします。
import pandas as pd

df = pd.read_table("米失業申請者数データ20200328.csv")
df['day'] = pd.to_datetime(df['N.S.A'], format='%m/%d/%Y')
「N.S.A」列が日付の部分の文字列「m/d/y」形式になっているので
日付のデータに直します。

次に可視化ツールのplotlyの方ですが
普通はインストールされていないと思うので
インストールしていない方はpip install plotly
などでインストールしてください。

以下のコードがこのデータを可視化するコードです。
import plotly
plotly.offline.init_notebook_mode(connected=False)
data = [
    plotly.graph_objs.Scatter(x=df["day"], y=df["S.F."], name="Claims")
]
layout = plotly.graph_objs.Layout(
    width=1000, height=600,
    title="title",
    xaxis={"title":"Years"},
    yaxis={"title":"Claims"},
)
fig = plotly.graph_objs.Figure(data=data, layout=layout)
plotly.offline.iplot(fig, show_link=False) 

日付を横軸(x) , 申請者数を縦軸(y)にあてて
線グラフを作ります。

可視化の結果は・・・
スクリーンショット 2020-04-05 15.56.29

右上にplotlyのツール類が表示され、ズームインアウトや
選択など色々選んで操作できます。

一般的なpandas、matplotlibの可視化では
動かすことができないので
可視化された図表を動かして見ることのできる
plotlyはかなりの優れものです。

データの方を見てみると
1982年とリーマンショックのあった2009年に
かなり多くの申請があったことが見えました。

しかし2020年3月になると
ドーンと跳ね上がって・・・

スクリーンショット 2020-04-05 16.01.20

爆増しているのが見えます。
レポートの数値から見ると
失業申請者数は600万人を超えているみたいですね。

リーマンの時でさえ100万人に満たなかった訳で
今回の影響がどれだけヤバイのかがすぐにわかります。

このデータは3/28のデータ
今日は4/5なのでそこから1週間経ってるいるため
さらに倍増している可能性もあります。

一説によると
アメリカの労働人口の2割ほどが影響を受けているそうで
もし、日本でも同様の事態となると
数十万人 - 100万人単位で
影響を受ける方が増えると予想されます。

特にレストランやバー、映画館、ホテル、スポーツジム
などは営業停止しており
特定の製造業も工場の稼働停止をしています。

リーマンの時は稼働停止までは至っていなかったと思うので
10年前の大不況に比べると
はるかに大きな不況が目の前に来ています。

前回の余波は、自分も食らったので2年くらい
まともな仕事が無かったです。

今回、それを超えるようなことに
ならないことを願うばかりです。

エンジニアの対策としては
現状新規案件が白紙、撤回されたり
内定も取り消されるケースが増えているようです。

フリーランスになったり、転職活動は
かなり厳しくなると予想されるので
今雇用があるなら、そこでじっと騒動が収まるまで
耐えるしかないかなと思います。

頑張って乗り切れば
明るい未来が待っていると思いたい。

それでは。



 

新型コロナウイルスが流行ってきています。

ありがたいことに
データをまとめて頂いている方が
いらっしゃるので
そのデータを用いて可視化をしてみます。


解説動画はこちら




データの提供元は東洋経済新聞社の方のようです。
めちゃくちゃ感謝したいと思います。


新型コロナウイルス国内感染の状況
https://toyokeizai.net/sp/visual/tko/covid19/

制作:荻原 和樹(東洋経済オンライン編集部)
データソース:厚生労働省の報道発表資料。

更新履歴・ソースコード:GitHub
https://github.com/kaz-ogiwara/covid19/

さてそれではデータを可視化をしていきましょう。

まずは
ライブラリの読み込みです。

今回は下記のライブラリを用います。
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline


次に
データの読み込みです。
直接データを読み込み指定します。

file_path = 'https://toyokeizai.net/sp/visual/tko/covid19/csv/data.csv'
df = pd.read_csv(file_path)
df.head()


新No.
旧No.確定日年代性別居住地周囲の患者の発生※濃厚接触者\nの状況
0111/1530代神奈川県なし38名特定、健康観察終了
1221/2440代中国(武漢市)なし32名特定、健康観察終了
2331/2530代中国(武漢市)なし7名特定、健康観察終了
3441/2640代中国(武漢市)No.192名特定、健康観察終了
4551/2840代中国(武漢市)なし3名特定、健康観察終了

こんな感じのローデータですね。

年代や性別などで
日別の感染者の状況をまとめてくれています。


はじめに
性年代別で集計してみましょう。

年代の並びがアレなので先に指定しておきます。
# 年代の並びを指定
order = ['10歳未満', '10代', '20代','30代','40代','50代','60代','70代','80代','90代']
data = pd.crosstab(df['性別'],df['年代'])[order]
data
年代10歳未満10代20代30代40代50代60代70代80代90代
性別
01941112151231
4161017283318120

これをヒートマップにしてみましょう。
ヒートマップはseabornライブラリで可視化できます。
data = pd.crosstab( df['性別'],df['年代'])[order]
ax = sns.heatmap(data,annot=True, fmt="d")
ax.set_ylim(len(data), 0)
plt.title('性年代別感染者数')
plt.show()
download-4

棒グラフにもしてみます。
棒グラフはseabornでは
countplotで可視化できます。
sns.countplot(y="年代", hue="性別",data=df,order=order)
plt.title('性年代別感染者数')
plt.show()

download-3
50-60代の男性の感染者が多いですね。

全体的には女性に比べると
男性の方が感染する方が多いようです。

男性の方がかかりやすいのかどうかは
このデータからは分かりませんね。



次に日別です。

日の並びも先に指定します。
date_order = ['1/15', '1/24', '1/25', '1/26', '1/28', '1/29', '1/30', '1/31','2/4', '2/5', '2/11',
       '2/13', '2/14', '2/15', '2/16', '2/17', '2/18', '2/19', '2/20', '2/21',
       '2/22', '2/23', '2/24', '2/25', '2/26', '2/27', '2/28', '調査中']
plt.figure(figsize=(16,9))
sns.countplot(x="確定日", hue="性別",data=df,order=date_order)
plt.title('日別感染者数')
plt.show()
download-2

日別の性別での可視化です。

男女を積み上げ棒グラフにしてみます。
data = pd.crosstab(df['性別'],df['確定日'])[date_order].T

fig = plt.figure(figsize=(16,9))
ax = fig.add_subplot(1, 1, 1)
ax.bar(date_order, data['男'], label='男')
ax.bar(date_order, data['女'], bottom=data['男'], label='女')
ax.legend()
plt.title('日別感染者数')
plt.show()
download-1
2/22,2/27に感染者数が激増していますね。

グラフを累積にしてみます。
累積のデータを先に作って
それを可視化しています。

numpyのcumsumで累積データを作ることができます。
data = pd.crosstab(df['性別'],df['確定日'])[date_order]
data2 = np.cumsum(data.T)

fig = plt.figure(figsize=(16,9))
ax = fig.add_subplot(1, 1, 1)
ax.bar(date_order, data2['男'], label='男')
ax.bar(date_order, data2['女'], bottom=data2['男'], label='女')
ax.legend()
plt.title('日別累積感染者数')
plt.show()
download


最後に都道府県別でみてみましょう。
data = pd.crosstab(df['居住地'],df['性別'])
data2 = data.sort_values('男',ascending=True)
data2


fig = plt.figure(figsize=(16,9))
ax = fig.add_subplot(1, 1, 1)
ax.barh(data2.index, data2['男'], label='男')
ax.barh(data2.index, data2['女'], left=data2['男'], label='女')
ax.legend()
plt.title('都道府県別感染者数')
plt.show()
download-5

北海道がすごいことになっていますね。

2番目に東京と愛知です。

地域差はかなりあると思いますが
そもそも目には見えないので
どこに潜んでいるかは
正直感じることもできないと思います。

企業の中には
在宅勤務を始める会社も出てきていて

人混みの中に出ないことが
感染予防につながると思いますので
リモートワークはどんどん広がっていくと
いーなーと思っています。

まあ
我々エンジニアは
客先に行くことなんて稀なので
全然在宅でも仕事できちゃいますよね。

2,3月は
大人しくしていた方が
良さそうな気はしますね。

この機会に
Pythonプログラミングを
覚えてみてはいかがでしょうか?

Youtubeなどでも
講座を公開していますので
ぜひみてみてください。

それでは。

グランメゾン東京をみているので
ミシュランの三つ星店が気になってしまいました。

ミシュランの星のついたお店群を
いい感じのライブラリがあったので
可視化してみました。

解説動画はこちら



さて今回使用する可視化のライブラリは
Foliumです。

緯度経度を使用して
いい感じに地図にマッピングできます。

foliumを使うにはインストールしないといけません

まずはインストールしておきましょう。

pip install folium

可視化するにはデータが必要です。

次のようなデータを作りました。
スクリーンショット 2019-12-29 20.31.33

必要な項目としては
お店の名前、星の数、ジャンル、住所、緯度経度などが必要です。

データを集めたら
Foliumを使って可視化です。

地図にマッピングした
HTMLファイルを作成することができます。

実際に作成したコードを貼っておきます。
import folium
from folium.features import CustomIcon
import pandas as pd

stars = {
'一つ星'        :'star1.png',
'二つ星'        :'star2.png',
'三つ星'        :'star3.png',
'ビブグルマン'  :'starbib.png'
}

def makeicon(icon_image):
    icon = CustomIcon(
    icon_image=icon_image,
    icon_size=(30, 30),
    icon_anchor=(30, 30),
    shadow_image='',
    shadow_size=(5, 5),
    shadow_anchor=(4, 4),
    popup_anchor=(-3, -3))
    return icon

def make_maker(r):
    tmp = folium.Marker(
        location = [r['longitude'],r['latitude']], 
        popup    = r['name'] + ' : ' + r['genre'],
        tooltip  = r['name'] + ' : ' + r['genre'] + ' : ' + r['address'].replace('東京都',''),
        icon     = makeicon(stars[r['star']]))
    return tmp

michelin_data = pd.read_table('michelin_data_2020.csv')

plot_map = folium.Map(location=[35.6725175,139.7210145] ,  zoom_start=12)

star1_group = folium.FeatureGroup(name="一つ星").add_to(plot_map)
star2_group = folium.FeatureGroup(name="二つ星").add_to(plot_map)
star3_group = folium.FeatureGroup(name="三つ星").add_to(plot_map)
bib_group   = folium.FeatureGroup(name="ビブグルマン").add_to(plot_map)

for i, r in michelin_data[michelin_data['star']=='一つ星'].iterrows():
    star1_group.add_child(make_maker(r))
for i, r in michelin_data[michelin_data['star']=='二つ星'].iterrows():
    star2_group.add_child(make_maker(r))
for i, r in michelin_data[michelin_data['star']=='三つ星'].iterrows():
    star3_group.add_child(make_maker(r))
for i, r in michelin_data[michelin_data['star']=='ビブグルマン'].iterrows():
    bib_group.add_child(make_maker(r))

folium.LayerControl().add_to(plot_map)
plot_map.save("mishelin_all_maps.html")

コードの説明ですが
まず星を出し分けるためにカスタムアイコンを用います。

CostomIconをインポートしておきます。

folium.Mapで初期マップを作ります。
緯度経度とズーム値を指定して
どこの地点から始めるのかを指定できます。

この初期マップにお店を一軒ずつ加えていきます。

グループ化しておくと
アイコンを点けたり消したり出来るので
星の種別ごとにグループ化しておきます。

グループごとにお店を加えて
LayerControlで出し分けをするための
パーツを作れます。

最後saveでHTMLファイルに出力をして
おしまいです。

出来上がりはこんな感じです。
スクリーンショット 2019-12-29 20.39.52

3つ星のお店だけ表示させました。

Foliumでは星ごとに出し入れ出来るので
右上のパーツを押してみてください。


出来上がりをリンクしておきますね。
ミシュランの3つ星のお店

400店舗ほどあるので
行きたい方はぜひ使ってみてください。

さて
緯度経度を用いた可視化も
Pythonを使えば簡単にできます。

ぜひ試してみてくださいね

グランメゾン東京の最終回も楽しみですね!!!

それでは
 

さて
最近話題に上がった

食べログ分布

に関して
そんなものが存在するのかどうか
検証してみました。

解説動画はこちら



食べログ分布を手元で見たい方は
まずは
データを集めてください。

食べログさんのサイトへ行って
コピペしていただければ
集まるかなーと思います。

集めるのは大変だと思うので
こちらで集めてみました。

手元のデータは
東京の店舗で
約36千件です。

これを可視化してみましょう。

評点で3-4だけに絞っていますが
全店舗だとこうなりました。

zenken

縦が店舗数
横は評点です

3.0-3.1あたりがボリュームが多いですね

おそらくですが
加盟したばかりの店舗というのは
3.0から始まるのではないかと思います。

有る程度コメントなどが加味されて
評点が決まっていくのではないかな?
と思われます。

ということで
有る程度コメントがある店舗に絞って
みてみましょう。

コメント100より多い店舗だけに
絞って可視化してみると・・・

100ken

どうでしょうか

分布が変わりましたね。

有る程度
コメント数などで
評点が定まってくるのだと思います。

この場合はボリュームゾーンが
3.6あたりになりますね。

自然界のデータを無作為に抽出すると
正規分布を取ることが多いので
正規分布も重ねてみましょう。

seiki

赤線は平均を3.6とした際の正規分布です。

どうでしょう
正規分布と比べると
ややスカスカしてる部分が有りますね!!!!

seiki2

これがそのスカスカ部分を囲ってみたものですが

評点に対する店舗数は
正規分布に収束するという仮定だと

もう少し3.6-3.7と
3.8-3.85くらいまでの店舗が
存在していてもおかしくはないのですが
少ないんですねーーー

このやや
歪な感じの分布というのが
「食べログ分布」
ということになります。

有りましたね!!

正規分布などに比べると
いびつさが際立つ分布になるという
結果になりました。

さて
いかがでしたでしょうか?

あと余談ですが
色々みてみると
食べログさんは

「3.0から5.0までの20段階評価である」

ということが分かりました。

なので
3.5と言っても20段階で見れば
それほどでも無いのです。

ただし、店舗の大半は
3.5に到達しないので

3.5も有れば相対的には
良く見えるよ、ということなのでしょう。

単純にコメント数の大小などでは
この評点は決まらない仕組みなのでしょうね

そもそも仕組みを公開してないと思いますし

この評点を信じるのか
自分の舌を信じるのかは
あなた次第です!!

このページのトップヘ