nanoseeingの技術系ブログ

機械学習・競プロなど。アウトプットが目的。

はてなブログで数式を書くときのメモ

よく使う記法のメモ

参考サイト:

基本形

はてなで数式を埋め込む際には、エスケープを気にする場面が多く、めんどくさい。 基本はdivタグ(またはpreタグ)で囲めばエスケープ問題は解決する。

数式、 hogehogeです。
<div>
数式、[tex: hogehoge]です。
</div>

上付き文字

{x}^{a}

[tex:{x}^{a}]

下付き文字

{x}_{a}

[tex:{x}_{a}]

総和

\sum_{i=0}^{n} {x}_{i}
[tex:\sum_{i=0}^{n} {x}_{i}]

累乗根

\sqrt[n]{x}
[tex:\sqrt\[n\]{x}]

ベクトル・行列を太字に

\boldsymbol{x}

\boldsymbol{x} 

数式を中央寄せ

y=ax
<div style="text-align: center;">
[tex:y=ax]
</div>

行列を書く

 \boldsymbol{A} =
\begin{pmatrix}
a&b\\
c&d
\end{pmatrix}


<div>
[tex: \boldsymbol{A} =
\begin{pmatrix}
a&b\\
c&d
\end{pmatrix}
]
</div>

小ネタ

ベクトルのノルムを書くときの縦二重線。

‖v‖


合成関数を書くときの丸。

f∘g

回帰分析を実装する【機械学習アウトプット第1回】

初心に帰って、機械学習の全体像を勉強していきます。
1日目は回帰分析から。

今回は、2次関数 y=w_{0}x^{2}-w_{1}x+w_{2}
のパラメーター、\boldsymbol{w} =[w_{0},w_{1},w_{2}]を予測してみます。

まずは、データを用意してプロットしてみます。

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

x = np.arange(-10, 10, 0.1)
y = 3 * (x ** 2) - 5 * x + 4
y += np.random.rand(200) * 10 - 5 

fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1, 1, 1)
ax.set_ylabel('y')
ax.set_xlabel('x')
ax.scatter(x, y)
plt.show()

f:id:nanoseeing:20210201212411p:plain

y=3{x}^{2}-5x+4\boldsymbol{w} =[4,-5,3])とし、\pm5の誤差を加えました。

\boldsymbol{w}を求める実装方法は何通りかありますが、それぞれ試してみます。

1. 数式から愚直に実装

訓練データN組が以下の形式で与えられたとします。

\boldsymbol{x}=[x_{0},x_{1},x_{2},...,x_{N}]^{T}
\boldsymbol{y}=[y_{0},y_{1},y_{2},...,y_{N}]^{T}


この訓練データをM多項式で近似することを考えます。
つまり、パラメータ\boldsymbol{w} =[w_{0},w_{1},w_{2},...,w_{M}]を求めることを考えます。

\boldsymbol{x}の各要素をそれぞれp乗したベクトルを、

\boldsymbol{x_{p}}=[{x_{0}}^{p},{x_{1}}^{p},{x_{2}}^{p},...,{x_{N}}^{p}]^{T}

とし、

\boldsymbol{X}=[\boldsymbol{x_{0}},\boldsymbol{x_{1}},\boldsymbol{x_{2}},...,\boldsymbol{x_{M}}]

とおきます。

このとき、損失関数である二乗和誤差E(\boldsymbol{w})は、

E(\boldsymbol{w})=\dfrac{1}{2}||\boldsymbol{X}\boldsymbol{w}-\boldsymbol{y}||

と表せます。

二乗和誤差を偏微分してイコール0となる方程式を解くと、下記が導けます。

\boldsymbol{w}=(\boldsymbol{X^{T}}\boldsymbol{X})^{-1}\boldsymbol{X^{T}}\boldsymbol{y}


これで\boldsymbol{w}が求まります。
numpyでごり押し実装するとこんな感じです。

x = x.reshape(200,1)
y = y.reshape(200,1)
X = np.concatenate([x**0, x**1, x**2], 1)
W = np.dot(np.dot(np.linalg.inv(np.dot(X.transpose(), X)), X.transpose()), y)
print(W)
>>
[[ 4.37261064]
 [-4.98425549]
 [ 2.99470365]]

正解のパラメータ\boldsymbol{w} =[4,-5,3]に近い値が出力されました。

2. numpy.polyfit()を使用

回帰分析はnumpyに元から入っています。

W = np.polyfit(x, y, 2)
print(W)
>>
[[ 4.37261064]
 [-4.98425549]
 [ 2.99470365]]

手計算と全く変わりません(笑)。

【AtCoder】メモリ領域の話(C++)

メモリ領域に関する知識が怪しかったので調べてみた。

スタック領域に気をつける

以下のようなコードは危険

int main() {
    int dp[10000000]; //ローカル変数に巨大サイズの配列を宣言
}

ローカル変数を宣言すると、メモリ内の「スタック領域」と呼ばれる領域に変数が保管される。スタック領域は一般に数MB程度しかないので、巨大な配列などを宣言するとスタックオーバーフローを起こす危険がある。

解決策1(staticで静的領域に変数を保管)

int main() {
    static int dp[10000000];
}

解決策2(グローバル変数にして静的領域に変数を保管)

int dp[10000000];

int main() {
    // 処理
}

解決策3(newで動的に領域を確保)

int main() {
    int *dp = new int[10000000];
}

解決策4(vectorなら動的に領域が確保される)

int main() {
    vector<int> dp(10000000);
}

メモリ制限について

AtCoderのメモリ制限はたいてい1024MB。

下記ならギリギリACになることを確認した。

vector<long long> test(100 * 1024 * 1024); // 800MB

下記はMLE(メモリ制限超過)

vector<long long> test(128 * 1024 * 1024); //1024MB

MLEになるような問題はめったにないと思うが、過去問にはメモリ制限が小さいものもあるので、頭の片隅に入れておくとよいかも。