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

プログラミング

グッバイ、イレーーギュラーーーーー
とか叫びたくなる今日この頃

なんとなく
Official髭男dismの歌詞の特徴を見てみたい
と思ってしまいました。

解説動画はこちら





はい
ひげだんさんの歌詞の特徴を見ていきたいですが
事前準備として
1.歌詞を集める
2.形態素解析する
3.テキストファイルにする

この作業が必要でーーーす。

これができましたら
以下のコードを試すことができます。

先ずは
ワードクラウドで歌詞の特徴を可視化する。

ワードクラウドは歌詞に出てくる単語の出現頻度順で
文字を大きさを決めて、1枚にまとめたものです。

コードは
from wordcloud import WordCloud
text_file = open('higedan_list.txt', encoding='utf-8')
text = text_file.read()

#fpath = 'C:/Windows/Fonts/meiryob.ttc'
fpath = '/System/Library/Fonts/ヒラギノ丸ゴ ProN W4.ttc'
stop_words = []
#stop_words = ['そう', 'ない', 'いる', 'する', 'まま', 'よう', 'てる','しまう','それ','なる', 'こと', 'もう', 'いい', 'ある', 'ゆく', 'れる']
wordcloud = WordCloud(background_color='white',font_path=fpath,width=800, 
  height=600, stopwords=set(stop_words),
                      regexp=r"[\w']+"
                     ).generate(text)
wordcloud.to_file('higedan.png')
plt.figure(figsize=(12,9))
plt.imshow(wordcloud)
plt.axis("off")
plt.show()

このコードではfpathでフォントの場所を指定しているので
お使いのマシンのパスにあわせてください。

ワードクラウドの結果は
higedan

する、僕、君
が大きいですねーーー

「僕と君がする」んでしょうね!!!!

何をするかは存じませんが
割と一般的な語句が多いようですね。

歌詞の特徴としてはそこまで
突拍子もない単語は連呼していない訳です。

次に単語の数ではなく
TF-IDFで重要そうな言葉を見てみます。

TF とは Term Frequency の略で、単語の出現頻度を表します。
IDF とは Inverse Document Frequency の略で、逆文書頻度を表します。

これを掛け合わせたものがTF-IDFで

ある単語が多くの文書で出現するほど値は下がり
特定の文書にしか出現しない単語の重要度を上げる役割をします。

TF-IDF値は0-1の間の値を取ります。
重要なキーワードは1に近づきます。

0.25より大きなワードを出してみました。

import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
np.set_printoptions(precision=2)

with open('higedan_list.txt','r') as _f:
    docs = [row.replace('\n','') for row in _f]

vectorizer = TfidfVectorizer() 
X = vectorizer.fit_transform(docs)

words = vectorizer.get_feature_names()
for did, vec in zip(range(len(docs)), X.toarray()):
    print('doc id : ', did)
    for w, tfidf in sorted(enumerate(vec), key=lambda x: x[1], reverse=True):
        if tfidf>0.25:
            wo = words[w]
            print('\t{0:s}\t{1:f}'.format(wo, tfidf))
doc id :  1
	love	0.721728
      ・・・
doc id :  43
	違う	0.329506
	グッ	0.327694
	バイ	0.296629
	もっと	0.265779

doc id1は最近佐藤健さんが主演したドラマの主題歌です。

loveという単語は
他の歌詞にはあまり使われていないけど
ここの歌詞では連呼されてるんでしょうねーー

tf-idf 閾値0.1にすると
「イレギュラー」も含まれてきます。

doc id43は映画の主題歌になった曲です。
「グッバイ」が特徴的な感じしますね。

最後にn-gramをみてみます。

n-gramとはn個の単語の繋がりを表す言葉で
3つの単語であればtrigramになります。
with open('higedan_list.txt','r') as _f:
    docs = [row.replace('\n','').split(' ') for row in _f]

def n_gram(st, n):
    return [st[i:i+n] for i in range(len(st)-n+1)]

counts = {}
for doc in docs:
    trigrams = n_gram(doc,3)
    for tri in trigrams:
        key = ''.join(tri)
        if key in counts:
            counts[key] +=1
        else:
            counts[key] = 1
for k,v in sorted(counts.items(),reverse=True,key=lambda x:x[1]):
    print(k,v)
metellme 16
StandByYou 15
tellmetell 14
・・・・

一番多かったのは英語の歌詞の繋がりでした。
かなり英語の歌詞を多用している感じがあります。

まとめると

・全体的に割と一般的な日本語を多く使用する。
・1つの歌詞でキーワードになるような単語がある
「グッバイ」「イレギュラー」
・割と英語を多用するところもある。

かなーと思います。

歌詞の特徴を見るには
他にもいろんな手法があると思いますが
比較的簡単な方法をご紹介しました。

皆さんもぜひ試してみてください。
それでは。

新型コロナウィルスの感染者増加が止まりません。

このまま行ったらどうなるのかを
データから予測してみました。


解説動画はこちら



さて
今回は予測モデルを使って未来の予測を行います。

用いるライブラリとしては
pandas
matplotlib
fbprophet
になります。

一番初めにデータを読み込んでみましょう。

pandasでデータの提供元(奥村研究所)から
ダウンロードしてデータ化します。
import matplotlib.pyplot as plt
import pandas as pd
%matplotlib inline

df = pd.read_csv("https://oku.edu.mie-u.ac.jp/~okumura/python/data/COVID-19.csv",
                 index_col='Date', parse_dates=['Date'])

これでデータフレームにデータが読み込まれます。

データは4列あるようです。

まずは感染者数の推移を見てみましょう。
df.iloc[0:,0:2].plot(figsize=(16,9))
plt.show()
download

直近での推移が爆裂していますね。
増加率も見てみましょう。
pandasの関数 pct_changeで増加率を算出できます。

df['diff_Global Confirmed'] = df['Global Confirmed'].pct_change()
df['diff_Global Deaths'] = df['Global Deaths'].pct_change()
plt.figure(figsize=(16,9))
plt.bar(df.index,df['diff_Global Confirmed'],alpha=0.3,label="Confirmed")
plt.bar(df.index,df['diff_Global Deaths'],alpha=0.3,label="Deaths")
plt.legend()
plt.show()
download-1

1月末ごろから
中国での大流行があったことが
みて取れます。


中国を抜かした世界の推移を見てみましょう。
別の列を用意してあげます。
df['Confirmed2']=df['Global Confirmed'] - df['China Confirmed']
df['Deaths2']=df['Global Deaths'] - df['China Deaths']
df.iloc[0:,6:8].plot(figsize=(16,9))
plt.show()

download-2

中国以外は3月の頭くらいから
急激に増えているようですね。

増加率も見てみると

df['diff_Confirmed2'] = df['Confirmed2'].pct_change()
df['diff_Deaths2'] = df['Deaths2'].pct_change()
plt.figure(figsize=(16,9))
plt.bar(df.index,df['diff_Confirmed2'],alpha=0.3,label="Confirmed")
plt.bar(df.index,df['diff_Deaths2'],alpha=0.3,label="Deaths")
plt.legend()
plt.show()
download

2月の手前に急激に増えた日がありますね。
ここら辺が起点になっているようです。

次に死亡率です。
df['Death Rate'] = df['Deaths2'] / df['Confirmed2']
plt.figure(figsize=(16,9))
plt.bar(df.index,df['Death Rate'],alpha=0.8,label="Death Rate")
plt.legend()
plt.show()
download-1

直近では5%近くなっていてどんどん上がってきてもいます。

このまま増え続けるとどうなるのか
感染者数の推移を予測してみます。
facebookのprophetを用います。

これはインストールをしないと使えないので
お気をつけください。
from fbprophet import Prophet
import warnings

warnings.simplefilter('ignore',)
model_df = df[['Confirmed2']]
model_df = model_df.reset_index()
model_df = model_df.rename(columns={'Date':'ds','Confirmed2':'y'})
model_df.head()
予測用のデータは
ds,yの2列を用意してあげます。
dsは日付、yは感染者数です。


ds
y
02020-01-204
12020-01-215
22020-01-2310
32020-01-2416
42020-01-2523


モデルを作ります。
model = Prophet()
model.fit(model_df)

最後に予測です。
予測したい日数分の空のデータフレームを用意します。

空のデータフレームを使って
学習したモデルで予測します。
future_df = model.make_future_dataframe(600)
forecast_df = model.predict(future_df)
model.plot(forecast_df)

可視化もできます。
結果は
スクリーンショット 2020-03-29 17.17.04

このままの推移が続くと
今年の終わりには600万人
来年の6月にはその倍くらいにはなっています。

すでに対策を始めていますので
ここまでにはならないと思いたいですが
不要不急の用事がない限りは
あまり出歩かない方が良いでしょうね。

死亡率も5%近くということで
20人のうち一人亡くなると考えると
無視できない確率かなと
個人的には思います。

リモートワークが続いて
ずっと家にいるわけですが

早く
収束してくれることを
願うばかりであります。


今をときめくスーパースター
江頭2:50様と

今年引退するとかしないとか
よく分からないと噂のarashiメンバーの顔を
入れ替えて遊んでみました。



解説動画はこちら


前回やった
opencvのプログラムで
また顔の入れ替えをしてみます。


メンバー5人の

目鼻口を

江頭2:50さんの顔に当て込んでみます。



さてどうなるでしょうか!!!

・・・


・・





どーーーん
matuj

5人とも
ほぼ江頭さんになりますが
顔の特徴が微妙に出ているので
なかなか興味深いですね!!!!

5人結果の詳細は
動画をご覧くださいませ。

それでは

昔どっかの番組で
松崎しげるさんがどんどん黒くなったらいつ気づくのか?
みたいな番組をやっていたのを思い出しました。

今回はopencvを使って
画像の一部分の黒さを濃くするプログラムを作ってみました。

解説動画はこちら



ソースコードはこちら

画像はご自身で用意してくださいね。

import cv2
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact, IntSlider
%matplotlib inline

def detect_red_color(img):
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    hsv_min = np.array([0,64,0])
    hsv_max = np.array([30,255,255])
    mask1 = cv2.inRange(hsv, hsv_min, hsv_max)
    hsv_min = np.array([150,64,0])
    hsv_max = np.array([179,255,255])
    mask2 = cv2.inRange(hsv, hsv_min, hsv_max)    
    mask = mask1 + mask2
    masked_img = cv2.bitwise_and(img, img, mask=mask)
    return masked_img

img = cv2.imread(‘ファイルパス’)
red_masked_img = detect_red_color(img)
mask_img = cv2.cvtColor(red_masked_img, cv2.COLOR_BGR2RGB)

rate1 = IntSlider(min=1 , max=20,step=1,value=20)

@interact(rate1=rate1)
def plot(rate1):
    mask = mask_img  // 20 * rate1 
    mask[mask==0]=255
    height, width, color = img.shape
    for y in range(0, height):
        for x in range(0, width):
            if (mask[y][x] < 240).all():
                img[y][x] = mask[y][x]
    plt.figure(figsize=(16,9))
    plt.imshow(img)
    plt.show()

ファイルパスの部分だけ
ご自身で用意したファイルに差し替えれば
動くと思います。

このプログラムですが
画像の色味を見てその濃さを調整するので
できれば顔以外は真っ黒な方が望ましいです。

スライダーで黒みを調整できます。
初期値は20で
この時は0%です。

スライドを左にずらして行けば
5%ずつ濃くなっていきます。

MAXにしてみると
download-1

ぶっちゃけ誰か分かりません!!!!

プログラム内で何をやっているかと言うと
まず赤みを判定して
顔のマスク部分を作る関数があります。

赤みの部分だけ抽出し
その濃さをスライダーの値から
計算して黒に近づけます。

画像は取り込んだ際に
配列で取り込まれているので
データ上は数値です。

RGB値だと
黒は0,0,0
白は255,255,255です。

単純に数値を
割って小さくすれば
黒に近づきます。

最後にマスク部分だけ
元の画像の色と入れ替えて表示
と言うことだけやっている
シンプルなプログラムです。

他の画像でも
色味を変えることはできますので
色々な方々でやってみてください。

本日はこれまで
それでは

在宅勤務他で暇なので
ドット絵クイズを作ってみました。

問題の動画はこちら



ドット絵を作る
ソースコードはこちら
import cv2
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
%matplotlib inline

def resize1(img):
    height, width = img.shape[:2]
    rate = 720 / height
    n_width = round(width * rate)
    size = (n_width,720)
    return cv2.resize(img, size)

def resize2(img):
    height, width = img.shape[:2]
    rate = 256 / height
    n_width = round(width * rate)
    size = (n_width,256)
    return cv2.resize(img, size)

def center_img(img):
    img2 = np.zeros((720, 1280, 3), np.uint8)
    height, width = img.shape[:2]
    img2[0:height, (1280-width)//2:(1280-width)//2+width] = img
    return img2

def sub_color(src, K):
    Z = src.reshape((-1, 3))
    Z = np.float32(Z)
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
    ret, label, center = cv2.kmeans(
        Z, K, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
    center = np.uint8(center)
    res = center[label.flatten()]
    return res.reshape((src.shape))

def anime_filter(img, K):
    gray = cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)
    edge = cv2.blur(gray, (3, 3))
    edge = cv2.Canny(edge, 50, 150, apertureSize=3)
    edge = cv2.cvtColor(edge, cv2.COLOR_GRAY2BGR)
    img = sub_color(img, K)
    return cv2.subtract(img, edge)

def mosaic(src, ratio=0.25):
    small = cv2.resize(src, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST)
    return cv2.resize(small, src.shape[:2][::-1], interpolation=cv2.INTER_NEAREST)

input_path = 'フォルダのパス'
file_name = 'ファイル名'
input_file_path = input_path + file_name

# ファイル読み込み
img = cv2.imread(input_file_path, cv2.IMREAD_COLOR)
# リサイズ
img = resize1(img)
# アニメ化
img = anime_filter(img, 16)
# モザイク処理(img,粒度)
img = mosaic(img,0.01)
# リサイズ2
img = resize2(img)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
fig, ax = plt.subplots(figsize=(16,9))
ax.imshow(img)
plt.show()



download

やっていることは
画像を取り込んで
リサイズ加工し
ドット絵加工しています。

モザイクの粒度を変えれば、
もう少し判別できる形になります。
小さくすればするほど荒く
大きくすると細かくなります。

ぜひ挑戦してみてください。
分かった秒数を
コメント欄に是非!!!

それでは

このページのトップヘ