JSON文字列をオブジェクトに変換する

昨日の記事の逆です。(まとめて書けばよかった)

ドキュメントも同じ場所。
json — JSON エンコーダおよびデコーダ

JSON型の文字列でデータが渡されたとき、それをオブジェクトに変換するには、
json.loads という関数を使います。

早速やってみましょう。
printするだけだと型が変わっていることがわかりにくいので、
typeの結果も出しました。


import json
json_data = '{"key1": "value1", "key2": "value2", "ary1": ["element1", "element2"]}'
data = json.loads(json_data)

print(data)
print(type(data))

# 出力
# {'key1': 'value1', 'key2': 'value2', 'ary1': ['element1', 'element2']}
# <class 'dict'>

辞書型のオブジェクトをJSON文字列に変換する

仕事で必要になったのでメモです。

pythonには jsonという標準ライブラリがあり、
それを使うことで、配列や辞書型のオブジェクトをJSON文字列に簡単に変換することができます。

ドキュメントはこちら。
json — JSON エンコーダおよびデコーダ

インポートして dumps関数を使うだけなので早速やってみましょう。


import json
data = {
        "key1": "value1",
        "key2": "value2",
        "ary1": ["element1", "element2"],
    }
json_data = json.dumps(data)
print(json_data)

# 出力
# {"key1": "value1", "key2": "value2", "ary1": ["element1", "element2"]}

ちなみに、json.dumpsを使わず、str(data)で文字列に変換すると、結果は
"{'key1': 'value1', 'key2': 'value2', 'ary1': ['element1', 'element2']}"
になります。
JSONのルールでは文字列はダブルクオーテーションで囲まないといけないので、
これはJSONではありません。

厳密にJSON型を要求する関数やAPIに渡すときはこれだと受け付けられないので、
json.dumpsを使いましょう。

numpyの乱数生成関数の設計について

このブログに登場するコードでも頻繁にnumpyで乱数を生成していますが、
そのドキュメントは一回読んでおいたほうがいいよという話です。

Random sampling (numpy.random)

pythonの学習を始めた頃は、本に載っているサンプルコードや検索したらでてくる各サイトを参考に、
個々の関数の使い方を覚えて使ってました。

例えばrandであれば次のような感じ。


import numpy as np
# スカラーで一つ値が欲しい場合
np.random.rand()
# 配列で5個値が欲しい場合
np.random.rand(5)
# 引数を複数指定すると多次元配列で乱数が生成される
np.random.rand(2, 2, 2)

標準正規分布に従う乱数が欲しい時はrandnがあり、randと同じように使えます。

その一方で、normalという関数も準備されていて、
これは使い方が違います。

引数が
normal([loc, scale, size])となっていて、
最初に平均と標準偏差を与える必要があり、
欲しい乱数の個数は3個目の引数に与えます。

一方、randやrandnは複数個の乱数を得るには便利ですが、パラメータを渡すことができません。
(なので、得た乱数に対して、定数を足したり掛けたりして調整する)

特に難しくも複雑でもないので、本に出てきた通りに暗記して使っていましたが、
関数の設計が統一されてないので不便だとずっと思ってました。

それでこの度ドキュメントをみたのですが、各関数が、
Simple random data と、Distributionsというカテゴリに分けて定義されていることを知りました。
(あと二つ、PermutationsとRandom generatorがありますが割愛)
そして、(完全に揃ってる訳ではないのですが、)それぞれのカテゴリ内である程度使い方を揃えて作られていることがわかりました。

要は、Simple random dataのほうは欲しいデータの数だけ渡せばよく、
Distributionsの方は最初に分布のパラメーターを指定して、データの個数はsize引数で渡す。

今更なんですが、最初にpython勉強し始めた頃に、
公式ドキュメントもきちんと読んでおけば、もう少し楽に覚えられたかなと思いますね。

pythonでARモデルの推定

時系列解析で理論の話題が続いていましたが、用語の定義がだいぶ済んだので、
そろそろ実際にコードを書いてモデルの推定等をやってみます。
(とはいえAIC,BICなどのかなり重要なキーワードや、推定の理論面の話をまだ紹介してないのですが。)

今回はAR(2)過程のデータを生成し、statusmodelsを使って、そのパラメーターを推定します。
真のモデルが不明なサンプルデータではなくてもともと正解がわかってるデータで雰囲気をつかもうというのが主目的です。

今回使うのは、次の定常AR(2)過程です。
$$
y_t = 5 + 1.4y_{t-1} – 0.48y_{t-2} + \varepsilon_{t}, \ \ \varepsilon_{t} \sim W.N.(0.5^2)
$$

早速データを生成して可視化しておきましょう。(過去の記事の例と大して変わらないので、可視化の結果は略します。)


import statsmodels.api as sm
import matplotlib.pyplot as plt
import numpy as np
phi_1 = 1.4
phi_2 = -0.48
c = 5
sigma = 0.5
T = 500
# 過程の期待値
mu = c/(1-phi_1-phi_2)


# データの生成
ar_data = np.zeros(T)
ar_data[0] = mu + np.random.normal(0, sigma)
ar_data[1] = mu + np.random.normal(0, sigma)
for t in range(2, T):
    ar_data[t] = c + phi_1*ar_data[t-1] + phi_2*ar_data[t-2] \
                                + np.random.normal(0, sigma)
# データの可視化 (記事中では出力は略します)
fig = plt.figure(figsize=(12, 6))
ax = fig.add_subplot(1, 1, 1)
ax.plot(ar_data)
plt.show()

あとはこのデータから、元のパラメータである、定数項の5や、自己回帰係数の1.4と-0.48、撹乱項の分散0.25(=0.5^2)などを
推定できれば成功です。

使うのはこれ。
statsmodels.tsa.ar_model.AR
fitの戻り値であるARResultsのドキュメントも読んでおきましょう。
statsmodels.tsa.ar_model.ARResults

早速やってみます。
なお、手順は以下の通りです。

  1. ARモデルの生成
  2. 次数の決定(select_order, 今回はAICを使用)
  3. 決定した次数で推定
  4. 推定結果の確認

# モデルの生成
model = sm.tsa.AR(ar_data)
# AICでモデルの次数を選択
print(model.select_order(maxlag=6, ic='aic'))  # 出力:2

# 推定
result = model.fit(maxlag=2)

# モデルが推定したパラメーター
print(result.params)
# 出力
# [ 5.68403723  1.38825575 -0.47929503]
print(result.sigma2)
# 出力
# 0.23797695866882768

今回は正解にそこそこ近い結果を得ることができました。
乱数を使うので当然ですが実行するたびに結果は変わります。
また、T=500くらいのデータ量だと、モデルの次数が異なる値になることも多く、
結構上手くいかないことがあります。

実行するたびに全然結果が変わるのと、
実際の運用では同一条件のデータを500件も集められることは滅多にないので、
正直、ARモデルでの推定結果をあまり過信しすぎないように気をつけようと思いました。

LightsailのMySQLに接続する

このブログはAWSのLightsailを使って構築しています。
ちょっと訳あって、そのサーバーのDB(MySQL)に接続したくなったのですが、
少しつまずいたのでメモです。

mysqlは勝手に構築してくれているので初期パスワードに何が設定されているのか、わかりませんでした。

結論から言うと
user : root
pass : bitnami_application_password ファイルの中身
で接続できます。
このwordpressの管理画面と同じ初期パスワードだったんですね。

わかるまで、サーバーにログインし、

\$ mysql
\$ mysql -u user
\$ mysql -u root
など試しましたが、ログインできず。

パスワードとして心当たりがあるのが管理画面のパスワードだけだったので、

\$ mysql -u root -p
とコマンドを打った後、bitnami_application_passwordの中身を入力したら接続できました。

念のため設定変えておこう。

定常AR過程をMA過程で表現する

前回の記事がMA過程の反転可能性について述べたものだったので、今回はAR過程をMA過程で表現できることについてです。
参考:MA過程の反転可能性

AR過程全てではなく、定常AR過程に限った性質ですが、
定常AR過程はMA($\infty$)過程に書き直すことができます。

たとえば、 $|\phi|<1$の時、次のAR(1)過程は定常です。 $$ y_t = \phi y_{t-1} + \varepsilon_t , \varepsilon_t\sim W.N.(\sigma^2). $$ これは、 $$ y_t = \sum_{k=0}^{\infty}\phi^k\varepsilon_{t-k} $$ と書き直すことができます。 また、MA過程は常に定常なので、MA過程に書きなおせるAR過程は定常です。 ということで、AR過程が定常になる条件と、AR過程をMA過程に書きなおせる条件は同一になり、 AR特性方程式の解を調べることで判断ができます。

MA過程の反転可能性

今日もまた沖本本からMA過程の話題です。

本題に入る前にAR過程の復習ですが、このブログでも紹介した通り、
AR過程は定常になるとは限らず、各種の性質については、定常AR過程なら、という前提がついていました。
参考:自己回帰過程の定義と定常になる条件、定常自己回帰過程の性質
その一方で、MA過程については常に定常でなのでとても扱いやすいように見えます。
しかし、MA過程には同一の期待値と、同一の自己相関構造を持つ異なるMA過程が複数存在するという問題があります。

一般に、同一の期待値と自己相関構造を持つMA(q)過程は$2^q$個存在するらしいです。
本に、MA(1)の例が載っているので、このブログではMA(4)あたりに対して、この$2^4=16$個がそうだ!って例を見つけて描きたかったのですが、
挫折したので本に載ってるMA(1)に対する例を紹介します。

それは
$$
\begin{eqnarray}
y_t = \varepsilon_t +\theta\varepsilon_{t-1} , \varepsilon_t \sim W.N.(\sigma^2)
\end{eqnarray}
$$
と、
$$
\begin{eqnarray}
y_t = \tilde{\varepsilon}_t+\frac{1}{\theta}\tilde{\varepsilon}_{t-1}, \tilde{\varepsilon}_t \sim W.N.(\theta^2\sigma^2)
\end{eqnarray}
$$
です。
これの期待値や自己相関を 移動平均過程の定義と性質 で紹介した式に沿って計算すると、一致することを確認できます。

この時、$2^q$個のMA(q)過程の中からどれを採用するかの基準が必要になりますが、
そのために一つの基準になるのがMA過程の反転可能性(invertibility)です。

MA(q)過程が反転可能(invertible)とは、そのMA(q)過程をAR($\infty$)過程に書きなおせることです。

例えば、$|\theta|<1$であれば、 $$ y_t = \varepsilon_t + \theta\varepsilon_{t-1} $$ は $$ y_t = -\sum_{k=1}^{\infty}(-\theta)^ky_{t-k}+\varepsilon_t $$ と書き直せます。 このMA(1)の例も沖本先生の本からです。 (MA(2)の例を紹介しようと計算を頑張っていたのですが思ったより複雑になったので本の例をそのまま。) 一般のMA(q)過程の反転可能性については、AR過程の定常条件とよく似ています。 次のMA特性方程式を調べることで確認できます。 $$ 1+\theta_1z+\theta_2z^2+\cdots+\theta_qz^q=0. $$ このMA特性方程式の全ての解の絶対値が1より大きければMA過程は反転可能になります。 この時、撹乱項$\varepsilon_t$は、$y_t$を過去の値から予測した時の予測誤差と解釈できます。 昔、別の本で移動平均過程を勉強した時、いきなり移動平均もでるは誤差項による回帰だと書かれていて全く理解できなったのですが、 ようやく理解できました。 沖本先生の本だと、反転可能なものの唯一性等の証明が載っていない(そして自分で証明しようともしたが上手くいっていない)ので、 何かの折に他の文献にも当たってみようと思います。

pandasで数値データを区間ごとに区切って数える

今日偶然知って便利だった関数を紹介します。

まずやりたいこと。
配列でもDatafarameの列でも、数値データを区間(bins)ごとに区切って数えたい場面は多々あると思います。
例えば、
[455,133,666,111,645,236]
みたいなデータを、
100以上,200未満が2個、200以上,300未満が1個、、、といった具合です。
ヒストグラム書くためにやる操作ですね。

これまで僕がこれをやる時100単位でやるのであれば、
各データを100で割り算して小数点以下を切り捨てて、再度100倍するといった面倒なことをやってました。

これを pandas.cut という関数を使うと、非常に容易に行えます。
ドキュメントはこちら。
pandas.cut

早速これを使ってみましょう。
次のコードは、乱数で生成した10個の数値を、100ごとに区切って数えるものです。
結果に出てくる “[300, 400)”といった出力は、文字列に見えますが、Intervalというオブジェクトです。
right=False は指定しないと、n以上m未満ではなく、nより大きいm以下、って区切り方になります。
引数のbinsには区切りたい点のリストを渡していますが、arrange関数で生成して渡しています。


import pandas as pd
import numpy as np  # ダミーデータ生成用

# 300〜999 の整数を10個生成
data = np.random.randint(300, 1000, 10)
# 100 ごとに区切る。
category = pd.cut(data, bins=np.arange(300, 1100, 100), right=False)

print("データとそれが所属する区間")
for d, c in zip(data, category):
    print(d, "・・・", c)

print("\n区間ごとのデータ件数")
print(category.value_counts())

# 以下出力
データとそれが所属する区間
309 ・・・ [300, 400)
305 ・・・ [300, 400)
874 ・・・ [800, 900)
953 ・・・ [900, 1000)
727 ・・・ [700, 800)
950 ・・・ [900, 1000)
384 ・・・ [300, 400)
789 ・・・ [700, 800)
486 ・・・ [400, 500)
501 ・・・ [500, 600)

区間ごとのデータ件数
[300, 400)     3
[400, 500)     1
[500, 600)     1
[600, 700)     0
[700, 800)     2
[800, 900)     1
[900, 1000)    2
dtype: int64

ARMA過程

今回も沖本先生の経済・ファイナンスデータの計量時系列分析を元にした記事です。
最近、AR過程やMA過程について色々と紹介していますが、これら両方を含む過程を考えることができます。
それを自己回帰移動平均(ARMA)過程と言います。
(autoregressive moving average process)

(p,q)次ARMA過程(ARMA(p,q)過程)は、次の式で定義されます.

$$
y_t = c + \phi_1y_{t-1}+\cdots+\phi_py_{t-p}+\varepsilon_t+\theta_1\varepsilon_{t-1}+\cdots+\theta_q\varepsilon_{t-q}\\
\varepsilon_t \sim W.N.(\sigma^2)
$$
ARMA過程の性質は、AR過程の性質とMA過程の性質の強い方が残ります。
例えば定常性については、AR過程部分が定常であれば定常になります。
(結果だけ見れば、MA過程が定常過程なので、それに定常過程を足しても定常というだけの話に見えますが、
正確な証明にはもう少し細かな議論を要します)

AR過程部分の定常性については、以前の記事でも紹介したAR特性方程式を使います。

ARMA(p,q)過程が定常の時、過程の期待値は、AR過程部分の期待値と等しくなります。
$$
\mu = E(y_t) = \frac{c}{1-\phi_1-\phi_2-\cdots-\phi_p}
$$

また、$q+1$次以降の自己共分散と自己相関もAR部分とおなじ、次のユール・ウォーカー方程式に従います。
$$
\begin{eqnarray}
\gamma_k & = \phi_1\gamma_{k-1}+\phi_2\gamma_{k-2}+\cdots+\phi_p\gamma_{k-p}, k\geq q+1\\
\rho_k & = \phi_1\rho_{k-1}+\phi_2\rho_{k-2}+\cdots+\phi_p\rho_{k-p}, k\geq q+1
\end{eqnarray}
$$
$q$次までについては、MA項の影響もあり具体的な表記が難しくなります。

また、定常ARMA過程の自己相関は指数的に減衰します。これもAR部分の性質ですね。
(MA過程の部分の自己相関はq+1次以降消えます。)

2019年第1四半期によく読まれた記事

一昨日でこのブログを開設してから3ヶ月が経過しました。
まだ毎日数人ですが、このブログに訪れてくれる方も現れています。

せっかくGoogle アナリティクスも導入していますので、
このあたりで、これまでによく読まれた記事を紹介したいと思います。
他のブログではよくベスト10とか紹介されていますが、そこまで記事数も訪問数もないのでベスト5で。

早速ですが結果はこちらになります。なお、自分のアクセスは除外しています。

  1. Mac(Mojave) に pip で mecab-python3をインストールする時にはまった
  2. macにgraphvizをインストールする
  3. WP Mail SMTPを設定してLightsailのwordpressからメール送信できるようにする
  4. pythonで編集距離(レーベンシュタイン距離)を求める
  5. Prestoで1ヶ月後の時刻を求める時に気をつけること

トップ2が環境構築の話、3位がWordpressの話となり、全然データサイエンティストのブログぽくない結果になりました。
そもそもこのブログ開設当初の記事がブログ構築の話ばかりだったのでしかたがないですね。

最近書いている時系列解析の話などはほぼ読まれていないようです。
ただ、今後も当分は今のペースで記事を増やしていこうと思っています。
もともと過去に検証したこととか、手元にメモしたものを一箇所に集約することも目的だったので、
これまで通り基本的な内容の記事が中心になる予定です。