- 投稿日:2019-11-15T23:38:11+09:00
PythonでC(++)のヘッダファイル(.h)からマクロ定数を取得
「PythonとC++で定数を共有したい,かつC++側の定数はコンパイル時に確定させたい,かつPythonでも同じ変数を使いたい」という特異な例があったのでメモ.
Pythonから.hで定義された
sample.h#ifndef _PARAM #define _PARAM #define NUM 10 #define epoch 100 #endifと言うような定数を取り出す.今回は,
const int
などで定義したグローバル変数は場合分けがめんどくさいので考えません.def read_header_and_get_macro(header_filepath): with open(header_filepath, mode='r') as f: lst = [s.strip() for s in f.readlines()] comment_flg = False for l in lst: items = l.split() if len(items) != 0 and items[0] == "/*": comment_flg = True continue if comment_flg == True: if len(items) != 0 and items[0] == "*/": comment_flg = False continue if len(items) < 2 or items[0] != "#define": continue if items[1] in globals(): if items[2] == 'true': globals()[items[1]] = True elif items[2] == 'false': globals()[items[1]] = False else: try: globals()[items[1]] = float(items[2]) except ValueError: try: globals()[items[1]] = int(items[2]) except ValueError: globals()[items[1]] = items[2]やっていること
3行目lst = [s.strip() for s in f.readlines()]ファイルを読み込んで行ごとにリストにする.今回は行ごとのリストをとってきてそれをリストで回したけど別に
f.readline()
をfor文回すのは自由4行目comment_flg = FalseC(++)では
/*
から始まって*/
で終わるまでの間は全てコメントなので,これを覚えておくためのフラグ.6行目items = l.split()行の中身について,半角スペースなどでわけられているところを分けたリストを取得.
['#define', 'NUM', '10']みたいなリストがほしかった.
7行目~13行目if len(items) != 0 and items[0] == "/*": comment_flg = True continue if comment_flg == True: if len(items) != 0 and items[0] == "*/": comment_flg = False continue上記の通り,コメントを除く.
14行目~15行目if len(items) < 2 or items[0] != "#define": continue
#define
から始まらない行はマクロを定義していないので除く.16行目~28行目if items[1] in globals(): if items[2] == 'true': globals()[items[1]] = True elif items[2] == 'false': globals()[items[1]] = False else: try: globals()[items[1]] = float(items[2]) except ValueError: try: globals()[items[1]] = int(items[2]) except ValueError: globals()[items[1]] = items[2]今までのもの以外のものが定数のはずです.このとき,
items[1]
には定数名が入っているはずなので,これがグローバル変数として定義されているかチェックするためにitems[1] in globals()
をします.もしも定義されていれば,globals()[items[1]]
でその値がわかるので,変数を強制的に書き換えれば完成.ですが,C++のbool型をPythonにそろえてあげる処理をしているのと,float/int/strの変換も行っています.
- 投稿日:2019-11-15T23:35:09+09:00
python argparse memo
argparse_sample.pyfrom argparse import ArgumentParser if __name__ == "__main__": parser = ArgumentParser() # 必須になる parser.add_argument("must", type=int) # 任意になる # actionにstore_treuでbool引数にあればtrueが格納される。 parser.add_argument("-d", "--do", help="do something", action="store_true") # 途中のハイフンはアンダースコアにすれば使える parser.add_argument("-o", "--this-is-option") args = parser.parse_args() print(args.must) print(args.do) print(args.this_is_option)$ python argparse_sample.py 1 -d -o "hello" 1 True hello
- 投稿日:2019-11-15T23:19:38+09:00
AirpodsProが欲しいので入荷したらLINEに通知する
ことの始まり
AirpodsProの波に乗り遅れた。
先月末発売されたAirpodsProですが、Sonyの例のノイキャンと比較レビューとか見てから買おうと思ってたが、自分が記事を読んだ頃には完売してた、やらかした。
たまに直営のAppleStoreに入荷が入るらしいのでそれを監視して、入荷が入り次第自分のLINEに通知を送る。下調べ
どうやって入庫情報を取得するか問題
どうやら毎朝入荷があった場合ちゃんと更新されているらしい
受け取れる日を確認をクリックするとこの画面が出る。
郵便番号入れると近くのショップ情報が取得できる
この感じだとGETとかPOSTで取れそうなので、ネットワーク見る
めっちゃこれじゃねえかみたいなのがある
デベロッパーツールでResponse見れますが
見た目わかりやすくしたいのでGETとかPOSTしてくれるアプリで情報取ってみる
めっちゃ来たpartsが品番でlocationが郵便番号
レスポンスをちゃんと見る
さっき返ってきたレンスポンスは一店舗でこれだけ返ってくる。
response{ "head": { "status": "200", "data": {} }, "body": { "stores": [ { "storeEmail": "shinsaibashi@apple.com", "storeName": "心斎橋", "reservationUrl": "http://www.apple.com/jp/retail/shinsaibashi", "makeReservationUrl": "http://www.apple.com/jp/retail/shinsaibashi", "state": "大阪府", "storeImageUrl": "https://rtlimages.apple.com/cmc/dieter/store/4_3/R091.png?resize=828:*&output-format=jpg", "country": "JP", "city": "大阪市", "storeNumber": "R091", "partsAvailability": { "MWP22J/A": { "storePickEligible": true, "storeSearchEnabled": true, "storeSelectionEnabled": true, "storePickupQuote": "土 2019/12/07 Apple 心斎橋", "pickupSearchQuote": "受け取れる日:<br/>土 2019/12/07", "storePickupLabel": "受取日:", "partNumber": "MWP22J/A", "purchaseOption": "", "ctoOptions": "", "storePickupLinkText": "受け取れる日を確認", "storePickupProductTitle": "AirPods Pro", "pickupDisplay": "ships-to-store" } }, "phoneNumber": "06-4963-4500", "address": { "address": "Apple 心斎橋", "address3": "アーバンBLD心斎橋", "address2": "中央区西心斎橋1-5-5", "postalCode": "542-0086" }, "hoursUrl": "http://www.apple.com/jp/retail/shinsaibashi", "storeHours": { "storeHoursText": "営業時間", "bopisPickupDays": "日数", "bopisPickupHours": "時間", "hours": [ { "storeTimings": "10:00~21:00", "storeDays": "月~日:" } ] }, "storelatitude": 34.672, "storelongitude": 135.50007, "storedistance": 3.44, "storeDistanceWithUnit": "3.44 km", "storeDistanceVoText": "542-0086からの距離:3.44 km", "storelistnumber": 1, "storeListNumber": 1 } ----------------いっぱい下に続く----------------
storePickupQuote
だけ取得できれば問題なさそうPython で書いてく
GETするだけならrequestsだけで実装できるので適当に書く
在庫情報の取得def get_store_status(_parts, _location): arrival = [] url = "https://www.apple.com/jp/shop/retail/pickup-message" param = {"parts.0": _parts, "location": _location} response = requests.get(url, params=param) json_data = json.loads(response.text) stores = json_data['body']['stores'] for store in stores: store_pickup = store['partsAvailability'][_parts]['storePickupQuote'] if '本日' in store_pickup: arrival.append({'店舗':store['address']['address'], '郵便番号':store['address']['postalCode']}) return arrivalとりあえず書いた、適当に解説すると
帰ってきたjsonを辞書に入れて
入荷が入った店舗は日付ではなく本日が入っているのでそういう判定をして
本日があれば通す実際に在庫情報がいつ更新されるかはわからないので、
6時〜10時の間に1分に1回リクエストさせる。def start_job(): parts = {'AirpodsPro':'MWP22J/A', 'Airpods':'MV7N2J/A'} location = '530-0000' end_stamp = datetime.now().timestamp() + (60 * 60 * 4) while True: now = datetime.now().timestamp() arrival = get_store_status(parts['AirpodsPro'], location) if arrival or now > end_stamp: line_notif(arrival) break time.sleep(60) def trigger(): schedule.every().day.at('06:00').do(start_job) while True: schedule.run_pending() time.sleep(1)在庫があればループ抜けて通知
なければ10時までオリョクルLINEに通知する
LINEはNotifyののやつ登録して自分に送る
これを参考にさせて頂く - PythonでLINEに通知を送るdef line_notify(stores): line_notify_token = 'アクセストークン' line_notify_api = 'https://notify-api.line.me/api/notify' if stores: strings='' for s in stores: strings += f''' 店舗: {s['店舗']} 郵便番号: {s['郵便番号']}\n''' message = f''' AirpodsProが入荷されました。 対象店舗:{strings} ショッピングカート:https://www.apple.com/jp/shop/bag ''' payload = {'message': message} headers = {'Authorization': 'Bearer ' + line_notify_token} line_notify = requests.post(line_notify_api, data=payload, headers=headers)とりあえず入荷があればこれでLINEに通知くる
ショッピングカートのURL貼っておけばそのまま購入できる。
(前もって購入する端末とブラウザでショッピングカートに入れておく必要はある)入荷されているのに来なかったら悲しいので動くのか試しておく
airpodsはあるのでこいつで試す
さっきの辞書にAirpodsの情報入れといたのでそれを使うarrival = get_store_status(parts['Airpods'], location)これで実行する。
通知が来たのでオッケー
最後に
LINE Notify めっちゃ便利ですね、これ今後もめっちゃ使えそう。
一番の問題は朝起きているかなんですけどね
- 投稿日:2019-11-15T23:06:27+09:00
多変量正規分布に従う乱数の背景にはCholesky分解がいた
1. 数学的背景
- 確率変数の変数変換
- 多次元正規分布の導出
- 分散共分散行列の性質
- Cholesky分解のアルゴリズム
を解説する。
1.1. 多次元確率分布の変数変換
確率変数
\begin{eqnarray} X_1,\ X_2,\ \cdots ,\ X_n \end{eqnarray}を、確率変数
\begin{eqnarray} Y_1,\ Y_2,\ \cdots ,\ Y_n \end{eqnarray}に変換する。
ただし、$X$と$Y$は、それぞれ\begin{eqnarray} &f_X&\left(x_1,\ x_2,\ \cdots ,\ x_n\right)\\ &f_Y&\left(y_1,\ y_2,\ \cdots ,\ y_n\right) \end{eqnarray}の確率密度関数をもつものとする。
各$Y$を、$X$の全単射として、
\begin{eqnarray} \begin{cases} Y_1 = h_1\left(X_1,\ X_2,\ \cdots ,\ X_n\right)&\\ Y_2 = h_2\left(X_1,\ X_2,\ \cdots ,\ X_n\right)&\\ \ \vdots &\\ Y_n = h_n\left(X_1,\ X_2,\ \cdots ,\ X_n\right) \end{cases} \end{eqnarray}と表す。各$h_i$は全単射ゆえ逆関数が存在し、
\begin{eqnarray} \begin{cases} X_1 = g_1\left(Y_1,\ Y_2,\ \cdots ,\ Y_n\right)&\\ X_2 = g_2\left(Y_1,\ Y_2,\ \cdots ,\ Y_n\right)&\\ \ \vdots &\\ X_n = g_n\left(Y_1,\ Y_2,\ \cdots ,\ Y_n\right) \end{cases} \end{eqnarray}と表される。$n$次元実数空間の任意の部分集合$D$に対して、積分の変数変換を施して、
\begin{eqnarray} &\int\cdots\int_D& f_X\left(x_1,x_2,\cdots ,x_n\right) dx_1dx_2\cdots dx_n \nonumber \\ = &\int\cdots\int_D& f_X\left(y_1,y_2,\cdots ,y_n\right)\left|\frac{\partial\left( x_1,x_2,\cdots x_n\right) }{\partial\left(y_1,y_2,\cdots y_n\right) }\right| dy_1dy_2\cdots dy_n \end{eqnarray}が成立する。
ただし、ヤコビアンを、\begin{eqnarray} \left|\frac{\partial\left( x_1,x_2,\cdots x_n\right) }{\partial\left(y_1,y_2,\cdots y_n\right) }\right| = \begin{pmatrix} \frac{\partial g_1}{\partial y_1}&\frac{\partial g_1}{\partial y_2}&\cdots&\frac{\partial g_1}{\partial y_n}\\ \frac{\partial g_2}{\partial y_1}&\ddots&&\vdots\\ \vdots &&\ddots&\vdots\\ \frac{\partial g_n}{\partial y_1}&\cdots&\cdots&\frac{\partial g_n}{\partial y_n} \end{pmatrix} \end{eqnarray}と表記している。
ここから、確率密度関数の変換式
\begin{eqnarray} f_Y\left(y_1,y_2,\cdots ,y_n\right) = f_X\left(y_1,y_2,\cdots ,y_n\right)\left|\frac{\partial\left( x_1,x_2,\cdots x_n\right) }{\partial\left(y_1,y_2,\cdots y_n\right) }\right| \end{eqnarray}を得る。
1.2. 多次元正規分布の導出
$1$次元標準正規分布を、$N\left(0,1\right)$と表記する。
互いに独立な$n$個の標準正規分布
\begin{eqnarray} Z_1,\ Z_2,\cdots ,\ Z_n \sim N\left(0,1\right)\ \textrm{i.i.d} \end{eqnarray}を定める。
これらの同時密度関数は、独立分布であるため積で表され、\begin{eqnarray} f_Z\left(z\right) = \frac{1}{\left(2\pi\right)^{n/2}} \exp\left(-\frac{1}{2}z^Tz\right) \end{eqnarray}となる。
ここで、
\begin{eqnarray} X &=& AZ + \mu \end{eqnarray}の変数変換を施す。
ただし、$Z,X$は$n$次元確率変数ベクトル、$A$は$n\times n$行列、$\mu$は$n$次元ベクトルである。\begin{eqnarray} X&=&\left(X_1,\ X_2,\ \cdots\ X_n\right)^{\mathrm{T}} \nonumber \\ Z&=&\left(Z_1,\ Z_2,\ \cdots\ Z_n\right)^{\mathrm{T}} \nonumber \\ A&=& \begin{pmatrix} a_{1,1}&a_{1,2}&\cdots&a_{1,n}\\ a_{2,2}&\ddots&&\vdots\\ \vdots&&\ddots&\vdots\\ a_{n,1}&\cdots&\cdots&a_{n,n} \end{pmatrix} \nonumber \\ \mu&=&\left(\mu_1,\ \mu_2,\ \cdots\ \mu_n\right)^{\mathrm{T}} \nonumber \end{eqnarray}変数変換のヤコビアンは、
\begin{eqnarray} \left|\frac{\partial\left( x_1,x_2,\cdots x_n\right) }{\partial\left(z_1,z_2,\cdots z_n\right) }\right| &=& \det\left( A\right) \end{eqnarray}より、
\begin{eqnarray} \left|\frac{\partial\left( z_1,z_2,\cdots z_n\right) }{\partial\left(x_1,x_2,\cdots x_n\right) }\right| &=& \frac{1}{\det\left( A\right)} \end{eqnarray}を得る。
よって、$X$の同時密度関数は、
\begin{eqnarray} f_X\left(x\right)&=&f_Z\left(A^{\mathrm{T}}\left(x-\mu\right)\right)\frac{1}{\det\left(A\right)} \nonumber \\ &=&\frac{1}{\left(2\pi\right)^{n/2}\det\left(A\right)}\exp\left\{-\frac{1}{2}\left(x-\mu\right)^{\mathrm{T}}AA^{\mathrm{T}}\left(x-\mu\right)\right\} \end{eqnarray}となる。
変換された確率変数の平均ベクトルと、分散共分散行列は、
\begin{eqnarray} E\left[X\right]&=&AE\left[Z\right]+\mu \nonumber \\ &=&\mu \\ Cov\left(X\right)&=&E\left[\left(X-\mu\right)\left(X-\mu\right)^{\mathrm{T}}\right] \nonumber \\ &=&E\left[AZZ^{\mathrm{T}}A^{\mathrm{T}}\right] \nonumber \\ &=&AE\left[Z\right] E\left[Z^{\mathrm{T}}\right] A^{\mathrm{T}} \nonumber \\ &=&AA^{\mathrm{T}} \end{eqnarray}分散共分散行列を、
\begin{eqnarray} \Sigma = AA^{\mathrm{T}} \end{eqnarray}と表記する。
これを適用して、多次元正規分布の同時密度関数
\begin{eqnarray} f_X\left(x\right) &=&\frac{1}{\left(2\pi\right)^{n/2}\det\left(A\right)}\exp\left\{-\frac{1}{2}\left(x-\mu\right)^{\mathrm{T}}\left(AA^{\mathrm{T}}\right)^{-1}\left(x-\mu\right)\right\} \nonumber \\ &=&\frac{1}{\left(2\pi\right)^{n/2}\det\left(\Sigma\right)^{1/2}}\exp\left\{-\frac{1}{2}\left(x-\mu\right)^{\mathrm{T}}\Sigma^{-1}\left(x-\mu\right)\right\} \end{eqnarray}を得る。
1.3. 分散共分散行列の性質
分散共分散行列からCholesky分解によって乱数列を生成するにあたり、分散共分散行列が正定値であるという制約条件が必要になる。
ここでは、一般に分散共分散行列の性質を確認し、Cholesky分解可能性を確かめる。
ここで、線形代数の知識を確認する。
行列の半正定値性
以下は同値。
- $n\times n$対称行列$A$が半正定値である
- 任意のベクトル$x$に対して、$x^\mathrm{T}Ax\geq 0$
- $A$の任意の主小行列式が非負
- 全ての固有値は非負行列の正定値性
以下は同値。
- $n\times n$対称行列$A$が正定値である
- 任意のベクトル$x$に対して、$x^\mathrm{T}Ax> 0$
- $A$の任意の主小行列式が正
- 全ての固有値は正以下の主張を証明する。
分散共分散行列$\Sigma$は半正定値対称行列である。分散$\sigma_i$、共分散$\rho_{i,j}$を成分とする$n\times n$分散共分散行列を$\Sigma$とする。
$\rho_{i,j}=\rho_{j,i}$より、$\Sigma$は対称行列である。
$a$を任意の$n$次元定数ベクトルとする。\begin{eqnarray} a^{\mathrm{T}}\Sigma a &=& a^{\mathrm{T}}E\left[\left(X-E\left[X\right]\right)\left(X-E\left[X\right]\right)^{\mathrm{T}}\right]a \nonumber \\ &=&E\left[a^{\mathrm{T}}\left(X-E\left[X\right]\right)\left(X-E\left[X\right]\right)^{\mathrm{T}}a\right] \nonumber \\ &=&E\left[\langle a,X-E\left[X\right]\rangle^2\right] \nonumber \\ &\geq&0 \nonumber \end{eqnarray}よって、$\Sigma$は半正定値である。
実用上、分散共分散行列は多くの場合で正定値対称となることが期待されるが、
正定値対称とならない場合は、以下の乱数生成ができないため注意。1.4. Cholesky分解
正定値対称行列$A$に対して、下三角行列$L$を用いて分解を与えることを、Cholesky分解という。
\begin{eqnarray} A&=&LL^{\mathrm{T}} \\ \nonumber \\ A&=& \begin{pmatrix} a_{1,1}&a_{1,2}&\cdots&a_{1,n}\\ a_{2,2}&\ddots&&\vdots\\ \vdots&&\ddots&\vdots\\ a_{n,1}&\cdots&\cdots&a_{n,n} \end{pmatrix} \nonumber \\ L&=& \begin{pmatrix} l_{1,1}&0&\cdots&\cdots&0\\ l_{2,1}&l_{2,2}&0&&\vdots\\ \vdots&&\ddots&\ddots&\vdots\\ \vdots&&&l_{n-1,n-1}&0\\ l_{n,1}&\cdots&\cdots&l_{n,n-1}&l_{n,n} \end{pmatrix} \nonumber \end{eqnarray}Cholesky分解の構成法は、以下の通りである。
\begin{eqnarray} l_{i,i}&=&\sqrt{a_{i,i}-\sum_{k=1}^{i-1}l_{i,k}^2}\ \ \ \ \ \ \left(\textrm{for}\ i=1,\cdots ,n\right) \\ l_{j,i}&=&\left(a_{j,i}-\sum_{k=1}^{i-1}l_{j,k}\ l_{i,k}\right)/l_{i,i}\ \ \ \left(\textrm{for}\ j=i+1,\cdots ,n\right) \end{eqnarray}1.5. Cholesky分解による多変量正規分布に従う乱数列の生成
分散$\sigma_i$、共分散$\rho_{i,j}$を成分とする分散共分散行列$\Sigma$に対し、正定値の制約を設ける。
$\Sigma$に対してCholesky分解を適用して、$A=L$(下三角行列)を得る。
\begin{eqnarray} x&=&Lz+\mu \\ \nonumber \\ L&=& \begin{pmatrix} l_{1,1}&0&\cdots&\cdots&0\\ l_{2,1}&l_{2,2}&0&&\vdots\\ \vdots&&\ddots&\ddots&\vdots\\ \vdots&&&l_{n-1,n-1}&0\\ l_{n,1}&\cdots&\cdots&l_{n,n-1}&l_{n,n} \end{pmatrix} \nonumber \\ l_{i,i}&=&\sqrt{\sigma_{i}-\sum_{k=1}^{i-1}l_{i,k}^2}\ \ \ \ \ \ \left(\textrm{for}\ i=1,\cdots ,n\right) \nonumber \\ l_{j,i}&=&\left(\rho_{j,i}-\sum_{k=1}^{i-1}l_{j,k}\ l_{i,k}\right)/l_{i,i}\ \ \ \left(\textrm{for}\ j=i+1,\cdots ,n\right) \nonumber \end{eqnarray}2. 実装
multivariate_normal_distribution.pyimport numpy as np #平均 mu = np.array([[2], [3]]) #分散共分散行列 cov = np.array([[1,0.2], 0.2,1]]) L = np.linalg.cholesky(cov) dim = len(cov) random_list=[] for i in range(n): z = np.random.randn(dim,1) random_list.append((np.dot(L,z)+mu).reshape(1,-1).tolist()[0])
- 投稿日:2019-11-15T23:06:27+09:00
多変量正規分布に従う乱数生成の背景にはCholesky分解がいた
分散共分散行列のChoresky分解で、独立な標準正規分布に従う乱数を、多変量正規分布に従う乱数に変換できる。
どゆこと?1. 数学的背景
- 確率変数の変数変換
- 多次元正規分布の導出
- 分散共分散行列の性質
- Cholesky分解のアルゴリズム
を解説する。
1.1. 多次元確率分布の変数変換
確率変数
\begin{eqnarray} X_1,\ X_2,\ \cdots ,\ X_n \end{eqnarray}を、確率変数
\begin{eqnarray} Y_1,\ Y_2,\ \cdots ,\ Y_n \end{eqnarray}に変換する。
ただし、$X$と$Y$は、それぞれ\begin{eqnarray} &f_X&\left(x_1,\ x_2,\ \cdots ,\ x_n\right)\\ &f_Y&\left(y_1,\ y_2,\ \cdots ,\ y_n\right) \end{eqnarray}の確率密度関数をもつものとする。
各$Y$を、$X$の全単射として、
\begin{eqnarray} \begin{cases} Y_1 = h_1\left(X_1,\ X_2,\ \cdots ,\ X_n\right)&\\ Y_2 = h_2\left(X_1,\ X_2,\ \cdots ,\ X_n\right)&\\ \ \vdots &\\ Y_n = h_n\left(X_1,\ X_2,\ \cdots ,\ X_n\right) \end{cases} \end{eqnarray}と表す。各$h_i$は全単射ゆえ逆関数が存在し、
\begin{eqnarray} \begin{cases} X_1 = g_1\left(Y_1,\ Y_2,\ \cdots ,\ Y_n\right)&\\ X_2 = g_2\left(Y_1,\ Y_2,\ \cdots ,\ Y_n\right)&\\ \ \vdots &\\ X_n = g_n\left(Y_1,\ Y_2,\ \cdots ,\ Y_n\right) \end{cases} \end{eqnarray}と表される。$n$次元実数空間の任意の部分集合$D$に対して、積分の変数変換を施して、
\begin{eqnarray} &\int\cdots\int_D& f_X\left(x_1,x_2,\cdots ,x_n\right) dx_1dx_2\cdots dx_n \nonumber \\ = &\int\cdots\int_D& f_X\left(y_1,y_2,\cdots ,y_n\right)\left|\frac{\partial\left( x_1,x_2,\cdots x_n\right) }{\partial\left(y_1,y_2,\cdots y_n\right) }\right| dy_1dy_2\cdots dy_n \end{eqnarray}が成立する。
ただし、ヤコビアンを、\begin{eqnarray} \left|\frac{\partial\left( x_1,x_2,\cdots x_n\right) }{\partial\left(y_1,y_2,\cdots y_n\right) }\right| = \begin{pmatrix} \frac{\partial g_1}{\partial y_1}&\frac{\partial g_1}{\partial y_2}&\cdots&\frac{\partial g_1}{\partial y_n}\\ \frac{\partial g_2}{\partial y_1}&\ddots&&\vdots\\ \vdots &&\ddots&\vdots\\ \frac{\partial g_n}{\partial y_1}&\cdots&\cdots&\frac{\partial g_n}{\partial y_n} \end{pmatrix} \end{eqnarray}と表記している。
ここから、確率密度関数の変換式
\begin{eqnarray} f_Y\left(y_1,y_2,\cdots ,y_n\right) = f_X\left(y_1,y_2,\cdots ,y_n\right)\left|\frac{\partial\left( x_1,x_2,\cdots x_n\right) }{\partial\left(y_1,y_2,\cdots y_n\right) }\right| \end{eqnarray}を得る。
1.2. 多次元正規分布の導出
$1$次元標準正規分布を、$N\left(0,1\right)$と表記する。
互いに独立な$n$個の標準正規分布
\begin{eqnarray} Z_1,\ Z_2,\cdots ,\ Z_n \sim N\left(0,1\right)\ \textrm{i.i.d} \end{eqnarray}を定める。
これらの同時密度関数は、独立分布であるため積で表され、\begin{eqnarray} f_Z\left(z\right) = \frac{1}{\left(2\pi\right)^{n/2}} \exp\left(-\frac{1}{2}z^Tz\right) \end{eqnarray}となる。
ここで、
\begin{eqnarray} X &=& AZ + \mu \end{eqnarray}の変数変換を施す。
ただし、$Z,X$は$n$次元確率変数ベクトル、$A$は$n\times n$行列、$\mu$は$n$次元ベクトルである。\begin{eqnarray} X&=&\left(X_1,\ X_2,\ \cdots\ X_n\right)^{\mathrm{T}} \nonumber \\ Z&=&\left(Z_1,\ Z_2,\ \cdots\ Z_n\right)^{\mathrm{T}} \nonumber \\ A&=& \begin{pmatrix} a_{1,1}&a_{1,2}&\cdots&a_{1,n}\\ a_{2,2}&\ddots&&\vdots\\ \vdots&&\ddots&\vdots\\ a_{n,1}&\cdots&\cdots&a_{n,n} \end{pmatrix} \nonumber \\ \mu&=&\left(\mu_1,\ \mu_2,\ \cdots\ \mu_n\right)^{\mathrm{T}} \nonumber \end{eqnarray}変数変換のヤコビアンは、
\begin{eqnarray} \left|\frac{\partial\left( x_1,x_2,\cdots x_n\right) }{\partial\left(z_1,z_2,\cdots z_n\right) }\right| &=& \det\left( A\right) \end{eqnarray}より、
\begin{eqnarray} \left|\frac{\partial\left( z_1,z_2,\cdots z_n\right) }{\partial\left(x_1,x_2,\cdots x_n\right) }\right| &=& \frac{1}{\det\left( A\right)} \end{eqnarray}を得る。
よって、$X$の同時密度関数は、
\begin{eqnarray} f_X\left(x\right)&=&f_Z\left(A^{\mathrm{T}}\left(x-\mu\right)\right)\frac{1}{\det\left(A\right)} \nonumber \\ &=&\frac{1}{\left(2\pi\right)^{n/2}\det\left(A\right)}\exp\left\{-\frac{1}{2}\left(x-\mu\right)^{\mathrm{T}}AA^{\mathrm{T}}\left(x-\mu\right)\right\} \end{eqnarray}となる。
変換された確率変数の平均ベクトルと、分散共分散行列は、
\begin{eqnarray} E\left[X\right]&=&AE\left[Z\right]+\mu \nonumber \\ &=&\mu \\ Cov\left(X\right)&=&E\left[\left(X-\mu\right)\left(X-\mu\right)^{\mathrm{T}}\right] \nonumber \\ &=&E\left[AZZ^{\mathrm{T}}A^{\mathrm{T}}\right] \nonumber \\ &=&AE\left[Z\right] E\left[Z^{\mathrm{T}}\right] A^{\mathrm{T}} \nonumber \\ &=&AA^{\mathrm{T}} \end{eqnarray}分散共分散行列を、
\begin{eqnarray} \Sigma = AA^{\mathrm{T}} \end{eqnarray}と表記する。
これを適用して、多次元正規分布の同時密度関数
\begin{eqnarray} f_X\left(x\right) &=&\frac{1}{\left(2\pi\right)^{n/2}\det\left(A\right)}\exp\left\{-\frac{1}{2}\left(x-\mu\right)^{\mathrm{T}}\left(AA^{\mathrm{T}}\right)^{-1}\left(x-\mu\right)\right\} \nonumber \\ &=&\frac{1}{\left(2\pi\right)^{n/2}\det\left(\Sigma\right)^{1/2}}\exp\left\{-\frac{1}{2}\left(x-\mu\right)^{\mathrm{T}}\Sigma^{-1}\left(x-\mu\right)\right\} \end{eqnarray}を得る。
1.3. 分散共分散行列の性質
分散共分散行列からCholesky分解によって乱数列を生成するにあたり、分散共分散行列が正定値であるという制約条件が必要になる。
ここでは、一般に分散共分散行列の性質を確認し、Cholesky分解可能性を確かめる。
ここで、線形代数の知識を確認する。
行列の半正定値性
以下は同値。
- $n\times n$対称行列$A$が半正定値である
- 任意のベクトル$x$に対して、$x^\mathrm{T}Ax\geq 0$
- $A$の任意の主小行列式が非負
- 全ての固有値は非負行列の正定値性
以下は同値。
- $n\times n$対称行列$A$が正定値である
- 任意のベクトル$x$に対して、$x^\mathrm{T}Ax> 0$
- $A$の任意の主小行列式が正
- 全ての固有値は正以下の主張を証明する。
分散共分散行列$\Sigma$は半正定値対称行列である。分散$\sigma_i$、共分散$\rho_{i,j}$を成分とする$n\times n$分散共分散行列を$\Sigma$とする。
$\rho_{i,j}=\rho_{j,i}$より、$\Sigma$は対称行列である。
$a$を任意の$n$次元定数ベクトルとする。\begin{eqnarray} a^{\mathrm{T}}\Sigma a &=& a^{\mathrm{T}}E\left[\left(X-E\left[X\right]\right)\left(X-E\left[X\right]\right)^{\mathrm{T}}\right]a \nonumber \\ &=&E\left[a^{\mathrm{T}}\left(X-E\left[X\right]\right)\left(X-E\left[X\right]\right)^{\mathrm{T}}a\right] \nonumber \\ &=&E\left[\langle a,X-E\left[X\right]\rangle^2\right] \nonumber \\ &\geq&0 \nonumber \end{eqnarray}よって、$\Sigma$は半正定値である。
実用上、分散共分散行列は多くの場合で正定値対称となることが期待されるが、
正定値対称とならない場合は、以下の乱数生成ができないため注意。1.4. Cholesky分解
正定値対称行列$A$に対して、下三角行列$L$を用いて分解を与えることを、Cholesky分解という。
\begin{eqnarray} A&=&LL^{\mathrm{T}} \\ \nonumber \\ A&=& \begin{pmatrix} a_{1,1}&a_{1,2}&\cdots&a_{1,n}\\ a_{2,2}&\ddots&&\vdots\\ \vdots&&\ddots&\vdots\\ a_{n,1}&\cdots&\cdots&a_{n,n} \end{pmatrix} \nonumber \\ L&=& \begin{pmatrix} l_{1,1}&0&\cdots&\cdots&0\\ l_{2,1}&l_{2,2}&0&&\vdots\\ \vdots&&\ddots&\ddots&\vdots\\ \vdots&&&l_{n-1,n-1}&0\\ l_{n,1}&\cdots&\cdots&l_{n,n-1}&l_{n,n} \end{pmatrix} \nonumber \end{eqnarray}Cholesky分解の構成法は、以下の通りである。
\begin{eqnarray} l_{i,i}&=&\sqrt{a_{i,i}-\sum_{k=1}^{i-1}l_{i,k}^2}\ \ \ \ \ \ \left(\textrm{for}\ i=1,\cdots ,n\right) \\ l_{j,i}&=&\left(a_{j,i}-\sum_{k=1}^{i-1}l_{j,k}\ l_{i,k}\right)/l_{i,i}\ \ \ \left(\textrm{for}\ j=i+1,\cdots ,n\right) \end{eqnarray}1.5. Cholesky分解による多変量正規分布に従う乱数列の生成
分散$\sigma_i$、共分散$\rho_{i,j}$を成分とする分散共分散行列$\Sigma$に対し、正定値の制約を設ける。
$\Sigma$に対してCholesky分解を適用して、$A=L$(下三角行列)を得る。
\begin{eqnarray} x&=&Lz+\mu \\ \nonumber \\ L&=& \begin{pmatrix} l_{1,1}&0&\cdots&\cdots&0\\ l_{2,1}&l_{2,2}&0&&\vdots\\ \vdots&&\ddots&\ddots&\vdots\\ \vdots&&&l_{n-1,n-1}&0\\ l_{n,1}&\cdots&\cdots&l_{n,n-1}&l_{n,n} \end{pmatrix} \nonumber \\ l_{i,i}&=&\sqrt{\sigma_{i}-\sum_{k=1}^{i-1}l_{i,k}^2}\ \ \ \ \ \ \left(\textrm{for}\ i=1,\cdots ,n\right) \nonumber \\ l_{j,i}&=&\left(\rho_{j,i}-\sum_{k=1}^{i-1}l_{j,k}\ l_{i,k}\right)/l_{i,i}\ \ \ \left(\textrm{for}\ j=i+1,\cdots ,n\right) \nonumber \end{eqnarray}2. 実装
multivariate_normal_distribution.pyimport numpy as np #平均 mu = np.array([[2], [3]]) #分散共分散行列 cov = np.array([[1,0.2], 0.2,1]]) L = np.linalg.cholesky(cov) dim = len(cov) random_list=[] for i in range(n): z = np.random.randn(dim,1) random_list.append((np.dot(L,z)+mu).reshape(1,-1).tolist()[0])
- 投稿日:2019-11-15T21:55:04+09:00
Pythonで標準入力を使って生徒の成績を管理するツールを作るには?
標準入力を使って生徒の成績を管理するツールを作ってください。
“save 生徒名 点数“とすると、その生徒の点数を保存。
“save 生徒名 点数“とした場合、
生徒名がすでに保存されている時は、点数を上書きするか警告文を出して、yes/noで上書きの選択を行う。
“get 生徒名“とするとその生徒の点数を表示。
“get 生徒名“を行った場合、生徒が登録されていない場合はErrorと出力させて処理を継続
“quit” とするとプログラムが終了する。
“average” すでに保存されいる生徒全員の平均点
“登録されている生徒XX人の平均点はXX.XX点です”条件としてsplit関数を使うのと辞書使うことです。
- 投稿日:2019-11-15T21:01:35+09:00
【pandas】文字列をDataFrameに展開
かゆいところに手が届くpandasレシピ集No.1
かゆいこと
「カテゴリ名(index)」と「値(value)」が文字列として1つの要素となってしまっている配列・DataFrameをなんとかしたい。
各カテゴリ(index)をcolumn名とする列に値を割り振ろう。
ID クソデカ文字列 0 A 0, B 1, C 2 1 B 3, D 4 2 A 5, C 6 3 C 7, D 8 ↑この↑クソデカ文字列を↓こう↓したい。
ID A B C D 0 0 1 2 0 1 0 3 0 4 2 5 0 6 0 3 0 0 7 8 レシピ
各カテゴリは既知とします。
未知の場合、カテゴリのリストを作成してください。str_to_dataframe.pyimport numpy as np import pandas as pd def str_to_dict(x): dic = {'A' : 0, 'B' : 0, 'C' : 0, 'D' : 0} for xx in x.split(","): xxs = xx.split(" ") dic[xxs[-2]] = int(xxs[-1]) return dic temp = df["クソデカ文字列"].apply(lambda x : pd.Series(str_to_dataframe(x))) df = pd.concat((df, temp), axis=1)これは早い!
- 投稿日:2019-11-15T20:42:56+09:00
Python から Azure CosmosDB を操作する (クイックスタート深掘り)
今回は Python から Azure Cosmos DB を操作する方法をクイックスタートを参考に見ていきます。
準備
まずは、
最新の Python のインストール -> https://www.python.org/
Visual Studio Code にて Python のインストールを実行します。VS Code での Python インストールは任意ですが、VS Code で直接 Python をいじれたり、色々なショートカットがあるので大変便利です。
https://marketplace.visualstudio.com/items?itemName=ms-python.python#overview
Python アプリの Clone
Microsoft が公開している GitHub からコードをクローンします。
git clone https://github.com/Azure-Samples/azure-cosmos-db-python-getting-started.git
Visual Studio の Terminal を開き、Clone したローカルディレクトリまで移動しておきましょう。
Cosmos DB のデプロイ
Azure Cosmos DB をデプロイします。今回はシンプルな Cosmos DB を作成するので、Azure CLI からデプロイします。
az cosmosdb create --name <account-name> --resource-group <resource-group-name>作成できたら、以下コマンドを Azure CLI から実行し、Endpoint と Key を取得します。
az cosmosdb keys list --name <account-name> --resource-group <resource-group-name> az cosmosdb show --name <account-name> --resource-group <resource-group-name>Visual Studio の Terminal からデプロイ
該当ディレクトリまで進んだ Visual Studio のターミナルから、以下コードを実行します。
python cosmos_get_started.pyすると以下が出力されます。
Read item with id Smith_d457f895-3756-49cd-a629-e7708d7ed252. Operation consumed 1 request units Read item with id Johnson_3bd2aa16-742f-4aed-9a95-3adc548a94e3. Operation consumed 1 request units Read item with id Wakefield_c73aa98d-7104-4b01-a3da-4946081575ff. Operation consumed 1 request units Query returned 2 items. Operation consumed 3.09 request unitsPortal ページを確認すると、Cosmos DB を操作できていることが確認できました。
深掘り
今回少しハマったのが、以下エラーが発生したときです。
Traceback (most recent call last): File "cosmos_get_started.py", line 1, in <module> from azure.cosmos import exceptions, CosmosClient, PartitionKey ImportError: cannot import name 'exceptions' from 'azure.cosmos' (...\lib\site-packages\azure\cosmos\__init__.py)このエラーは、Azure Cosmos DB の SDK が正しくインストールされていないことで発生するエラーです。-perp のバージョンのAzure Cosmos SDK をインストールしている場合、このエラーにぶち当たります。
解決策ですが、以下の Python ドキュメントに記載の方法で回避ができます。https://pypi.org/project/azure-cosmosdb-table/
(参照元)https://docs.microsoft.com/ja-jp/azure/cosmos-db/table-sdk-pythonまた、以下ページに Python SDK の正しいインストール方法が記載されているので、みてみると参考になります!
https://github.com/Azure/azure-cosmos-table-python/tree/master/azure-cosmosdb-table
- 投稿日:2019-11-15T18:57:48+09:00
MatrixProfileによるECGデータの異常検知
MatrixProfileにより時系列データマイニングがレボリューションだそうです。
が、日本語の文献はまだまだ少ないようなので、足しになればと思います。
本記事では、MatrixProfileの概要とPythonによる実装例を紹介します。MatrixProfileとは
部分時系列同士の類似結合のことです。
時系列データのペア(A,B)を考えます(同じ時系列同士のペアでも構いません)。
それぞれの時系列は長さmの部分時系列に分解されます。
A内のすべての部分時系列について、それに最も近いB内の部分時系列のインデックスおよびその距離(類似度)を求めたものをMatrixProfileと呼びます。なお、もしAとBが同じ時系列だと、部分時系列も自身とのペアが最適になってしまうので、自身の部分時系列周辺は無視します。まともに計算しようとすれば膨大な時間が必要となりますが、FFTなどを利用したアルゴリズムの工夫により現実的な時間で解くことが可能です。レボリューションですよね。
詳細はhttps://www.cs.ucr.edu/~eamonn/MatrixProfile.html
SAXやShapeletで有名なUCRのKeogh先生の研究室発の技術だそうです。
論文のタイトルがMatrix Profile 〇〇:みたいな形でシリーズ化されているようで、2019年11月現在Matrix Profile XIX:までパブリッシュされているみたいです。MatrixProfile用ライブラリ"matrixprofile-ts"
matrixprofile-tsという超お手軽なMatrixProfile専用Pythonライブラリがすでに存在します。
pip install matrixprofile-ts
こちらでも入手可能です。RやC++のものもあるらしいです。
今回はこのmatrixprofile-tsを使ってECGデータの異常検知を試みます。問題設定
今回は異常波形部位を含んだ一連のECGデータを用いて、教師なしで各点の異常度を計算し、その異常部位を特定するといった問題になります。
以下、実装に移ります。ECGデータの読込
今回はqtdbsel102と呼ばれるECGデータを用います。
https://www.cs.ucr.edu/~eamonn/discords/qtdbsel102.txt
こちらもKeogh先生の論文で用いられたデータです。
データ長が非常に長いため、初めの5000点を用いることにします。
ちなみにMatrixProfileでは計算過程で正規化されるため、前処理は必要ありません。from matrixprofile import * import pandas as pd import numpy as np import matplotlib.pyplot as plt #データの読み込み ECG = pd.read_csv('qtdbsel102.txt', header=None, delimiter='\t') X = ECG.values[:5000,2] #ECGの可視化 plt.style.use('seaborn') plt.figure(figsize=(16, 8)) plt.xlim(0, 5000) plt.plot(X) plt.axvspan(4200, 4400, facecolor='r', alpha=0.1)4200点~4400点付近異常波形が出現しています。一目瞭然ですね。
MatrixProfileの計算
優秀なライブラリのおかげでお手軽に実装出来ます。
ハイパーパラメータは部分時系列の長さだけです。今回は200に設定します。
計算手法は精度はやや落ちるものの最速かつ最新の手法であるSCRIMP++を使ってみます。#matrixProfileの計算 window_size = 200 MP = matrixProfile.scrimp_plus_plus(X,window_size)異常検知
ECGのような周期性を持つデータにおいて、正常な部分時系列は自身と非常に似通った波形が他の箇所にも確認されるはずです。
逆に言えば、自身と似通った波形が存在しない、つまりMatrixProfileの距離の値が大きくなる部分が異常と考えられます。さて、先ほど計算したMP内には距離列と参照インデックス列が格納されています。
距離列を確認し、可視化してみましょう。#MatrixProfileの可視化 plt.figure(figsize=(16, 8)) plt.subplot(2,1,1) plt.xlim(0, 5000) plt.title('ECG') plt.plot(X) x = np.arange(4200,4400) plt.axvspan(4200, 4400, facecolor='r', alpha=0.1) plt.subplot(2,1,2) plt.xlim(0, 5000) plt.title('MatrixProfile') plt.plot(MP[0]) plt.axvspan(4200, 4400, facecolor='r', alpha=0.1)MatrixProfileの強み
「異常検知なんて他の手法でも出来るじゃないか。ディープなラーニングでいいじゃないか。」
そう思われる方も多いかもしれません。しかし、MatrixProfileの魅力はそのシンプルさにあります。
MatrixProfileの計算過程にアメージングな斬新さはあれど、最終的に出力しているのは単なる部分波形同士のマッチングに過ぎません。つまり、異常が検出されたとして、その妥当性を人が容易にチェックすることが出来ます。信頼性やトラクタビリティといった観点において右に出るものはないでしょう。さらに、今回の異常波形検出はMatrixProfileの持つ機能の1つに過ぎません。MotifやShapeletの発見をはじめとして、数多くの応用先があるらしいです。レボリューションですよね。
まとめ
MatrixProfileを紹介し、matrixprofile-tsと呼ばれるライブラリを試しました
- 投稿日:2019-11-15T18:50:59+09:00
(書き直し)e-Gov法令APIとXML Pythonを用いた特定ワードが含まれる条文抽出
きっかけ
201910 Business Law Journalに,”XMLによる情報整理の薦め”という記事あり.
興あり.まず法令XMLをいじってみた.他記事で全くコードを記載していないことに対する代償行為ではない.ないってば.
*なお,”XMLによる情報整理の薦め”の著者は,
判例等を含めて閲覧可能としたXMLを作成しており,次で公開している.
民法体系XML http://cyberlawschool.jp/kagayama/civ_ver1.xml
http://cyberlawschool.jp/kagayama/内容
- e-Gov法令APIから指定する法令入手
- 法令条文表示.
- 特定のワードを含む条文のみ抽出することも可(個人的にはよく使う)
参照 https://qiita.com/sakaia/items/c787aa6471e70000d253
問題あり.
- 遅い.「条の~」を処理する部分が無駄.
- 遅い.法令全体を読み込んで特定条文のみ処理する方式のほうが速いであろうな.(とりま,all指定で法文全体読み込み可能に変更)
- KEYWORDを受ける関数が隠れてしまい明示的でない.(ダミーをおいてみたがどうも)
- 基礎からおかしいでしょう.指摘していただけると,本当に,助かります.
- iはデバグ用.
- lawnumはint入力だが内部処理はstr.スッキリしない.
*官報が取れるとよいのですが,掲載されていないのですねぇ.
コード
import requests import xml.etree.ElementTree as ET #e-Gov 法令API 仕様書 #https://www.e-gov.go.jp/elaws/pdf/houreiapi_shiyosyo.pdf #法令選択 def lawName2No(KEYWORD, TAG='LawName'): url = 'https://elaws.e-gov.go.jp/api/1/lawlists/2' r = requests.get(url) root = ET.fromstring(r.content.decode(encoding='utf-8')) iflag = 0 for i,e in enumerate(root.getiterator()): if TAG==e.tag: iflag = 0 if KEYWORD==e.text: iflag = 1 if iflag==1 and e.tag=='LawNo': return str(e.text) #法令表示・抽出 def lawTextExtractor(KEYWORD, lawnum='all', wordn=0, words=[]): if lawnum=='all': url = 'https://elaws.e-gov.go.jp/api/1/lawdata/'+lawName2No(KEYWORD) else: url = 'https://elaws.e-gov.go.jp/api/1/articles;lawNum='+lawName2No(KEYWORD)+';article='+str(lawnum) r = requests.get(url) if r.status_code!=requests.codes.ok: return root = ET.fromstring(r.content.decode(encoding='utf-8')) lawstrs = [] ssentcount = 0 for i,e in enumerate(root.getiterator()): for xtag in ['LawTitle', 'SupplProvisionLabel', 'ArticleCaption', 'ArticleTitle', 'ParagraphNum', 'ItemTitle', 'Sentence']: if e.tag==xtag : if wordn==1 and xtag=='Sentence':#ワード指定する場合 tmpstr = '' for word in words: if str(e.text).find(word)>-1: if tmpstr=='': tmpstr = e.text.replace(word, '●'+word) else: tmpstr = tmpstr.replace(word, '★'+word) if tmpstr!='': lawstrs.append(tmpstr) ssentcount += 1 else: lawstrs.append(str(e.text)) if lawstrs==[]: pass else: if lawnum=='all': print('●条項号数', ssentcount) print('\n'.join(lawstrs))#法令指定 KEYWORD = '著作権法' #ワード抽出する場合 1 wordn = 1 #抽出ワードリスト words = ['映画'] #条文指定 今回は14条から29条 for lawnum in range(14,30): lawTextExtractor(KEYWORD, lawnum, wordn, words) #「条の~」を無理やり処理.後で対策を考える. [lawTextExtractor(KEYWORD, str(lawnum)+'.'+str(i), wordn, words) for i in range(15)] #法令全体指定する場合(3秒ほどで出力される) lawTextExtractor(KEYWORD, 'all', wordn, words) #並行して, #lawTextExtractor(KEYWORD, 18, 0, []) #など,特定条文の非表示部分を確認するのも良い #for i in [134,134.2,134.3,153,164.2,134.2]: # lawTextExtractor(KEYWORD, i, 0, []) #など,「第百三十四条第一項若しくは第二項、第百三十四条の二第五項、 #第百三十四条の三、第百五十三条第二項又は第百六十四条の二第二項の規定により #指定された期間内に限り」など引用された条文をまとめて確認するのも良い出力結果
- ワード抽出すると,たとえば,映画では譲渡権等が頒布権に変換されているのだな,などよく分かる.
- 条項号はワード抽出有無に関わらずそのまま残し,全体構造がわかるようにした.
- Noneは法令を読み慣れている人にはこのほうが読みやすいと考え,そのまま.
- インデントは見にくくなったため,行わず.
(著作者の推定)
第十四条
None
(職務上作成する著作物の著作者)
第十五条
None
2
(映画の著作物の著作者)
第十六条
None
●映画の著作物の著作者は、その●映画の著作物において翻案され、又は複製された小説、脚本、音楽その他の著作物の著作者を除き、制作、監督、演出、撮影、美術等を担当してその●映画の著作物の全体的形成に創作的に寄与した者とする。
(著作者の権利)
第十七条
None
2
(公表権)
第十八条
None
2
一
二
三
第二十九条の規定によりその●映画の著作物の著作権が●映画製作者に帰属した場合
3
一
二
三
四
五
4
一
二
三
四
五
六
七
八
(氏名表示権)
第十九条
None
2
3
4
一
二
三
(同一性保持権)
第二十条
None
2
一
二
三
四
(複製権)
第二十一条
None
(上演権及び演奏権)
第二十二条
None
(上映権)
第二十二条の二
None
(公衆送信権等)
第二十三条
None
2
(口述権)
第二十四条
None
(展示権)
第二十五条
None
(頒布権)
第二十六条
None
著作者は、その●映画の著作物をその複製物により頒布する権利を専有する。
2
著作者は、●映画の著作物において複製されているその著作物を当該●映画の著作物の複製物により頒布する権利を専有する。
(譲渡権)
第二十六条の二
None
著作者は、その著作物(●映画の著作物を除く。以下この条において同じ。)をその原作品又は複製物(●映画の著作物において複製されている著作物にあつては、当該●映画の著作物の複製物を除く。以下この条において同じ。)の譲渡により公衆に提供する権利を専有する。
2
一
二
三
四
五
(貸与権)
第二十六条の三
None
著作者は、その著作物(●映画の著作物を除く。)をその複製物(●映画の著作物において複製されている著作物にあつては、当該●映画の著作物の複製物を除く。)の貸与により公衆に提供する権利を専有する。
(翻訳権、翻案権等)
第二十七条
None
著作者は、その著作物を翻訳し、編曲し、若しくは変形し、又は脚色し、●映画化し、その他翻案する権利を専有する。
(二次的著作物の利用に関する原著作者の権利)
第二十八条
None
第二十九条
None
●映画の著作物(第十五条第一項、次項又は第三項の規定の適用を受けるものを除く。)の著作権は、その著作者が●映画製作者に対し当該●映画の著作物の製作に参加することを約束しているときは、当該●映画製作者に帰属する。
2
専ら放送事業者が放送のための技術的手段として製作する●映画の著作物(第十五条第一項の規定の適用を受けるものを除く。)の著作権のうち次に掲げる権利は、●映画製作者としての当該放送事業者に帰属する。
一
二
3
専ら有線放送事業者が有線放送のための技術的手段として製作する●映画の著作物(第十五条第一項の規定の適用を受けるものを除く。)の著作権のうち次に掲げる権利は、●映画製作者としての当該有線放送事業者に帰属する。
一
二
- 投稿日:2019-11-15T18:40:32+09:00
計算ドリル python
今回はテキストファイルを利用して、一桁自然数の二項演算の計算ドリルを作っていきます。環境はanaconda。書いたコードは以下の通りです。
コードと出力結果
計算ドリルimport random with open("keisan.txt","w") as f: answer = [] for cnt in range(10): num1 = random.randint(1,9) num2 = random.randint(1,9) question = str(num1) + " + " + str(num2) + " = " answer.append(num1+num2) f.write(question+"\n") f.write("\nA. ") for ans in answer: f.write(str(ans) + " ")出力結果5 + 1 = 5 + 2 = 3 + 3 = 2 + 6 = 1 + 5 = 4 + 8 = 6 + 1 = 8 + 4 = 6 + 7 = 6 + 4 = A. 6 7 6 8 6 12 7 12 13 10フロー
プログラムのフローを説明してきます。
テキストファイルのオープンwith open("keisan.txt","w") as f:まず、最初に一桁の自然数を取得するためにrandomモジュールをインポートします。そして、テキストファイルに出力するためにwithステートメントを使い、ファイル名を"keisan.txt"として、書き込みモードにして開きます。
式の書き込みanswer = [] for cnt in range(10): num1 = random.randint(1,9) num2 = random.randint(1,9) question = str(num1) + " + " + str(num2) + " = " answer.append(num1+num2) f.write(question+"\n") f.write("\nA. ")ここでは実際の足し算を書き込んでいます。答えの出力もするので、リストを用意します。randomモジュールの整数を生成するrandint関数を使い、1~9の自然数を生成しています。questionには問題文を格納するのですが、演算子を使うと勝手に計算されてしまいますので文字列に変換して格納しています。答えの方はappendメソッドを使い、リストに加えていきます。そして、questionに格納された計算式をwriteメソッドで書き込んでいます。見やすいように改行しつつ出力します。
答えの書き込みfor ans in answer: f.write(str(ans) + " ")最後に、answerに格納された答えのリストをfor文で順番に出力していきます。
振り返り
過去にC言語を使った、テキストファイルの書き読み込みをしたことがありますが、pythonだとwith文を使うことでファイルのクローズを意識しなくなるのでとても楽ですね。
このコードは足し算の二項演算だけなので、今後はもっとこの計算ドリルを演算を自由に選べたり桁数を指定したりと機能を拡張していきたいと思います。なにかご意見、質問などありましたら気軽にコメントして下さい。
- 投稿日:2019-11-15T18:26:34+09:00
SonyのPaSoRi(RCS370)でSesameを動かす
背景
第2回「研究室のみんなそれぞれ1日使って何か作ろう!」の日。
他のメンバーの記事はこちら。
第1回の僕の記事はこちら。研究室の鍵にはSesameがついているんですが、開閉するたびに携帯でアプリ開いて操作するのが非常にめんどくさい。SuicaとかApple payのFelicaで開けられたらいいのに、と思った。
画像はこちらの記事のものです。ありがとうございます。
事前準備
https://www.otwo.jp/blog/raspi_sesame_1/
http://www.otwo.jp/blog/raspi_sesame_2/
この辺を参照。
- Raspberry Pi:研究室に転がってたやつ(多分Raspberry Pi3)。
- Sesame:研究室の入り口に設置済み。
- NFCリーダ:RCS370。研究室の先生の私物を拝借(なぜ持っているのか…)
Raspberry Piでやってみた(失敗)
nfcpy: 1.0.3
python2: 2.7.16
python3: 3.7.3nfcpyをpipでインストール。python3にも対応しているとのことだったのでpython3を使う方針。
$ pip3 install nfcpy同時にgithubからソースをクローン。
examples/tagtool.py
を動かしてみる。$ python3 tagtool.py [nfc.clf] searching for reader on path usb [nfc.clf] no reader available on path usb [main] no contactless reader found on usb [main] no contactless reader availableエラーが出る。
公式ドキュメントとか、Qiitaの記事とかを調べてみると、デバイスIDを使ってUSBのパスを指定する必要があるみたい。
lsusb
で調べてみると、$ lsusb (省略) Bus 001 Device 025: ID 054c:02e1 Sony Corp. FeliCa S330 [PaSoRi] (省略)デバイスIDが表示されている。370ではなく330になっているのが気になるが、用いるドライバは同じみたいなのでよしとする。
USBパスを指定して実行してみる。
$ python3 tagtool.py [nfc.clf] searching for reader on path usb:054c:02e1 [nfc.clf.rcs956] input/output error while waiting for ack [main] no contactless reader availableあれれ?色々と調べてみると、指定したパスのデバイスとうまくコミュニケーションができていないみたい…。
色々試す
ピザ休憩を挟んで作業再開。
そもそも、RCS370 & Raspberry Pi & nfcpyでうまくいっている例がない。
この記事を始め、370を380に変えたら動きました!系がちらほら…。テンション下がりつつも、まだ諦めたくなかったのでMonsterを飲んで調査を続ける。
この記事ではDebianとRCS370を使っている。
python -m nfc
でそもそもnfcpyがちゃんとインストールできているかを確認できるそう。とりあえずやってみる。This is the 1.0.3 version of nfcpy run in Python 3.7.3 on Linux-4.19.57-v7+-armv7l-with-debian-10.0 I'm now searching your system for contactless devices ERROR:nfc.clf.rcs956:input/output error while waiting for ack I'm not trying serial devices because you haven't told me -- add the option '--search-tty' to have me looking -- but beware that this may break other serial devs Sorry, but I couldn't find any contactless deviceinput/output errorと出ている。python, nfcpyのバージョンを参考記事と合わせても変わらなかった。
エラーの内容としてはこの記事と同じ。うーん…。
nfcpy, pythonのバージョンを色々試しましたが、やっぱりできない…。これはお手上げ…。
僕なりの結論
RCS370 & Raspberry Pi & nfcpyはうまくいかない!
USBポートにRCS370が挿さったことをラズパイは認識するんだけどなあ…。まあRCS380使えということか。
MacBook Airでやってみた(成功)
nfcpy: 1.0.3
python3: 3.6.5それでも諦めたくなかったので、自分のパソコン(MacBook Air)でやってみることにした。
同様にnfcpyをクローンし、
examples/tagtool.py
を走らせる。[nfc.clf] searching for reader on path usb [nfc.clf] using Sony RC-S370/P RCS956v1.30 at usb:020:018 ** waiting for a tag ** Type3Tag 'FeliCa Standard (RC-S???)' ID=カードのID (省略)行けた。
Sesameとの接続
公式の記事を参照。Python3を使いたかったのでところどころいじる。
nfc_card.py# -*- coding: utf-8 -*- import requests import json import binascii import nfc import time from threading import Thread, Timer # login CANDY HOUSE account and get token url = "https://api.candyhouse.co/v1/accounts/login" head = {"Content-type": "application/json"} payload = {"email":"アカウントのメールアドレス", "password":"アカウントのパスワード"} response = requests.post(url, headers=head, data=json.dumps(payload)) token = response.json()["authorization"] # Suica待ち受けの1サイクル秒 TIME_cycle = 1.0 # Suica待ち受けの反応インターバル秒 TIME_interval = 0.2 # タッチされてから次の待ち受けを開始するまで無効化する秒 TIME_wait = 3 # NFC接続リクエストのための準備 # 212F(FeliCa)で設定 target_req_suica = nfc.clf.RemoteTarget("212F") # 0003(Suica) target_req_suica.sensf_req = bytearray.fromhex("0000030000") print('Waiting for SUICA...') while True: # USBに接続されたNFCリーダに接続してインスタンス化 clf = nfc.ContactlessFrontend('usb') # Suica待ち受け開始 # clf.sense( [リモートターゲット], [検索回数], [検索の間隔] ) target_res = clf.sense(target_req_suica, iterations=int(TIME_cycle//TIME_interval)+1 , interval=TIME_interval) if target_res is not None: # != -> is not に変更 #tag = nfc.tag.tt3.Type3Tag(clf, target_res) #なんか仕様変わったっぽい?↓なら動いた tag = nfc.tag.activate_tt3(clf, target_res) tag.sys = 3 #IDmを取り出す idm = binascii.hexlify(tag.idm) print('Suica detected. idm = ' + str(idm)) if (idm == b'ICのID'): headers = {'X-Authorization':token,} response = requests.get('https://api.candyhouse.co/v1/sesames/セサミのシリアルナンバー', headers=headers) status = response.json()["is_unlocked"] url_control = "https://api.candyhouse.co/v1/sesames/セサミのシリアルナンバー/control" head_control = {"X-Authorization": token, "Content-type": "application/json"} # 開いてたら閉まる、閉まってたら開く if status: payload_control = {"type":"lock"} else: payload_control = {"type":"unlock"} response_control = requests.post(url_control, headers=head_control, data=json.dumps(payload_control)) print(response_control.text) print('sleep ' + str(TIME_wait) + ' seconds') time.sleep(TIME_wait) #end if clf.close() #end whileシリアルナンバーで、SESAME ID(これ)ではないことに注意。ここをSESAME IDにしていたせいでAPIが叩けず、30分ぐらい無駄な時間を過ごした…。
使ってみる
笑
まあ、今回はしょうがない。NFCリーダを内側からセロテープではり(先生ごめんなさい)、外からICカードで開けられるか確認します。
…開く!けどタッチしてから3~5秒ほどの間がある。それでも
「携帯取り出す→ロック解除→セサミのアプリ開く→接続されるのを待つ→タップする」
よりは早いし楽!良さげ。iPhone XにいれているモバイルSuicaもちゃんと反応。ただICカードと比べて若干反応が悪いかな?
感想と今後
さらっといけると思っていたけど、やっぱりさらっといかなかった。通信・ハードが絡むとちょっと難易度あがる。でも研究室がさらに便利になりそうで満足。
そしてRCS380を発注した。笑
すぐに届くみたいなので実装して扉につけます。380でうまくいったらまた記事にします。月1回ぐらいでこの会やりたいなあ。次は何を作ろう。
- 投稿日:2019-11-15T18:10:18+09:00
機械学習入門者が一日でシェルティー判定AIを作成してみた
謝辞
まず初めに参考にさせていただきました。
大変感謝申し上げます。https://qiita.com/yottyann1221/items/a08300b572206075ee9f
https://qiita.com/tomo_20180402/items/e8c55bdca648f4877188
https://qiita.com/mainvoidllll/items/db991dc30d3ddced6250
https://newtechnologylifestyle.net/keras_imagedatagenerator/掲載している画像はフリー画像を使用させていただきました。
https://pixabay.com/ja/序
機械学習に入門しました。
ざっとぐぐったところこんな感じで進めていくようです。
- 大量の画像を用意する
- 教師/テストデータを作成する
- モデルを作成する
- モデルで評価する
今回は、画像認識でシェルティー判定プログラムを作成することにしました。
環境構築
Windows 10 に chocolatey で python3 を入れました。
venv で仮想環境を構築し、必要なライブラリを入れます。> mkdir -p e:\python\ml > cd e:\python\ml > python -m venv ml > .\ml\Scripts\activate (ml)> pip install requests (ml)> pip install beautifulsoup4 # lxml を入れないと下のエラーが出る # bs4.FeatureNotFound: Couldn't find a tree builder with the features you requested: lxml. Do you need to install a parser library? (ml)> pip install lxml (ml)> pip install pillow # 最新の numpy 入れて np.load() すると下のエラーが出るので古いバージョンを指定する # ValueError: Object arrays cannot be loaded when allow_pickle=False (ml)> pip install numpy==1.16.2 (ml)> pip install sklearn (ml)> pip install tensorflow (ml)> pip install keras (ml)> pip install matplotlib構成
こんな構成にしました。
e:\python\ml ├─ml └─src ├─data │ ├─img │ │ ├─original : スクレイピングして取得した元画像 │ │ │ ├─シェルティー │ │ │ ├─コーギー │ │ │ └─ボーダーコリー │ │ ├─trimmed : 不要な画像を取り除いて残った画像 │ │ │ ├─シェルティー │ │ │ ├─コーギー │ │ │ └─ボーダーコリー │ │ ├─excluded : 不要な画像 │ │ │ ├─シェルティー │ │ │ ├─コーギー │ │ │ └─ボーダーコリー │ │ ├─extended : 残った画像を加工して水増しした画像 │ │ │ ├─シェルティー │ │ │ ├─コーギー │ │ │ └─ボーダーコリー │ │ └─test : AI の動作確認用の画像 │ ├─train_test_data │ │ └─data.npy : extended の画像を使って作成した教師/テストデータ │ ├─model : 作成したモデル │ │ ├─Training_and_validation_accuracy.png │ │ ├─Training_and_validation_loss.png │ │ ├─model_predict.hdf5 │ │ └─model_predict.json ├─img_scraper : 画像スクレイピング │ ├─google_search.py │ └─main.py ├─img_trimmer : 画像除去 │ └─main.py ├─img_duplicator : 画像水増し │ └─main.py ├─train_test_data_generator : 教師/テストデータ作成 │ └─main.py ├─model_generator : モデル生成 │ └─main.py └─ai : シェルティー判定 └─main.py画像スクレイピング
まずは画像を用意します。
今回は 300 枚ずつスクレイピングしました。
img_scraper\google_search.py
# -- coding: utf-8 -- import json from urllib import parse import requests from bs4 import BeautifulSoup class Google: def __init__(self): self.GOOGLE_SEARCH_URL = 'https://www.google.co.jp/search' self.session = requests.session() self.session.headers.update({ 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0'}) def Search(self, keyword, type='text', maximum=1000): '''Google検索''' print('Google', type.capitalize(), 'Search :', keyword) result, total = [], 0 query = self.query_gen(keyword, type) while True: # 検索 html = self.session.get(next(query)).text links = self.get_links(html, type) # 検索結果の追加 if not len(links): print('-> No more links') break elif len(links) > maximum - total: result += links[:maximum - total] break else: result += links total += len(links) print('-> 結果', str(len(result)), 'のlinksを取得しました') return result def query_gen(self, keyword, type): '''検索クエリジェネレータ''' page = 0 while True: if type == 'text': params = parse.urlencode({ 'q': keyword, 'num': '100', 'filter': '0', 'start': str(page * 100)}) elif type == 'image': params = parse.urlencode({ 'q': keyword, 'tbm': 'isch', 'filter': '0', 'ijn': str(page)}) yield self.GOOGLE_SEARCH_URL + '?' + params page += 1 def get_links(self, html, type): '''リンク取得''' soup = BeautifulSoup(html, 'lxml') if type == 'text': elements = soup.select('.rc > .r > a') links = [e['href'] for e in elements] elif type == 'image': elements = soup.select('.rg_meta.notranslate') jsons = [json.loads(e.get_text()) for e in elements] links = [js['ou'] for js in jsons] return links
img_scraper\main.py
# -- coding: utf-8 -- import os import requests import google_search # 検索キーワード KEYWORDS = [u'シェルティー', u'コーギー', u'ボーダーコリー'] # 取得する画像数 IMG_CNT = 300 g = google_search.Google() for keyword in KEYWORDS: # 保存先作成 img_dir = os.path.join('./../data/img/original', keyword) os.makedirs(img_dir, exist_ok=True) print(u'保存先: {}'.format(img_dir)) # 画像検索 img_urls = g.Search('{} filetype:jpg -柴犬 -フェルト -商品 -おもちゃ -ぬいぐるみ -置物 -アイテム -マスコット -本 -表紙 -映画 -漫画 -チャーム -jpg -楽天市場 -イラスト -ステッカー -通販 -LINE -スタンプ -シルエット -デザイン -マグカップ -ブリーダー -ジモティー -集団 -群れ -ネイル -クレーン -景品 -製品'.format(keyword), type='image', maximum=IMG_CNT) # 画像保存 total_cnt = 0 for i,img_url in enumerate(img_urls): try: # 画像パス img_full_path = os.path.join(img_dir, (str(i) + '.jpg')) print('{}: {} -> {}'.format(str(i), img_url, img_full_path)) re = requests.get(img_url, allow_redirects=False) if len(re.content) <= 0: print(u'{}: レスポンスの中身が空のためスキップします。'.format(str(i))) continue with open(img_full_path, 'wb') as f: f.write(re.content) total_cnt = total_cnt + 1 except requests.exceptions.ConnectionError: continue except UnicodeEncodeError: continue except UnicodeError: continue except IsADirectoryError: continue print(u'{}: {} 件の画像を取得しました。'.format(keyword, total_cnt)) print(u'保存完了しました。')> cd e:\python\ml\src\img_scraper > python main.py シェルティー: 270 件の画像を取得しました。 コーギー: 286 件の画像を取得しました。 ボーダーコリー: 281 件の画像を取得しました。数件はうまく画像を保存できなかったようです。
画像精査
教師データとして使えない画像を取り除きます。
例えば他の犬種が一緒に写っていたりテキストが大量に入っていたり…しているのでそういった画像の番号をメモします。
あとは Python で教師データに使用するデータと除外対象とを仕分けします。
img_trimmer\main.py
# -- coding: utf-8 -- import os, glob import shutil # 検索キーワード KEYWORDS = [u'シェルティー', u'コーギー', u'ボーダーコリー'] targets = [ [19, 25, 34, 40, 41, 49, 54, 74, 77, 81, 86, 89, 91, 93, 102, 104, 108, 111, 118, 119, 124, 127, 130, 131, 132, 136, 152, 154, 158, 159, 161, 168, 169, 173, 178, 181, 183, 184, 192, 193, 198, 201, 202, 213, 218, 233, 235, 236, 238, 240, 243, 245, 246, 248, 249, 252, 255, 264, 265, 269, 271, 272, 280, 283, 284, 287, 294, 295], [19, 29, 30, 40, 45, 67, 69, 73, 76, 78, 80, 100, 101, 105, 117, 120, 132, 136, 141, 143, 149, 151, 154, 158, 167, 170, 179, 180, 183, 186, 200, 201, 208, 213, 220, 224, 225, 228, 234, 235, 241, 243, 247, 248, 250, 253, 259, 262, 264, 266, 273, 277, 278, 279, 281, 282, 283, 285, 290, 293, 294, 298, 299], [9, 21, 25, 37, 38, 40, 41, 42, 49, 52, 55, 61, 65, 66, 71, 72, 78, 80, 89, 93, 96, 103, 108, 110, 113, 114, 118, 122, 126, 127, 128, 145, 146, 152, 158, 160, 161, 164, 166, 167, 171, 174, 175, 176, 182, 183, 186, 187, 193, 194, 196, 197, 200, 202, 203, 206, 207, 222, 223, 224, 226, 228, 230, 232, 233, 234, 237, 238, 241, 243, 244, 257, 259, 260, 262, 263, 264, 265, 267, 268, 270, 273, 275, 276, 277, 278, 281, 282, 283, 287, 289, 292, 293, 295] ] for idx, keyword in enumerate(KEYWORDS): total_count = 0 # コピー元 img_dir = os.path.join('./../data/img/original', keyword) # コピー先 os.makedirs(os.path.join('./../data/img/trimmed', keyword), exist_ok=True) os.makedirs(os.path.join('./../data/img/excluded', keyword), exist_ok=True) files = glob.glob(os.path.join(img_dir, '*.jpg')) for f in files: if int(os.path.splitext(os.path.basename(f))[0]) in targets[idx]: shutil.copy2(f, os.path.join('./../data/img/excluded', keyword)) print(u'{} : 除外対象です。'.format(f)) else: shutil.copy2(f, os.path.join('./../data/img/trimmed', keyword)) print(u'{} : 教師データに使用します。'.format(f)) total_count = total_count + 1 print(u'{} : 使用できるデータ数は {} 件です。'.format(keyword, total_count)) print(u'保存完了しました。')> cd e:\python\ml\src\img_trimmer > python main.py シェルティー : 使用できるデータ数は 202 件です。 コーギー : 使用できるデータ数は 223 件です。 ボーダーコリー : 使用できるデータ数は 187 件です。教師データとして使用できるのは 6 ~ 7 割となりました。
画像複製
Keras の ImageDataGenerator で画像を複製、加工することでデータ数を水増しします。
img_duplicator\main.py
# -- coding: utf-8 -- import os import glob import numpy as np from keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array, array_to_img CATEGORIES = [u'シェルティー', u'コーギー', u'ボーダーコリー'] # 画像サイズ IMG_SIZE = 150 # ImageDataGeneratorを定義 DATA_GENERATOR = ImageDataGenerator(horizontal_flip=0.3, zoom_range=0.1) for idx, category in enumerate(CATEGORIES): # コピー元 img_dir = os.path.join('./../data/img/trimmed', category) # コピー先 out_dir = os.path.join('./../data/img/extended', category) os.makedirs(out_dir, exist_ok=True) files = glob.glob(os.path.join(img_dir, '*.jpg')) for i, file in enumerate(files): img = load_img(file) img = img.resize((IMG_SIZE, IMG_SIZE)) x = img_to_array(img) x = np.expand_dims(x, axis=0) g = DATA_GENERATOR.flow(x, batch_size=1, save_to_dir=out_dir, save_prefix='img', save_format='jpg') for i in range(10): batch = g.next() print(u'{} : ファイル数は {} 件です。'.format(category, len(os.listdir(out_dir))))> cd e:\python\ml\src\img_duplicator > python main.py Using TensorFlow backend. シェルティー : ファイル数は 1817 件です。 コーギー : ファイル数は 1983 件です。 ボーダーコリー : ファイル数は 1708 件です。教師データ作成
大量の画像を用意したので教師データを作成します。
画像をラベリングしていきます。
全データの 2 割ほどをテストデータにまわします。
作成した教師/テストデータは保存しておきます。
train_test_data_generator\main.py
# -*- coding: utf-8 -*- from PIL import Image import os, glob import numpy as np import random, math from sklearn.model_selection import train_test_split from keras.utils import np_utils # 画像が保存されているルートディレクトリのパス IMG_ROOT_DIR = './../data/img/extended' # カテゴリ CATEGORIES = [u'シェルティー', u'コーギー', u'ボーダーコリー'] # 密度 DENSE_SIZE = len(CATEGORIES) # 画像サイズ IMG_SIZE = 150 # 画像データ X = [] # カテゴリデータ Y = [] # 教師データ X_TRAIN = [] Y_TRAIN = [] # テストデータ X_TEST = [] Y_TEST = [] # データ保存先 TRAIN_TEST_DATA = './../data/train_test_data/data.npy' # カテゴリごとに処理する for idx, category in enumerate(CATEGORIES): # 各ラベルの画像ディレクトリ image_dir = os.path.join(IMG_ROOT_DIR, category) files = glob.glob(os.path.join(image_dir, '*.jpg')) for f in files: # 各画像をリサイズしてデータに変換する img = Image.open(f) img = img.convert('RGB') img = img.resize((IMG_SIZE, IMG_SIZE)) data = np.asarray(img) X.append(data) Y.append(idx) X = np.array(X) Y = np.array(Y) # 正規化 X = X.astype('float32') /255 Y = np_utils.to_categorical(Y, DENSE_SIZE) # 教師データとテストデータを分ける X_TRAIN, X_TEST, Y_TRAIN, Y_TEST = train_test_split(X, Y, test_size=0.20) # 教師/テストデータを保存する np.save(TRAIN_TEST_DATA, (X_TRAIN, X_TEST, Y_TRAIN, Y_TEST)) print(u'教師/テストデータの作成が完了しました。: {}'.format(TRAIN_TEST_DATA))> cd e:\python\ml\src\train_test_data_generator > python main.py Using TensorFlow backend. 教師/テストデータの作成が完了しました。: ./../data/train_test_data/data.npyモデル構築
教師/テストデータを用意できたのでいよいよモデルを構築します。
構築したモデルは保存しておきます。
model_generator\main.py
# -*- coding: utf-8 -*- #モデルの構築 from keras import layers, models from keras import optimizers import numpy as np import matplotlib.pyplot as plt import os # カテゴリ CATEGORIES = [u'シェルティー', u'コーギー', u'ボーダーコリー'] # 密度 DENSE_SIZE = len(CATEGORIES) # 画像サイズ IMG_SIZE = 150 INPUT_SHAPE = (IMG_SIZE, IMG_SIZE,3) # 教師データ X_TRAIN = [] Y_TRAIN = [] # テストデータ X_TEST = [] Y_TEST = [] # データ保存先 TRAIN_TEST_DATA = './../data/train_test_data/data.npy' # モデル保存先 MODEL_ROOT_DIR = './../data/model/' # ----- モデル構築 ----- # model = models.Sequential() model.add(layers.Conv2D(32,(3,3),activation="relu",input_shape=INPUT_SHAPE)) model.add(layers.MaxPooling2D((2,2))) model.add(layers.Conv2D(64,(3,3),activation="relu")) model.add(layers.MaxPooling2D((2,2))) model.add(layers.Conv2D(128,(3,3),activation="relu")) model.add(layers.MaxPooling2D((2,2))) model.add(layers.Conv2D(128,(3,3),activation="relu")) model.add(layers.MaxPooling2D((2,2))) model.add(layers.Flatten()) model.add(layers.Dropout(0.5)) model.add(layers.Dense(512,activation="relu")) model.add(layers.Dense(DENSE_SIZE,activation="sigmoid")) #モデル構成の確認 model.summary() # ----- /モデル構築 ----- # # ----- モデルコンパイル ----- # model.compile(loss="binary_crossentropy", optimizer=optimizers.RMSprop(lr=1e-4), metrics=["acc"]) # ----- /モデル構築 ----- # # ----- モデル学習 ----- # # 教師データとテストデータを読み込む X_TRAIN, X_TEST, Y_TRAIN, Y_TEST = np.load(TRAIN_TEST_DATA) model = model.fit(X_TRAIN, Y_TRAIN, epochs=10, batch_size=6, validation_data=(X_TEST, Y_TEST)) # ----- /モデル学習 ----- # # ----- 学習結果プロット ----- # acc = model.history['acc'] val_acc = model.history['val_acc'] loss = model.history['loss'] val_loss = model.history['val_loss'] epochs = range(len(acc)) plt.plot(epochs, acc, 'bo', label='Training acc') plt.plot(epochs, val_acc, 'b', label='Validation acc') plt.title('Training and validation accuracy') plt.legend() plt.savefig(os.path.join(MODEL_ROOT_DIR, 'Training_and_validation_accuracy.png')) plt.figure() plt.plot(epochs, loss, 'bo', label='Training loss') plt.plot(epochs, val_loss, 'b', label='Validation loss') plt.title('Training and validation loss') plt.legend() plt.savefig(os.path.join(MODEL_ROOT_DIR, 'Training_and_validation_loss.png')) # ----- /学習結果プロット ----- # # ----- モデル保存 ----- # # モデル保存 json_string = model.model.to_json() open(os.path.join(MODEL_ROOT_DIR, 'model_predict.json'), 'w').write(json_string) #重み保存 model.model.save_weights(os.path.join(MODEL_ROOT_DIR, 'model_predict.hdf5')) # ----- /モデル保存 ----- #> cd e:\python\ml\src\model_generator > python main.py Using TensorFlow backend. 2019-11-15 17:02:03.400229: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 Model: "sequential_1" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d_1 (Conv2D) (None, 148, 148, 32) 896 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 74, 74, 32) 0 _________________________________________________________________ conv2d_2 (Conv2D) (None, 72, 72, 64) 18496 _________________________________________________________________ max_pooling2d_2 (MaxPooling2 (None, 36, 36, 64) 0 _________________________________________________________________ conv2d_3 (Conv2D) (None, 34, 34, 128) 73856 _________________________________________________________________ max_pooling2d_3 (MaxPooling2 (None, 17, 17, 128) 0 _________________________________________________________________ conv2d_4 (Conv2D) (None, 15, 15, 128) 147584 _________________________________________________________________ max_pooling2d_4 (MaxPooling2 (None, 7, 7, 128) 0 _________________________________________________________________ flatten_1 (Flatten) (None, 6272) 0 _________________________________________________________________ dropout_1 (Dropout) (None, 6272) 0 _________________________________________________________________ dense_1 (Dense) (None, 512) 3211776 _________________________________________________________________ dense_2 (Dense) (None, 3) 1539 ================================================================= Total params: 3,454,147 Trainable params: 3,454,147 Non-trainable params: 0 _________________________________________________________________ Train on 4396 samples, validate on 1100 samples Epoch 1/10 4396/4396 [==============================] - 103s 23ms/step - loss: 0.5434 - acc: 0.7298 - val_loss: 0.5780 - val_acc: 0.7067 Epoch 2/10 4396/4396 [==============================] - 109s 25ms/step - loss: 0.4457 - acc: 0.7989 - val_loss: 0.4288 - val_acc: 0.8024 Epoch 3/10 4396/4396 [==============================] - 103s 23ms/step - loss: 0.3874 - acc: 0.8318 - val_loss: 0.3992 - val_acc: 0.8170 Epoch 4/10 4396/4396 [==============================] - 106s 24ms/step - loss: 0.3483 - acc: 0.8469 - val_loss: 0.3476 - val_acc: 0.8476 Epoch 5/10 4396/4396 [==============================] - 107s 24ms/step - loss: 0.3029 - acc: 0.8717 - val_loss: 0.3085 - val_acc: 0.8603 Epoch 6/10 4396/4396 [==============================] - 109s 25ms/step - loss: 0.2580 - acc: 0.8947 - val_loss: 0.2918 - val_acc: 0.8736 Epoch 7/10 4396/4396 [==============================] - 107s 24ms/step - loss: 0.2182 - acc: 0.9084 - val_loss: 0.2481 - val_acc: 0.8970 Epoch 8/10 4396/4396 [==============================] - 113s 26ms/step - loss: 0.1855 - acc: 0.9217 - val_loss: 0.1920 - val_acc: 0.9209 Epoch 9/10 4396/4396 [==============================] - 120s 27ms/step - loss: 0.1548 - acc: 0.9394 - val_loss: 0.1775 - val_acc: 0.9345 Epoch 10/10 4396/4396 [==============================] - 114s 26ms/step - loss: 0.1243 - acc: 0.9530 - val_loss: 0.1738 - val_acc: 0.9412シェルティー判定プログラム作成
いよいよシェルティー判定プログラムを用意するときがきました。
確認用の画像を用意していよいよ実行です。
ai\main.py
# -*- coding: utf-8 -*- from keras import models from keras.models import model_from_json from keras.preprocessing import image import numpy as np import sys import os from keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array, array_to_img # モデル保存先 MODEL_ROOT_DIR = './../data/model/' MODEL_PATH = os.path.join(MODEL_ROOT_DIR, 'model_predict.json') WEIGHT_PATH = os.path.join(MODEL_ROOT_DIR, 'model_predict.hdf5') # カテゴリ CATEGORIES = [u'シェルティー', u'コーギー', u'ボーダーコリー'] # 画像サイズ IMG_SIZE = 150 INPUT_SHAPE = (IMG_SIZE, IMG_SIZE,3) # モデルを読み込む model = model_from_json(open(MODEL_PATH).read()) model.load_weights(WEIGHT_PATH) # 入力引数から画像を読み込む args = sys.argv img = image.load_img(args[1], target_size=INPUT_SHAPE) x = image.img_to_array(img) x = np.expand_dims(x, axis=0) # モデルで予測する features = model.predict(x) print(features) if features[0, 0] == 1: print(u'シェルティーです。') else: for i in range(0, len(CATEGORIES)): if features[0, i] == 1: print(u'シェルティーではないようです。{}です。'.format(CATEGORIES[i]))(ml)> cd e:\python\ml\src\ai (ml)> python .\main.py '..\data\img\test\sheltie_00.jpg' Using TensorFlow backend. 2019-11-15 17:58:44.863437: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 [[1. 0. 0.]] シェルティーです。 (ml)> python .\main.py '..\data\img\test\corgi_00.jpg' Using TensorFlow backend. 2019-11-15 17:58:55.519838: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 [[0. 1. 0.]] シェルティーではないようです。コーギーです。 (ml)> python .\main.py '..\data\img\test\bordercollie_00.jpg' Using TensorFlow backend. 2019-11-15 17:59:06.457517: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 [[0. 0. 1.]] シェルティーではないようです。ボーダーコリーです。sheltie_00.jpg
シェルティーです。cogy_00.jpg
シェルティーではないようです。コーギーです。bordercolli_00.png
シェルティーではないようです。ボーダーコリーです。いい感じに判定できました。
フランちゃんはシェルティー?
アイコンにも使用しているフランちゃんはどう判定されるでしょう。
(ml)> python .\main.py '..\data\img\test\fran.jpg' Using TensorFlow backend. 2019-11-15 17:59:28.118592: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 [[0. 0. 1.]] シェルティーではないようです。ボーダーコリーです。fran.png
シェルティーではないようです。ボーダーコリーです。残念。。。
うちのフランちゃんはシェルティーなのに「シェルティーではないようです。ボーダーコリーです。」と判定されました。
理由はおそらく教師データに黒いシェルティーが少なかったからだと考えられます。
教師データの重要性を痛感しました。追記
画像を変えてリベンジしました。
(ml)> python .\main.py '..\data\img\test\fran_01.jpg' Using TensorFlow backend. 2019-11-18 17:21:07.929836: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 [[1. 0. 0.]] シェルティーです。うちのフランちゃんがシェルティーとして判定されました。
展望
- 教師データに黒いシェルティーを追加してリベンジする
- Web アプリに AI を組み込む
- CNN について理解する
- 投稿日:2019-11-15T18:03:49+09:00
PHP→Pythonの呼び出し時に'ascii' codec can't encode characters in position xx-xx: ordinal not in range(128)
Pythonでスクリプト書いて、PHPから呼び出したい。
Python側をコンソール上で動作確認して、
PHPでフロント作って呼び出そうとしたらこれ'ascii' codec can't encode characters in position 28-32: ordinal not in range(128)ascii?コンソール上で動くけど?
locale変更してもダメ試しにpython実行コマンドで
LC_ALL=\"ja_JP.utf8\" python test.pyのように定義したら動いた。
分からんわこんなん。
P.S. 上司ありがとう。
- 投稿日:2019-11-15T17:36:30+09:00
DjangoのModelsはDB製品が変わっても大丈夫なのか?
目的
とある知り合いが、「なんでDjangoの書籍とか研修はsqlite3が前提なんじゃ!既存のDBをそのまま使ってDjangoでWebアプリ作りたいんじゃ!とりあえずsqliteで練習して後から本番DBに差し替えられないのか!?」とかぬかしおったので検証。結論を言ってしまうと、とりあえず実現できました。
本記事では検証用に簡単なWebアプリを作っていますが、Djangoの詳しい使い方についてはちゃんと触れていませんのでご了承ください。
検証環境
- Django 2.2.4
$ pip install djangoPostgreSQL 9.6.12
Webページ(https://www.postgresql.jp/download) 等からダウンロードし、インストールします。Djangoで簡単なWebアプリを開発する
今回は、とりあえず商品一覧を表示するだけの簡単なアプリケーションを作成してみます。
特に検索機能等はつけず、純粋に全件表示するだけです。Djangoプロジェクトの作成
プロジェクト用のファイルを展開するために適当なフォルダを検討し、コンソール等で以下のコマンドを叩きます。
#Djangoプロジェクトを作成 > django-admin startproject my_project #プロジェクトフォルダに移動 > cd my_project #テストサーバを起動してみる > python manage.py runserverブラウザを立ち上げて、http://127.0.0.1:8000にアクセスしてみます。
テストページが表示されれば、プロジェクトの作成は完了です。
サーバを停止させたい時は、Ctrl+Cを押します。
アプリケーションを作成する
Djangoではプロジェクト内に複数の「アプリケーション」を登録することができ、それら一つ一つが単体のWebアプリを構成します。つまり、ここからさらに「アプリケーション」とやらを作る必要があります。
以下コマンドで、アプリケーションを作ることができます。今回はwebshoppingという名前で登録します。
> python manage.py startapp webshopping
自動的にアプリケーションと同名のフォルダが出来上がり、様々なファイルが展開されます。
my_project |-- manage.py |-- db.sqlite3 |-- my_project | |-- __pycache__ | |-- settings.py | |-- urls.py | (略) |-- webshopping |-- migrations |-- apps.py |-- models.py |-- views.py (略)次に、アプリケーションの登録を行います。
my_project/settings.pyに既に記述があるので、追記するイメージです。my_project/settings.pyINSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'webshopping.apps.WebshoppingConfig' #追記 ]Webページの準備
Webページは、以下の場所にtemplatesフォルダを作り、その中に配置することになっているので
templatesフォルダとhtmlを一枚作ります。my_project |-- manage.py |-- db.sqlite3 |-- my_project | |-- __pycache__ | |-- settings.py | |-- urls.py | (略) |-- webshopping |-- migrations |-- apps.py |-- models.py |-- views.py |-- templates <--作成 |-- itemlist.html <--作成 (略)htmlファイルの中身はこんな感じにします。
webshopping/templates/itemlist.html<!DOCTYPE html> <html> <body> <h1>商品一覧</h1> <table border=1> <tr> <th>商品名</th> <th>価格</th> </tr> </table> </body> </html>Python関数(View)とWebページのマッピング
このWebページと、Python関数(View)とマッピングします。
このマッピングは、webshopping/views.pyで定義します。webshopping/views.pyfrom django.shortcuts import render # 以下の関数を追加 def itemlist(request): return render(request, 'itemlist.html')URLとViewのマッピング
次に、特定のURLへリクエストが来たときにこの関数が動くようにマッピングを調整します。
このマッピングはmy_project/urls.pyで定義します。my_project/urls.pyfrom django.contrib import admin from django.urls import path from webshopping import views #追加 urlpatterns = [ path('admin/', admin.site.urls), path('itemlist/', views.itemlist) #追加(itemlist/にリクエストが来たらviews.itemlist関数を動かす) ]確認
とりあえず色々そろったので、確認してみます。
サーバを起動してから、http://127.0.0.1:8000/itemlistへアクセスしてみます。Modelクラスを準備する
DjangoではSQLをほぼ書かずにDBを構築することができます。
「顧客」「商品」「社員」等ひとかたまりのデータ群をModelクラスとして定義し、
クラスに書かれている内容を元に勝手に構築やデータの取得、書き込みを行ってくれます。ではModelを書いていきます。Modelはwebshopping/models.pyに追記していきます。
webshopping/models.pyfrom django.db import models #以下のクラスを追記 class Item(models.Model): #クラスが持つ(あるいはDBのテーブルが持つ)べきデータを定義する item_name = models.CharField(primary_key=True, max_length=20) #商品名(文字データなのでCharField) price = models.IntegerField() #価格(数字データなのでIntegerField)データベースと同期する
コンソールを立上げ、以下のコマンドを実行することで簡単にデータベースのテーブルを構築できます。
> python manage.py makemigrations webshopping > python manage.py migrate webshopping適当なデータを突っ込む
これでテーブルはできていますが、中身が何もないのであまりおもしろくありません。
コンソールを使って、データを突っ込んでいきましょう。> python manage.py shell IN [1]: from webshopping import models IN [2]: models.Item('重すぎるノートPC', 80000).save() IN [3]: models.Item('軽すぎるノートPC', 120000).save() IN [4]; exit()これで2件の商品が登録された状態です。
View関数でDBから値を取得するように調整する
webshopping/views.pyを調整していきます。
webshopping/views.pyfrom django.shortcuts import render from webshopping import models #追加 def itemlist(request): #追加 context = { 'item_list': models.Item.objects.all() #DBから情報を取得する } #変更 return render(request, 'itemlist.html', context=context)View関数から渡された値を利用するようにHTMLを調整する
webshopping/templates/itemlist.htmlを調整していきます。
webshopping/templates/itemlist.html<!DOCTYPE html> <html> <body> <h1>商品一覧</h1> <table border=1> <tr> <th>商品名</th> <th>価格</th> </tr> <!--以下を追加--> {% for item in item_list %} <tr> <td>{{ item.item_name }}</td> <td>{{ item.price }}</td> </tr> {% endfor %} </table> </body> </html>確認
PostgreSQLのデータベースを用意する
いよいよPostgreSQLに切り替えて行きます。
PostgreSQLのインストールとデータベースの作成
PostgreSQLをインストールし、適当なユーザ名とパスワードを設定しておきます。
この時点では、データベースのみ作りテーブルは作りません。> psql -U postgres -W ユーザpostgresのパスワード: *********** postgres=# create database webshopping; CREATE DATABASEDjango側の設定をいじる
実は参照先DBの設定は、my_project/settings.pyにあります。
DATABASESと書いてあるところを探し、以下のように書き換えます。
(元の設定はコメントアウトしておくことをオススメします。my_project/settings.py#(略) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'webshopping', #1つ上の項目で作成したデータベースの名前 'USER': 'postgres', #DBにログインするユーザ名 'PASSWORD': 'P@ssw0rd', #DBにログインするパスワード 'HOST': 'localhost', 'PORT': '', } } #(略)設定をDBと同期する
再度設定をDBと同期させます。
> python manage.py migrate webshopping
データを流し込む
再度データを流し込んでいきます。実際に移行する場合は、ここで一旦CSVやSQLファイルに吐き出しておいてからインポートする流れになるでしょう。
> python manage.py shell IN [1]: from webshopping import models IN [2]: models.Item('重すぎるノートPC', 80000).save() IN [3]: models.Item('軽すぎるノートPC', 120000).save() IN [4]; exit()PostgreSQL側のデータを確認
一応、PostgreSQLにログインしてデータが入っているか確認します。
> psql -U postgres -W ユーザpostgresのパスワード: *********** postgres=# \c webshopping webshopping=# \d リレーションの一覧 スキーマ | 名前 | 型 | 所有者 ----------+--------------------------+------------+---------- public | django_migrations | テーブル | postgres public | django_migrations_id_seq | シーケンス | postgres public | webshopping_item | テーブル | postgres (3 行) webshopping=# select * from webshopping_item; item_name | price ------------------+-------- 重すぎるノートPC | 80000 軽すぎるノートPC | 120000 (2 行)うまくいっているようです。
Webページで確認
最後に、サーバを立上げ直してWebで確認してみます。
問題なさそうです!!
結論
- ModelsはDB製品が変わったとしても特に大きな影響は無し
- 別件で日付も検証したが、sqlite3のdatetime型とpsqlのdate型ならpythonのdatetime.date型で特に問題なさそう
- 製品が変わってもほぼコードいじらなくていい、なんならSQLもほぼ書かなくていいDjangoバンザイ!
- 投稿日:2019-11-15T17:22:05+09:00
Pythonによる二値化画像処理の基本
画像処理
画像の加工、解析を行うためによくされる画像処理である。おぼえておくと、画像ファイルの減少などもできるので覚えておくとよい。
二値化画像
グレースケール画像ともいう。白黒することである。画像処理の基本となる。
環境
・jupyternotebook
・python version == 3.7.4
・sample.jpg(from http://free-photo.net/archive/entry10252.html)
ソースコード
#opencvとnumpyのimport import cv2 import numpy as np #画像の読み込み img = cv2.imread("sample1.jpg") #グレースケール変換 gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) #閾値の設定 threshold_value = 150 #配列の作成(output用) threshold_img = gray.copy() #実装(numpy) threshold_img[gray < threshold_value] = 0 threshold_img[gray >= threshold_value] = 255 #Output cv2.imwrite("C:\\Users\\fgdao\\python\\sample1-2.jpg",threshold_img)出力画像結果
閾値の設定のところで、"150"ではなく、ほかの数字で試してみると白黒の位置変化がみられる。
imageJ(URL:"https://imagej.nih.gov/ij/")
などのソフトを使うとそういった変化もリアルタイムで見ることができるので、使ってみるとよい。
- 投稿日:2019-11-15T17:10:47+09:00
「Kaggleで勝つ」を読んでみた。?
本全体の感想
実際に上位のkagglerが使用した手法が記載されていて面白い。また数学的知識や数学に嫌悪感のある人でもかなりわかりやすく説明してくれている。また機械学習をしない人でも知見として軽く読むには適していると感じた
本の構成
- はじめに
- 分析コンペとは
- タスクと評価指標
- 特徴量の作成
- モデルの作成
- モデルの評価
- モデルのチューニング
- アンサンブル
1 はじめに
目次を読んで好奇心をあげるために読んだ。あらかじめ機械学習をちょろっと知ってる人なら好奇心あげあげ
2 分析コンペとは
この辺は分析コンペのモラルとかルールとかが記載されている。コンペに参加する場合は読んでみて損はない
3 タスクと評価指標
kaggle側がどのような評価指標を使っているか知れる。もちろんこの辺は実務的なことに使えてくるのでここから読み始めるのがおすすめ。評価指標を知ることは自分の見解だと機械学習を行う上で二番目に大事なことだと思います。
4 特徴量の作成
この本は後半モデル(学習器)の話が多いけどここが一番大事。ここだけでかなりの知見を得ることができた。この本は機械学習の本じゃなくてコンペ専用の本なのでここが詳しくなるのは必然かな。。すなわち機械学習を行うので一番大事なのは前処理ってことです。(個人的な意見です)
5 モデルの作成
数学的でなく直感的にモデルどんなものか知れる。使うだけなら非常に便利。特にGBDTに詳しく書いてある。ここ読むだけで機械学習の話ができるようになるかも
6 モデルの評価
三番目に大事なのがここの章かもしれない。なぜかというと後述のアンサンブルは実務的ではなくコンペで気持ちよくなるのが目的と言った印象
簡単にいうとバリデーションがでぇーじ、時系列データのバリデーションの注意点も教えてくれる7 モデルのチューニング
ここの読んだ時の印象は「え、もっと早く教えてくんね?」って感じです。今まで読んだ本の中でもかなり効率よく見やすく教えてくれる。(そんな読んだことないけど)ありがとうございました
8 アンサンブル
みんな気になるアンサンブル。スタッキングについて全体像を理解するのにかなり助かった。正直ここ読むまでスタッキングが何かわかった気になっていた。数学的知識も不要。
また実際にkaggleで使われた例を何個もあげてくれているので想像がとてもしやすいかなり雑に書いたので誤字脱字がたくさんあると思います。
- 投稿日:2019-11-15T17:00:10+09:00
Jupyter Notebookの拡張機能、nbextensionsの設定について 自分用
タイトル通り、nbextensionsの個人的の設定について。
導入
参考にしたサイト
https://www.pynote.info/entry/jupyter-notebook-nbextensions#インストール pip install jupyter-contrib-nbextensions (pip install jupyter-nbextensions-configurator) #上記の時点であるっぽい? #有効化 jupyter contrib nbextension install --user jupyter nbextensions_configurator enable --userアンインストール、無効化したい場合は以下の通り。
参考にしたサイト
https://github.com/ipython-contrib/jupyter_contrib_nbextensions/issues/1012#無効化 jupyter contrib nbextension uninstall --user jupyter nbextensions_configurator disable --user #アンインストール pip uninstall jupyter-contrib-nbextensions pip uninstall jupyter-nbextensions-configuratornbextensionsの設定
参考にしたサイト
https://qiita.com/simonritchie/items/88161c806197a0b84174
- 投稿日:2019-11-15T16:38:05+09:00
Python (第一章:初めて~実行まで)
はじめに
初心者(インストールしたこともない)人のためのページ
windows上での説明になります。macの人は違うページへ。インストール
まずはpythonをインストールしよう。
https://www.python.org/1)このページに"Downloads"にカーソルを当てて"Windows"を選択。
2)その中から、"Python 3.8.0 - Oct. 14, 2019"の下にある"Download Windows x86-64 executable installer"を探してクリック!
3)そのあと、Pythonのinstallerが勝手にダウンロードが始まります。あとは、全部、次へっぽいボタンをどんどん押していく!
4)最後に、installとあると思うので、それをクリックすればPythonそのもののインストールが始まります!これで、Python本体のインストールは終了です!
Hello Worldの表示
「Hello Wolrd!」を表示させてみましょう。
"メモ帳"というアプリを開いて、print('Hello World!')と入力して、保存してください。保存するとき、"Ctrl+S"の2つのキーを押すと保存画面に行きます。
保存画面へと言ったら、
ファイル名を"test.py"
とおき、下の方にある、文字コードを
"UTF-8"
と設定してから、保存しましょう!場所は取り合えず、デスクトップ(Desktop)へ。
保存が終わったら、コマンドプロンプトの起動をしてください。
画面の左下にある「ここに入力して検索」のところに"cmd"
と打ち、Enterを押せば、黒い画面が起動します。
ここから注意。'[ ]'となっている場所は、パソコン本体に入っている名前か、任意の場所です。
起動後、
C:¥Users¥[username]>と表示される。
'>'の後に続けて、cd Desktopを入力。その後に、
C:¥Users¥[username]¥Desktop>と表示されます。
またまたその'>'に続けてpython test.pyと入力してください。
そうすると、Hello World!と出てきます。以上!
ちなみに、
print('')
はもうすでに、Python言語です。
Pythonが打てて実行できる状態になりました。これが環境設定のベースとなる部分です。
- 投稿日:2019-11-15T16:00:17+09:00
【Python中級者への道】クラスに__getattr__関数を定義する
まとめへのリンク
https://qiita.com/ganariya/items/fb3f38c2f4a35d1ee2e8
はじめに
Pythonの勉強をするために、acopyという群知能ライブラリを写経していました。
acopyでは、多くのPythonの面白い文法・イディオムが使われており、その中でも便利だなぁというのをまとめています。
今回は、クラスに
__getattr__
特殊メソッドを定義してみます。インスタンス属性
Pythonでインスタンス内部で使用される属性を取り出す方法として
__dict__
を参照する方法があります。インスタンス内部で使用される名前空間の名前が
__dict__
に辞書として定義されています。例えば、以下のような例を見てみます。
class A: def __init__(self, x, y): self.x = x self.y = y # {'x': 10, 'y': 20} a = A(10, 20) print(a.__dict__)aというインスタンスには、$x, y$の名前が存在し
それらを辞書として取り出すことができます。
__getattr__
Pythonのクラスには、
__getattr__
という特殊メソッドを定義することができます。Pythonのインスタンスの名前呼び出しにおいて
もし定義されていない名前で呼ばれればAttributeErrorを返します。しかし、もし
__getattr__
が定義されている場合は、
「名前が定義されていない呼び出し時に」AttributeErrorを返す代わりに、__getattr__
が実行されます。例を見てみます。
class A: def __init__(self, x, y): self.x = x self.y = y def __getattr__(self, name): print(name, 'getattr') if name == 'hello': return self.world raise AttributeError def world(self, x): return x ''' {'x': 10, 'y': 20} hello getattr <bound method A.world of <__main__.A object at 0x10e602150>> hello getattr 20 ''' a = A(10, 20) print(a.__dict__) print(a.hello) print(a.hello(20))上のAクラスには
__getattr__
メソッドが定義されています。
a.hello
を呼び出そうとすると、helloという属性がaに定義されていません。
そのため、__getattr__
メソッドが呼び出され、代わりにworldメソッドを返しています。
a.hello(20)
では、まずworldメソッドが返されて、worldメソッドに20という値を与えて実行しています。
よって、helloという名前が確定した時点で実行されています。よって、以上の性質を使うと、以下のような無駄コードをかけます。
class A: def __init__(self, x, y): self.x = x self.y = y def __getattr__(self, name): print(name, 'getattr') if name == 'hello': return self.world if name == 'world': return self.great if name == 'great': return self.bad if name == 'bad': return 0 raise AttributeError ''' {'x': 10, 'y': 20} hello getattr world getattr great getattr bad getattr 0 ''' a = A(10, 20) print(a.__dict__) print(a.hello)応用例
あまり応用例は思いつきませんが、
もし属性がない場合に代わりの規程処理をやらせる、などがあるのかなと思います。
また、分岐などを呼び出し名によって変えるなどがありそうです。class A: def __getattr__(self, name): self.nothing(name) def exist(self): print('exist!') def nothing(self, name): print(f'nothing {name}') ''' exist! nothing unnti ''' a = A() a.exist() a.unntiまた、後日別記事として各内容として
lambda式で名前がないとき例外コードを投げるなどでも使えそうです。参考文献
- 投稿日:2019-11-15T15:48:41+09:00
Winsows10でゼロから機械学習環境を作ってみる
はじめに
皆さん、やってますか?
機械学習
ここ数年、第3次AIブームなんて言われて、もてはやされているアイツです。
人工知能、機械学習、ニューラルネットワーク、ディープラーニング
最近、黙々と勉強してはいますが、 ん~…なんだか難しいですね…。今回は、その辺はいったん置いておいて、機械学習の環境をサクッと作っちゃいましょうというお話です。
意外と簡単に作れちゃいます。
(参考記事はたくさんあると思いますが、自分用メモも兼ねてます)
Google Colaboratory
でいいじゃん~って方は
こちらPC環境
・OS:Windows10 Pro
・GPU:GeForce 940MX
・CPU:Core i5-7200U
・メモリ:16GBnVIDIA CUDA ToolkitとcuDNNのインストール
まずは こちらの記事 を参考に
CUDA Toolkit
とcuDNN
をインストールしちゃいましょう。
TensorFlow(GPU版)
を使う場合に必要になるためです。注意点としては、記事中のリンクでCUDAをダウンロードしてしまうと、最新の10.1になってしまい、TensorFlowで使う場合シンボリックリンクを設定しなければならないため、こちら から10.0のアーカイブをダンロードしてインストールした方が楽です。
Anacondaのインストール
Pythonの環境は
Anaconda
を使います。実のところ一度、素の
Python3.7
環境でも機械学習の環境を作りました。
そして「Windows10でAnacondaなしで機械学習環境を作る」
みたいな記事を書こうと思いました。ですが、調べているうちに
condaでインストールした環境の方が速度が速い
という記事をいくつか見つけたため、
「え~?じゃあAnaconndaで環境作り直す~?」
という気持ちで改めて、AnacondaでPython環境を構築しました。ということでまずはAnacondaの公式からインストーラをダウンロードしてインストールします。
途中の
Add Anaconda to my PATH environment variavle
はチェックを入れておけば、環境変数にAnaconda系のパスが勝手に入ると思います。インストール後は、コマンドプロンプトやPowerShell等で
conda
python
pip
の3つを実行しパスが通っているか確認しましょう。仮想環境作成
AnacondaはPythonの環境をお手軽に作れてしまします。
どういう利点があるのかとか、詳しく知りたい人は今回はGoogle先生にお任せします。仮想環境を作成するコマンドは以下
> conda create --name myenv python=3.7myenvの部分は仮想環境の名前なのでお好きな名前にしちゃってください。
これだけで環境がバンバン作れちゃいます。環境の切り替えは
> conda activate myenv
で切り替えられます。
※ 注意として、よく見かけるのが、condaがついていない
> activate myenv
ですが、古いバージョンの書き方のようで、
一見何もエラーがなく切り替わったように見えますが、
後述のinfo
で調べても環境が切り替わっていません。自分が今どの環境をアクティブにしているか確認するには
> conda info -eで以下のように確認できます。
# conda environments: # base C:\Users\<ユーザー名>\Anaconda3 myenv * C:\Users\<ユーザー名>\Anaconda3\envs\myenv「*」がついているのが現在の環境です。
必要そうなパッケージのインストール
必要そうな
と書いているように、もしかしたらいらないかもしれません。
いろんな機械学習を試してみたい!って場合は必要かも。conda install pandas conda install scikit-learn conda install scikit-image
OpenAI Gym環境インストール
pip install gym conda install -c conda-forge jsanimation conda install pyglet conda install -c conda-forge ffmpeg pip install --no-index -f https://github.com/Kojoley/atari-py/releases atari_py
conda install
とpip install
を混在させると環境が壊れるという話もあるので、
できればpip install
は使わないようにしたいのですが、Anacondaにパッケージがない場合はやむなし…。KerasとTensorFlow環境インストール
TensorFlow
あればKeras
内包されてるし、いらないんじゃない?
という意見もあるかと思いますが、サンプルとかで混在している場合もあったりするので、念の為。conda install -c conda-forge keras conda install pydotplus conda install tensorflow conda install tensorflow-gpu
完成!
以上で、ある程度の機械学習の環境が整いました。
最終的な
conda list
# Name Version Build Channel _tflow_select 2.1.0 gpu absl-py 0.8.1 py37_0 astor 0.8.0 py37_0 astroid 2.3.2 py37_0 atari-py 1.2.1 pypi_0 pypi blas 1.0 mkl ca-certificates 2019.10.16 0 certifi 2019.9.11 py37_0 cloudpickle 1.2.2 py_0 colorama 0.4.1 py37_0 cudatoolkit 10.0.130 0 cudnn 7.6.4 cuda10.0_0 cycler 0.10.0 py37_0 cytoolz 0.10.0 py37he774522_0 dask-core 2.6.0 py_0 decorator 4.4.1 py_0 ffmpeg 4.2 h6538335_0 conda-forge freetype 2.9.1 ha9979f8_1 future 0.18.2 pypi_0 pypi gast 0.2.2 py37_0 google-pasta 0.1.7 py_0 grpcio 1.16.1 py37h351948d_1 gym 0.15.4 pypi_0 pypi h5py 2.9.0 py37h5e291fa_0 hdf5 1.10.4 h7ebc959_0 icc_rt 2019.0.0 h0cc432a_1 icu 58.2 ha66f8fd_1 imageio 2.6.1 py37_0 intel-openmp 2019.4 245 isort 4.3.21 py37_0 joblib 0.14.0 py_0 jpeg 9b hb83a4c4_2 jsanimation 0.1 py_1 conda-forge keras 2.3.1 py37h21ff451_0 conda-forge keras-applications 1.0.8 py_0 keras-preprocessing 1.1.0 py_1 kiwisolver 1.1.0 py37ha925a31_0 lazy-object-proxy 1.4.3 py37he774522_0 libgpuarray 0.7.6 hfa6e2cd_1003 conda-forge libpng 1.6.37 h2a8f88b_0 libprotobuf 3.9.2 h7bd577a_0 libtiff 4.1.0 h56a325e_0 mako 1.1.0 py_0 conda-forge markdown 3.1.1 py37_0 markupsafe 1.1.1 py37hfa6e2cd_0 conda-forge matplotlib 3.1.1 py37hc8f65d3_0 mccabe 0.6.1 py37_1 mkl 2019.4 245 mkl-service 2.3.0 py37hb782905_0 mkl_fft 1.0.15 py37h14836fe_0 mkl_random 1.1.0 py37h675688f_0 networkx 2.4 py_0 numpy 1.17.3 py37h4ceb530_0 numpy-base 1.17.3 py37hc3f5095_0 olefile 0.46 py37_0 opencv-python 4.1.1.26 pypi_0 pypi openssl 1.1.1d he774522_3 opt_einsum 3.1.0 py_0 pandas 0.25.2 py37ha925a31_0 pillow 6.2.1 py37hdc69c19_0 pip 19.3.1 py37_0 protobuf 3.9.2 py37h33f27b4_0 pydotplus 2.0.2 py37_1 pyglet 1.3.2 pypi_0 pypi pygpu 0.7.6 py37hc8d92b1_1000 conda-forge pylint 2.4.3 py37_0 pyparsing 2.4.2 py_0 pyqt 5.9.2 py37h6538335_2 pyreadline 2.1 py37_1 python 3.7.5 h8c8aaf0_0 python-dateutil 2.8.1 py_0 pytz 2019.3 py_0 pywavelets 1.1.1 py37he774522_0 pyyaml 5.1.2 py37hfa6e2cd_0 conda-forge qt 5.9.7 vc14h73c81de_0 scikit-image 0.15.0 py37ha925a31_0 scikit-learn 0.21.3 py37h6288b17_0 scipy 1.3.1 py37h29ff71c_0 setuptools 41.6.0 py37_0 sip 4.19.8 py37h6538335_0 six 1.12.0 py37_0 sqlite 3.30.1 he774522_0 tensorboard 2.0.0 pyhb230dea_0 tensorflow 2.0.0 gpu_py37h57d29ca_0 tensorflow-base 2.0.0 gpu_py37h390e234_0 tensorflow-estimator 2.0.0 pyh2649769_0 tensorflow-gpu 2.0.0 h0d30ee6_0 termcolor 1.1.0 py37_1 theano 1.0.4 py37h6538335_1000 conda-forge tk 8.6.8 hfa6e2cd_0 toolz 0.10.0 py_0 tornado 6.0.3 py37he774522_0 tqdm 4.36.1 py_0 vc 14.1 h0510ff6_4 vs2015_runtime 14.16.27012 hf0eaf9b_0 vs2015_win-64 14.0.25420 h55c1224_11 webencodings 0.5.1 py37_1 werkzeug 0.16.0 py_0 wheel 0.33.6 py37_0 wincertstore 0.2 py37_0 wrapt 1.11.2 py37he774522_0 xz 5.2.4 h2fa13f4_4 yaml 0.1.7 hfa6e2cd_1001 conda-forge zlib 1.2.11 h62dcd97_3 zstd 1.3.7 h508b16e_0まとめ
つらつらとインストールして、今は1つの仮想環境にいろいろまとめて入っていますが。
用途
によって別途仮想環境を作って分けて
もいいと思います。あとは、サンプルを探して動かしてみるなり、
自分で試行錯誤してみたり、いろいろ試せるようになると思います!・
・
・
と言いたいところですが、TensorFlow2.0.0
のサンプルがまだまだ転がってない状況なんですよね…。
過去バージョンのサンプルはたくさんあるのですが、2.0.0
で変わった箇所が多く、そのままでは動かないこと多数です。TensorFlowの公式も
GoogleColaboratory
でチュートリアルを体験できるようになっています。
(Googleが開発したライブラリなので当然っちゃ当然ですが)なので、旧バージョンのサンプルを自分なりに理解して、改変できるくらいの知識はやはり必要そうですね…_(┐「ε:)_
まだまだ機械学習についてはで勉強中ですが、今後何かおもしろいことができるようになってきたら、
自分の脳のメモリが追いつく限り、発信していければなーと思っています!
(既にパンパン)
- 投稿日:2019-11-15T14:46:56+09:00
RandomForest 使ってみた
今回の目的
SIGNATEのPractice,ワインの品種の予測を行う.
本題
用いた学習アルゴリズム
- SVC
- LogisticRegression(ロジスティック回帰)
RandomForest
(ランダムフォレスト)3つのアルゴリズムを試した結果, ランダムフォレストが一番精度が高くなったため, 最終的な分類器として採用した.
コード
データの読み込み
wine-learning.pywine_data = pd.read_csv('train.tsv',sep='\t') wine_test = pd.read_csv('test.tsv',sep='\t')前回は
read_table
を用いたが, せっかくなのでread_csv
も使ってみた. tableのほうが楽な気がします.
ちなみに, どちらも呼び出すメソッドは同じっぽいのでどちらが正しいとかはない.特徴量データと教師データの分離
wine-learning.pyX = wine_data.loc[:,['Alcohol','Malic acid','Ash','Alcalinity of ash','Magnesium','Total phenols','Flavanoids','Nonflavanoid ohenols','Proanthocyanins','Color intensity','Hue','OD280/OD315 of diluted wines','Proline']].values y = wine_data.loc[:,'Y'].values変数が多いと長くなりがちだからこれをどうにかしたい. 次の課題をやるときに改善できる方法があるか検討してみる.
ちなみにここでテストデータもやっとくwine-learning.pyXt = wine_test.loc[:,['Alcohol','Malic acid','Ash','Alcalinity of ash','Magnesium','Total phenols','Flavanoids','Nonflavanoid ohenols','Proanthocyanins','Color intensity','Hue','OD280/OD315 of diluted wines','Proline']].values学習データとテストデータに分割
wine-learning.pyX_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2)今回もデータを8:2の割合で分割して行った.
欠損値の削除
wine-learning.pyX_train = X_train[:, ~np.isnan(X_train).any(axis=0)] X_test = X_test[:, ~np.isnan(X_test).any(axis=0)] Xt = Xt[:, ~np.isnan(Xt).any(axis=0)]分割前まではなかった欠損値が突然現れた. 原因がわからなかったので,そのうち検証してみようと思う.
今回は欠損値を削除する方針にした.モデルの学習
SVC
wine-learning.pyclf = svm.SVC() clf.fit(X_train, y_train)ロジスティック回帰
wine-learning.pyclf = LogisticRegression() clf.fit(X_train, y_train)ランダムフォレスト
wine-learning.pyclf = RandomForestClassifier(n_estimators=500, random_state=0) clf.fit(X_train, y_train)random_stateは0,n_estimators(決定木の個数)は多めに500を設定した.
モデルの評価
wine-learning.pyy_pred = clf.predict(X_test) accuracy = accuracy_score(y_test, y_pred) print('正解率 = ' , accuracy)例のごとく,
accuracy
関数を用いて正解率を出した。SVCの正解率
正解率 = 0.6111111111111112ロジスティック回帰の正解率
正解率 = 0.8888888888888888ランダムフォレストの正解率
正解率 = 1.0分類
wine-learning.pyX_pred = np.array(Xt) y_pred = clf.predict(X_pred) print(y_pred)結果
やりました(パチパチ)
検討事項
- 変数の量によって学習アルゴリズムを変える.
- 変数の数を落とす(次元削除)作業を行ってから学習アルゴリズムを適用する.
- そもそものアルゴリズムの特性を理解する.
- データ分割の時点で発生した欠損値の原因追及
- 混合行列の採用
- 投稿日:2019-11-15T14:46:33+09:00
Pythonで問題解いてみた Vol.1
はじめに
今回からAtCoderににある問題を解いて、定期的にその問題の内容や
解説を投稿していこうと思います何回続くかも分からないし需要があるかも分からないですが、誰かが
問題に詰まった時にお役に立てたら幸いですでは、今回からゆるーく続けていきたいと思うのでよろしくお願いします
早速いきます!
今回は3問解いてみました!
それでは早速問題の説明・解説していきます「9x9」
問題文
高橋君は九九を覚えたので、1以上9以下の2つの整数の積を計算することが
できます。それ以外の計算はできません。2 つの整数A,Bが与えられます。
高橋君がA×Bを計算できるならその結果を、できないなら代わりに-1を
出力してください。制約
1 ≤ A ≤ 20
1 ≤ B ≤ 20
入力中のすべての値は整数である。入力
入力は以下の形式で標準入力から与えられる。
A,B出力
高橋君が A × Bを計算できるならその結果を、できないなら-1を出力せよ。
という問題でした。私の答えは ↓ の通りです。
9x9.pyA , B = map(int, input().split()) if 1 <= A and A <= 9 and 1 <= B and B <= 9: print(A * B) else: print(-1)カンタンに説明しますね
まずは"変数 , 変数 = map(型,input().split())"の形で二つの変数に
標準入力から入力させます。".split()"を使うと、スペースで区切って
入力された文字列を分割して入力できます。ちなみに".sprit("と")"
という風に入力すると"と"という文字で区切ってくれます次に"if"と"and"を使って複数の条件を作り、それに当てはまった場合に
"print"でAとBの掛け算の結果を出力させます。
条件に合わなかった場合は"-1"を出力します。以上です!簡単ですね
次行きましょう「Curtain」
問題文
高橋君の家の窓の横方向の長さは A であり、横方向の長さが B の
カーテンが 2 枚取り付けられています。(カーテンは縦方向には
窓を覆うのに十分な長さがあります。)窓のうちカーテンで隠されていない部分の横方向の長さが最小に
なるようにカーテンを閉めます。 このとき、窓のカーテンで隠されて
いない部分の合計の横方向の長さを求めてください。制約
1 ≤ A ≤ 100
1 ≤ B ≤ 100
A , B は整数である。入力
入力は以下の形式で標準入力から与えられる。
A , B出力
窓のうちカーテンで隠されていない部分の合計の横方向の長さを出力せよ。
窓がカーテンで完全に隠される場合は 0 と出力してください。
各カーテンが窓の横幅より長い場合があります。という問題でした。私の答えは ↓ です。
Curtain.pyA , B = map( int, input().split()) if(A - (B * 2) <= 0): print(0) else: print(A - (B * 2))これはまず、"変数 , 変数 = map(型,input().split())"の形で二つの変数に
標準入力から入力させます。"split()"なので空白区切り文字として入力です
次に"if(条件)"の文でカーテンで窓が隠れるか隠れないかの判断をし、
隠れた場合は"0"、隠れなかった場合は隠れていない横の長さ"A - (B * 2)"
を"print()"文で表示します。以上です。これまた簡単ですね
次で今回のラストです!「Tenki」
問題文
ある 3 日間の天気予報が、長さ 3 の文字列 S として与えられます。
S の i(1 ≤ i ≤ 3) 文字目が S のとき、i 日目の天気予報が晴れだったことを、
C のときは曇りだったことを、R のときは雨だったことを意味します。
また 3 日間の実際の天気が、長さ 3 の文字列 T として与えられます。
T の i(1 ≤ i ≤ 3) 文字目が S のとき、i 日目の実際の天気が晴れだったことを、
C のときは曇りだったことを、R のときは雨だったことを意味します。
3 日間で天気予報が的中した日が何日あるかを出力してください。制約
S および T は長さ 3 の文字列である。
S および T は S, C, R のみからなる。入力
入力は以下の形式で標準入力から与えられる。
S , T出力
3 日間で天気予報が的中した日が何日あるかを出力せよ。
という問題でした。私の答えは ↓ です。
Tenki.pyS = list(input()) T = list(input()) i = 0 x = 0 while(i < 3): if(S[i] == T[i]): x = x + 1 i = i + 1 print(x)この問題では、まずは"list(input())"で S と T に文字列をリストへ標準入力から入力
させました。
次に文字を3回比較するために変数"i"を、比較して一致した数を数えるための変数"x"を
用意しました。
あとは"while(条件)"の文で条件を"i < 1"にして処理が終わるたびに"i = i + 1"を
することで処理を3回繰り返させ、 S[] と T[] の配列の中身を順に比較して一致した場合
"x = x + 1"の処理をします。
whileから抜けたら x を"print()"で表示させることで一致した回数を表示させることが
できました終わり
今回は3つの簡単な問題を解いてみました。
正直ちょっとプログラミングが分かる人なら簡単すぎる問題だったと思います
こんな感じでゆるーく書いていこうと思うので分かりにくいところや無駄な書き方が
あったらコメントで教えていただけると私の勉強にもなってうれしいです
今回はここまで!
- 投稿日:2019-11-15T14:39:46+09:00
python csvデータを使用した計算問題
pythonでcsvデータを使用した計算を考えております。
具体的な内容としては、
1.csvファイルのgoalに着目し、異なる数字を5行抽出します。
df = pd.read_csv("start_goal.cost.csv")
df[0:15]2.やりたいこととしては、同じgoalの値を持つ3つのstart(A,B,C)の中からcostが最小(>0)となるものを抽出したいです。
これを5回(*)続け、costの総和が最小となる時のstart-goalの組み合わせを新たなcsvファイルに出力したいです。
((*)Aを選択できる回数は2回、Bを選択できる回数は2回、Cを選択できる回数は1回とします。⇒計5回)3.最初にcsvファイルから抽出した5行で5つの組み合わせが見つかればそこで終了としますが、5つの組み合わせが見つからない場合には再度csvファイルから1.で抽出した5行の次の5行を抽出し、残りの組み合わせを探します。(今回示したcsvデータでは、最初に抽出した5行で組み合わせが4つ決定する為、次の5行を抽出し、新たに抽出したデータを上から見ていき、組み合わせを決定することとします。(goalが66493,65661の時にcostが全て"-"になる為、少なくともgoalが88197,条件(*)によっては、72235まで検討を行うことになります。)
start_goal.csv
start,goal,detime,time,cost
A,84603,0.185663,0.155261921,0.160665765
B,84603,0.185663,0.306146838,0.009780848
C,84603,0.185663,0.222079925,0.093847761
A,69731,0.205922,0.290933359,0.157529338
B,69731,0.205922,0.153464999,0.294997698
C,69731,0.205922,0.234028039,0.214434658
A,66493,0.439999,0.232340368,-0.146627625
B,66493,0.439999,0.344083618,-0.258370875
C,66493,0.439999,0.233360601,-0.147647858
A,69083,0.770402,0.319535738,0.008896064
B,69083,0.770402,0.132349783,0.196082019
C,69083,0.770402,0.239396713,0.089035089
A,68044,1.96948,0.341085585,0.004103105
B,68044,1.96948,0.150513608,0.194675082
C,68044,1.96948,0.250685835,0.094502855
A,65661,2.43745,0.241541613,-0.252471114
B,65661,2.43745,0.338684945,-0.349614446
C,65661,2.43745,0.212515961,-0.223445462
A,88197,2.46186,0.182284001,0.001912936
B,88197,2.46186,0.287367027,-0.10317009
C,88197,2.46186,0.191792194,-0.007595257
A,54999,3.70759,0.325967326,-0.093275414
B,54999,3.70759,0.159753126,0.072938786
C,54999,3.70759,0.287357272,-0.05466536
A,72235,4.28023,0.289104207,0.025599918
B,72235,4.28023,0.167769969,0.146934156
C,72235,4.28023,0.250494153,0.064209972
A,95669,4.86535,0.223288997,0.114644782
B,95669,4.86535,0.299277266,0.038656513
C,95669,4.86535,0.183266565,0.154667214
A,67547,8.44938,0.223364342,-1.628245716
B,67547,8.44938,0.253998032,-1.658879406
C,67547,8.44938,0.152691651,-1.557573025
A,89495,10.035,0.261715505,-1.086858336
B,89495,10.035,0.265321578,-1.090464409
C,89495,10.035,0.132722503,-0.9578653342.3.で示した手順をどのように表現すればよいかがわからず悩んでおります。
アイデア等ある方がいらっしゃいましたら、ご教授いただけましたら幸いです。どうぞよろしくお願いいたします。
- 投稿日:2019-11-15T14:06:27+09:00
matplotlibでヒストグラムの左側の縦軸を度数、右側の縦軸を相対度数にする(邪道なやり方かも)
この記事で行うこと
この記事の続編です→「matplotlibでヒストグラムの縦軸を相対度数(棒の高さの合計=1)や相対度数密度(ヒストグラム全体の面積=1)にする」
matplotlibで、ヒストグラムを
- 左側の縦軸を度数(matplotlibのデフォルト)
- 右側の縦軸を相対度数(棒の高さの合計=1)
にして描画します。ただし、邪道なやり方かもしれません。
参考ページ(感謝します)
[python]matplotlibで左右に2つの軸があるグラフを書く方法
ソースコード(Jupyter Notebook)と描画結果
データ件数は7500件で、平均値50、標準偏差10の正規乱数にしました。
まず以下のPythonコードを実行してみます。#%% import numpy as np import matplotlib.pyplot as plt #%% # データ作成 μ = 50 σ = 10 data = [ np.random.normal(μ, σ) for i in range(7500) ] #%% # 階級数 num_bins = 20 # グラフ描画 fig = plt.figure(figsize=(12, 8)) plt.legend() plt.xlabel('x', fontsize=18) plt.title('null', fontsize=18) # (1) 縦軸を度数にしたヒストグラム ax1 = fig.add_subplot(111) ax1.set_ylabel('frequency', fontsize=18) ax1.grid(True, color="dimgray") ax1.set_axisbelow(True) # gridを最背面に移動 ax1.hist(data, bins=num_bins, rwidth=0.5, align="mid") # (2) 縦軸を相対度数にしたヒストグラム ax2 = ax1.twinx() ax2.set_ylabel('relative frequency', fontsize=18) ax2.grid(True, color="lightgrey", linestyle="--") ax2.set_axisbelow(True) # gridを最背面に移動 weights = np.ones_like(data) / len(data) ax2.hist(data, bins=num_bins, weights=weights, rwidth=0.5, align="right", color="red")縦軸=度数の棒をデフォルトの色で、縦軸=相対度数の棒を赤で、左右に並べて描画しました。
この両者の高さが同じに見えることを人が確認します(邪道たる所以..)度数と相対度数の棒の高さが同じに見えたら、棒の色を一致させます。
「color="red"」を指定せずに、ax2.hist()を呼び出します。ax2のGrid線が、ax1の棒より手前に表示されてしまいました。
この横線を見えなくするために、以下のコードを追加してax1と同じグラフを上書き描画することにしました。# (3) (1)の見栄えを調整 ax3 = ax1.twinx() ax3.set_yticklabels([]) ax3.hist(data, bins=num_bins, rwidth=0.5, align="mid")完成版のコード全体は以下の通りです。
#%% import numpy as np import matplotlib.pyplot as plt #%% # データ作成 μ = 50 σ = 10 data = [ np.random.normal(μ, σ) for i in range(7500) ] #%% # 階級数 num_bins = 20 # グラフ描画 fig = plt.figure(figsize=(12, 8)) plt.legend() plt.xlabel('x', fontsize=18) plt.title('null', fontsize=18) # (1) 縦軸を度数にしたヒストグラム ax1 = fig.add_subplot(111) ax1.set_ylabel('frequency', fontsize=18) ax1.grid(True, color="dimgray") ax1.set_axisbelow(True) # gridを最背面に移動 ax1.hist(data, bins=num_bins, rwidth=0.5, align="mid") # (2) 縦軸を相対度数にしたヒストグラム ax2 = ax1.twinx() ax2.set_ylabel('relative frequency', fontsize=18) ax2.grid(True, color="lightgrey", linestyle="--") ax2.set_axisbelow(True) # gridを最背面に移動 weights = np.ones_like(data) / len(data) ax2.hist(data, bins=num_bins, weights=weights, rwidth=0.5, align="right") # (3) (1)の見栄えを調整 ax3 = ax1.twinx() ax3.set_yticklabels([]) ax3.hist(data, bins=num_bins, rwidth=0.5, align="mid")邪道な感じなので、正攻法があれば教えてほしいです。
- 投稿日:2019-11-15T14:06:27+09:00
matplotlibでヒストグラムの縦軸の左側を度数、右側を相対度数にする(邪道なやり方かも)
この記事で行うこと
この記事の続編です→「matplotlibでヒストグラムの縦軸を相対度数(棒の高さの合計=1)や相対度数密度(ヒストグラム全体の面積=1)にする」
matplotlibで、ヒストグラムを
- 縦軸の左側を度数(matplotlibのデフォルト)
- 縦軸の右側を相対度数(棒の高さの合計=1)
にして描画します。ただし、邪道なやり方かもしれません。
参考ページ(感謝します)
[python]matplotlibで左右に2つの軸があるグラフを書く方法
ソースコード(Jupyter Notebook)と描画結果
データ件数は7500件で、平均値50、標準偏差10の正規乱数にしました。
まず以下のPythonコードを実行してみます。#%% import numpy as np import matplotlib.pyplot as plt #%% # データ作成 μ = 50 σ = 10 data = [ np.random.normal(μ, σ) for i in range(7500) ] #%% # 階級数 num_bins = 20 # グラフ描画 fig = plt.figure(figsize=(12, 8)) plt.legend() plt.xlabel('x', fontsize=18) plt.title('null', fontsize=18) # (1) 縦軸を度数にしたヒストグラム ax1 = fig.add_subplot(111) ax1.set_ylabel('frequency', fontsize=18) ax1.grid(True, color="dimgray") ax1.set_axisbelow(True) # gridを最背面に移動 ax1.hist(data, bins=num_bins, rwidth=0.5, align="mid") # (2) 縦軸を相対度数にしたヒストグラム ax2 = ax1.twinx() ax2.set_ylabel('relative frequency', fontsize=18) ax2.grid(True, color="lightgrey", linestyle="--") ax2.set_axisbelow(True) # gridを最背面に移動 weights = np.ones_like(data) / len(data) ax2.hist(data, bins=num_bins, weights=weights, rwidth=0.5, align="right", color="red")縦軸=度数の棒をデフォルトの色で、縦軸=相対度数の棒を赤で、左右に並べて描画しました。
この両者の高さが同じに見えることを人が確認します(邪道たる所以..)度数と相対度数の棒の高さが同じに見えたら、棒の色を一致させます。
「color="red"」を指定せずに、ax2.hist()を呼び出します。ax2のGrid線が、ax1の棒より手前に表示されてしまいました。
この横線を見えなくするために、以下のコードを追加してax1と同じグラフを上書き描画することにしました。# (3) (1)の見栄えを調整 ax3 = ax1.twinx() ax3.set_yticklabels([]) ax3.hist(data, bins=num_bins, rwidth=0.5, align="mid")完成版のコード全体は以下の通りです。
#%% import numpy as np import matplotlib.pyplot as plt #%% # データ作成 μ = 50 σ = 10 data = [ np.random.normal(μ, σ) for i in range(7500) ] #%% # 階級数 num_bins = 20 # グラフ描画 fig = plt.figure(figsize=(12, 8)) plt.legend() plt.xlabel('x', fontsize=18) plt.title('null', fontsize=18) # (1) 縦軸を度数にしたヒストグラム ax1 = fig.add_subplot(111) ax1.set_ylabel('frequency', fontsize=18) ax1.grid(True, color="dimgray") ax1.set_axisbelow(True) # gridを最背面に移動 ax1.hist(data, bins=num_bins, rwidth=0.5, align="mid") # (2) 縦軸を相対度数にしたヒストグラム ax2 = ax1.twinx() ax2.set_ylabel('relative frequency', fontsize=18) ax2.grid(True, color="lightgrey", linestyle="--") ax2.set_axisbelow(True) # gridを最背面に移動 weights = np.ones_like(data) / len(data) ax2.hist(data, bins=num_bins, weights=weights, rwidth=0.5, align="right") # (3) (1)の見栄えを調整 ax3 = ax1.twinx() ax3.set_yticklabels([]) ax3.hist(data, bins=num_bins, rwidth=0.5, align="mid")邪道な感じなので、正攻法があれば教えてほしいです。
- 投稿日:2019-11-15T13:44:54+09:00
PythonでX線回折シミュレーション
It’s !
どうもこんにちは。二回目の投稿です。今回はPythonでX線回折のシミュレーションをしてみました。コード全文(Jupyter Notebookを使っております)はGitHub1
に載せています。間違っている点などがあれば、ご指摘いただけると幸いです。X線回折(X-Ray Diffraction, XRD)
X線回折とは、X線が結晶中で回折する現象のことです。X線とは、波長が一定範囲内(1 nm ~ 1 pm程度)の電磁波のことで、回折とは、波の性質を持つものが、障害物を廻り込んで伝播することです。波は回折すると、互いに干渉することで強め合うところと相殺するところができ、縞状に分布するようになります。X線回折による分析では、回折によって生じた模様を解析することで対象の結晶構造を特定します。
ちなみに、回折現象はX線だけでなく、電子線や中性子線でも起き、それらを用いた結晶構造解析法も広く使われています。X線回折による結晶構造解析の原理
X線回折によってできた模様では、回折による干渉によって強めあったところ(回折条件を満たしたところ)がスポットとして得られます。回折条件と結晶構造の関係をブラッグ条件といい、
$$2dsin{\theta} = n\lambda$$
で表されます。dは結晶中の原子がつくる面(結晶面)同士の間隔、$\theta$は結晶面と入射X線のなす角度、$\lambda$はX線の波長です。原子散乱因子と結晶構造因子
先に説明したブラッグ条件では、X線を散乱する原子を点としていますが、実際にX線を散乱するのは、原子のまわりに分布している電子雲であり、散乱したX線の振幅は、(弾性散乱であるとすれば)散乱された位置での電子密度に比例します。そのため、原子によって散乱したX線の振幅fは、
$$f = \int{\rho(\vec{r})e^{2π\vec{k}\vec{r}}} dV$$
となります。この式は、fは電子密度$\rho(\vec{r})$を散乱ベクトル$\vec{k}$でフーリエ変換することに相当します。散乱ベクトルとは、逆空間中に成分(h, k, l)で定義されるベクトルのことです。このfを原子散乱因子と言います。原子散乱因子を求めるには、電子密度が必要ですが、原子のまわりの電子密度は単純な場合を除いて解析的に求めることができないため、ハートリー-フォック法などで近似計算されます。各原子の原子散乱因子はすでに求められ、データベース化されているため、今回の計算ではそれらを用います。さらに、結晶全体においても、同様の考え方を使うことができます。結晶中の電子密度をフーリエ変換することで結晶構造因子Fが得られます。
$$F(\vec{k}) = \int{\rho(\vec{r})e^{2π\vec{k}\vec{r}}} dV$$
式が原子散乱因子と一緒ですね。しかし、結晶中においては、原子位置の周辺にしか電子は分布していないので、これを原子の座標(x, y, z)と原子散乱因子fで書き換えることができ、
$$F(hkl) = \sum_{j}{f_jT_je^{2πi(hx_j + ky_j + lz_j)}}$$
となります。h, k, lは散乱ベクトルkの成分で、逆空間での格子点(逆格子点)の座標でもあります。
$T_j$は後ほど説明しますが、デバイ-ワラー因子というものです。プログラム
ここからが実際の実装方法になります。
まず、逆格子点hklを列挙します。本来であれば、エワルト球上の点のみを挙げればいいのですが、X線の波長ではかなり幅広い範囲がエワルト球に載ってしまうので、なるだけ多く列挙します。GitHubにあるhkl.csvは列挙されたhklのファイルです。
結晶の単位格子の原子座標も必要になります。こちらは、単位格子内の原子だけで充分です。今回は、例として面心立方格子(fcc)の座標を用いています。GitHubではpos.csvという名前のファイルになっています。次に、格子定数a, b, c, $\alpha$, $\beta$, $\gamma$から(これらはパラメータとしてあらかじめ持っておく)、実空間での格子テンソル$G$を組み立てます。
$$
G = \left(
\begin{matrix}
a^{2} & ab\cos\gamma & ac\cos\beta\\
ba\cos\gamma & b^{2} & ba\cos\alpha\\
ca\cos\beta & cb\cos\alpha & c^{2}
\end{matrix}
\right)
$$
次に、
$$G^{\ast} = G^{-1}$$
から、この格子テンソルの逆行列をとれば、逆空間での格子テンソル$G^{\ast}$が求まります。G = [[a**2, a*b*np.cos(gamma), a*c*np.cos(beta)], [b*a*np.cos(gamma), b**2, b*a*np.cos(alpha)], [c*a*np.cos(beta), c*b*np.cos(alpha), c**2]] invG = np.linalg.inv(G)この逆格子テンソル$G^{\ast}$を使って、逆格子点hklでの反射Kに対する逆格子ベクトルの長さ
$$|\vec{r}| = |ha^{\ast} + kb^{\ast} + lc^{\ast}|$$
を求めます。
$$
|\vec{r}| = |ha^{\ast} + kb^{\ast} + lc^{\ast}| = h^{\mathrm{T}}G^{\ast}h$$hkl = [h[i], k[i], l[i]] thkl = np.transpose(hkl) dk = 1/((np.matmul(np.matmul(invG, thkl), hkl))**(1/2))|r|とブラッグ条件から、反射Kでの面間隔dkとブラッグ角θkが求まります。
$$d_k = \frac{1}{|\vec{r}|^2}$$
$$\theta_k = \arcsin(\frac{λ}{2d_k})$$sinthetak = lamb/(2*dk) thetak = np.rad2deg(np.arcsin(sinthetak))原子散乱因子にはデータベースの値を使いますが、原子散乱因子はsinθ/λに依存する関数なので、データベースに載っているのはその係数だけです。係数から組み立てるには、
$$f(\frac{\sin\theta}{\lambda}) = \sum_{j=1}^{4}{a_j e^{-b_j(\frac{\sin\theta}{λ})^2}} + c$$
とします。$a_j$, $b_j$, cが係数です。プログラムでは、Na原子を想定してデータを用いました。ここで、デバイ-ワラー因子について説明しなければなりません。
デバイ-ワラー因子とは、熱振動の影響を補正する因子です。等方的な熱振動のデバイ-ワラー因子は
$$T = e^{-B(\frac{\sin\theta}{\lambda})^2}$$
で表されます。Bは等方性原子変位パラメータというものです。
熱振動が等方的でない場合(異方性と言いますが)、より複雑で、$3\times3$対称行列$\beta$を用いて
$$T = e^{-h^{\mathrm{T}} β h}$$
となります。
今回は等方的な熱振動を考え、B = 2.0にしています。原子変位パラメータの値を探したのですが、見つからず、適当な値です。すいません。原子散乱因子と結晶の単位格子の原子座標をもとに、結晶構造因子を計算します。
$$F_i(x, y, z, h_i, k_i, l_i, f_i) = f_i\sum_{j}{e^{2πi(hx_j + ky_j + lz_j)}}$$
見ての通り、結晶構造因子は複素数になります。求めた結晶構造因子の絶対値の二乗(散乱振幅の絶対値の二乗なので、散乱強度になる)を縦軸、$2\theta$を横軸としてプロットすれば、X線回折で得られるようなプロットが得られます。X線回折を測定する機械では、試料と測定部とが互いに逆回りに$\theta$づつ回転し測定するため、実際の移動角度は$2\theta$となり、プロットでも横軸を$2\theta$で取ることが習慣となっています。
結果
ブラッグ角は小数点2桁までで丸めています。
このプロットでは、ブラッグ条件を満たす反射の角度でのみデルタ関数的に散乱強度が出ていますが、実際のX線回折では、散乱強度のピークは幅を持っています。そのピークの広がりを再現してみましょう。デルタ関数に広がりを持たせたいときに、まず思いつくのは、ガウス関数(ガウシアン)による畳み込みでしょう。いわゆる、ガウシアンコンボリューションというやつです。
さっきのプロットに、ガウス関数を畳み込んだものが以下になります。分散は適当にそれっぽく見える値を入れています。
裾野に少し幅ができたのがわかると思います。X線回折の計測データを見たことがある人ならわかると思いますが、実際の物に比べて、このプロットは少し裾野が狭いように見えます。実はガウス関数は、粒子の熱振動などの挙動を表現するには適していますが、このようなスペクトルのピークの表現には適していません。
そこで、スペクトルのピークの表現に使われるローレンツ関数で畳み込みをしてみます。ローレンツ関数は以下のような関数です。
$$L = \frac{1}{1 + (\frac{x}{γ})^2}$$
$\gamma$は半値幅といい、ピーク高さの1/2でのピーク幅です。このパラメータで関数の広がり方が変わります。def lorentzian(theta, gamma): lorentz = 1/(1 + (theta/gamma)**2) return lorentz実際に畳み込んだものが以下です。またも半値幅の値はそれっぽく適当な値です。
先ほどのガウス関数よりも裾野が広くなりました。X線回折のピークっぽくなりましたね。
と言っても、ローレンツ関数だけでは正確ではありません。結晶内の原子が温度によって振動するために(たとえ絶対零度であっても零点振動があります)、ガウス関数的な挙動の熱振動もピークの広がりに影響を与えます。よってローレンツ関数とガウス関数を任意の重さで畳み込んだもので、より正確にピークを表現できます。ローレンツ関数とガウス関数を畳み込んだものをフォークト関数と言います。フォークト関数は愚直にローレンツ関数とガウス関数を畳み込んで作るよりも、複素誤差関数を用いて作る方が早いです。筆者は勉強不足でよくわかっていませんが、なんか複素誤差関数の実部がフォークト関数っぽくなっているみたいです。2
ちょうどscipyに複素誤差関数を生成してくれる関数があるらしいので、今回はそれを使いました。def voigt(theta, Hg, Hl): z = (theta + 1j*Hl)/(Hg * np.sqrt(2.0)) w = scipy.special.wofz(z) v = (w.real)/(Hg * np.sqrt(2.0*np.pi)) return vフォークト関数でピークの広がりを表現したものが以下です。
やってみたはいいものの、広がりをローレンツ関数のみで表現したものの方がそれっぽいですね。フォークト関数はパラメータとしてガウス関数部、ローレンツ関数部それぞれの半値幅が必要ですが、今回は適当に設定しています。半値幅を理論的に近づけることで、実際のピークの広がりに近づくかもしれません。回折像
X線回折においては、上記のようなプロットの他に、回折像と言われる、X線の回折をそのまま写しとった像が得られます。回折像では逆格子が見て取れるので、今回はおまけとして作ってみようと思います。
実装としては、任意の大きさでnumpy.zeros()の配列を生成しておいて、反射の条件を満たすところのみ|F|^2の値を入れ、スポットっぽく見えるようにガウス関数を畳み込みます。
def gaussian(theta, lamb): gauss = (1/(2*np.pi*sigma))*np.exp(-(theta**2 + lamb**2)/(2*sigma)) return gauss回折像は入射X線の方向に対して垂直な逆格子点のみがスポットとして出てきます。よって、今までの条件に加えて、入射X線方向についても考慮しなければなりません。入射X線方向を[001]として、内積をとって0になる反射のみを取り出します。この処理は[001]だと楽ですが、入射方向が[110]や[111]などでは複雑な処理が必要でしょう。
Pythonでは、配列をそのままmatplotlib.pyplot.imshow()で画像にできますので、白黒のコントラストで画像にします。t, l = np.meshgrid(np.arange(-1, 1, 0.1), np.arange(-1, 1, 0.1)) g = gaussian(t, l) xrdimage = scipy.signal.convolve2d(I, g, boundary='wrap', mode='same') plt.imshow(xrdimage, interpolation="nearest", cmap=plt.cm.gray)それっぽいですね。さっきからそれっぽいしか言っていませんね。体心立方格子(bcc)でもやってみました。
fccより楽しい感じになりましたね。まとめ
X線回折のシミュレーションをしてみました。回折理論が複雑ですが、コンピュータでする処理自体は簡単ですので、X線回折を理解するにはちょうどいい教材かもしれません。
実を言うと、精密なシミュレーションをするには、今回実装したものよりも多くの因子を考えなければなりません(ローレンツ・偏光因子や選択配向関数など)。加えて、今回適当に設定したパラメータ(原子変位パラメータ、フォークト関数の半値幅)も本来は正確な値を使うべきです。では、これらのパラメータは理論的に求めることができるのでしょうか。これらのパラメータは様々な要因が複雑に影響し合ってできているため、支配的な要因から類推はできても、解析的に求めるのは難しいでしょう。
上記のようなパラメータの正確な値を得るためには、実験値とシミュレーションをすり合わせ、誤差を減らしていく、という手法を用います。そこで、前回の記事3
で紹介した、非線形最小二乗法が活躍するわけです。参考文献
今回の記事は、以下の記事や書籍を元に作成しています。勝手ながら紹介させていただきます。
粉末X線解析の実際 リートベルト法入門 (日本分析化学会X線分析研究懇談会 編 中井泉 泉富士夫 編著)
コード
- 投稿日:2019-11-15T13:33:47+09:00
Conda 仮想環境の操作 メモ
Condaを使ったPythonの仮想環境「作成・アクティベート・削除・コピー(複製)」の簡易メモです。
仮想環境の作成
$ conda create -n 環境名
$ conda create -n 環境名 python=3.6
SSLErrorが出た場合、パスがすべて通っているか確かめてみてください。
Windowsでは「Anaconda3\Library\bin」を設定していないとエラーになります。アクティベート
$ activate 環境名
環境から出る
$ deactivate
環境の削除
$conda env remove -n 環境名
環境のコピー
conda create -n 新規環境 --clone 複製元環境名
- 投稿日:2019-11-15T11:55:23+09:00
配列の要素内で最長の文字長を取得する
これより短く書く方法が思いつかなかったので
あったら教えてください?li = ["あ", "いうえお", "かき", "くけこ"] print(len(max(li, key=len)))
- 投稿日:2019-11-15T11:49:59+09:00
matplotlibで作図入門: 簡単な関数を書く
この記事を読むとできるようになること
matplotlibで超基本的な図が描ける
gnuplot で図が作れるようになってしばらくすると,「もっと簡単に綺麗な図が描きたい」と思うようになると思います(※個人差があります).
研究発表の図を作るのに無料で使えるツールとして有名なものの1つがmatlotlibです.かなり綺麗な図が描けます(※個人の意見).
この記事では,すぐに使えるmatplotlibでの図の描き方の基礎中の基礎だけをまとめました.より詳細な使い方については,
pythonのmatplotlibの使い方をまとめてみた
が大変わかりやすく,参考になります.
特に,オブジェクト指向インターフェースは便利ですので使えるようになると良いです.
- 環境
- macOS mojave 10.14.6
- Python 3.7.5
ここではmatplotlibを用いて簡単な関数を描いてみましょう
$y = f(x)$ を描く時にコンピューター上で何が行われているかというと
(わかりやすさのために用語の正確さは無視すると),
$x$の組(配列)の要素$x_i$ のそれぞれに対し,
$y$の組(配列)の要素$y_i$ が計算されて,その組がプロットされています.
gnuplot でも同じです.
(なので,特に対数プロットにおいて,変化が急な部分ではプロット点を細かくとってあげないと正しい図にならないことがあります)Python では次のようにして組$x$を作ることができます.
これは等差数列の配列を作っていると思ってください.
x = numpy.arange(-10, 10, 0.01)
引数は,
x = numpy.arange(xの最小値,xの最大値,公差)
です.
この等差数列(みたいなもの)を使って$y = f(x)$ を描画することができます.
では,試しに放物線を描いてみましょう.sample.py#!/usr/bin/env python # -*- coding: utf-8 -*- # これはコード中に全角文字(日本語)を書く時に必要 #以下はおまじないみたいなもの #numpy に np という名前をつける import numpy as np #同様に,matplotlib.pyplot に plt という名前をつける import matplotlib.pyplot as plt #x = np.arange(xの最小値,xの最大値,刻み) x = np.arange(-10, 10, 0.1) #描画する関数 y = x*x #横軸にx,縦軸にyをとって描く plt.plot(x, y) #plot表示 plt.show()では,次によく使うオプションをつけていろいろ描いてみましょう.
sample2.py#!/usr/bin/env python # -*- coding: utf-8 -*- import numpy as np import matplotlib.pyplot as plt x = np.arange(-10, 10, 0.1) y = x*x #描画範囲を指定する場合(x軸でも同様) plt.ylim([0, 50]) #タイトルと軸ラベル plt.title("TITLE") plt.xlabel("Xlabel") plt.ylabel("Ylabel") #grid表示のon/off (デフォルトはFalse) plt.grid(True) #ラベルや線色,太さなどのオプション plt.plot(x,y, label="legend", color="red", lw=3, ls="--") #凡例を表示 plt.legend() #plot表示 plt.show()図を保存するには,最後に
plt.savefig("sample_figure.eps")
などと書けばOKです.ここで紹介したものは一例で,他のオプション(線色とか線種とか凡例の位置とかその他いろいろ)はググって必要なもの/お気に入りものを見つけてみてください.