今回は、Pythonで対数(log, ログ)のグラフを描写していきます。日常生活においては、対数の計算はほとんどする必要はありませんし、意識することもないと思います。
しかし、AIや機械学習、統計学などの分野で、コンピュータ上で膨大な大きさの数を扱う際には、対数変換することで、元の数を小さい数に変換することができ、実用上非常に有用なことから、多くの場面で利用されています。
今回は、PythonのライブラリであるNumpyとmatplotlibを利用して、対数のグラフを描写してみます。
- 対数の定義や性質をおさらい
- Pythonを利用して任意の関数を対数化したグラフを描写する方法
対数の定義と対数の性質
まず最初に対数がどのようなものか簡単に復習しておきましょう。
まず最初に、対数の定義からです。
$a > 0$, $a \neq 1$, $M >0 $のとき、
\begin{equation} a^p \space= \space M \Rightarrow log_a M = p \end{equation}
この時、$log_a M$を、aを底とするM の対数と呼ぶ。
また、$log_a M$に対して、$a$を底、$M$を真数と呼ぶ。
続いて、対数の定理や公式、性質についてまとめていきます。
指数や対数の定義から成り立つ式
指数の定義から、次の定理が数式が成り立ちます。
\begin{equation} log_{a} a = 1 \end{equation}
\begin{equation} log_{a} 1 = 0 \end{equation}
積・商・累乗の対数
\begin{equation} log_{a} MN = log_{a} M + log_a{N} \end{equation}
\begin{equation} log_{a} \frac{M}{N} = log_{a} M - log_a{N} \end{equation}
\begin{equation} log_{a} {M}^r = rlog_{a} M \end{equation}
機械学習分野で対数を利用することのメリット
対数自体は、ありとあらゆる分野で利用されます。
このサイトでは機械学習を主に扱っていますので、まず機械学習の分野でのメリットを説明すると、対数を利用することで、計算は非常にしやすくなるメリットがあります。
特にAIや機械学習分野では、パラメータを最適化するために、尤度関数の計算式などで$\Prod$などの積の演算が多数登場するのですが、この時も対数をとり、対数尤度関数などを考えたりします。
対数尤度関数を用いることで、積の演算が和の演算に変換されるため、そのあとの最適化計算が非常に簡潔になります。
また、対数では正の数を、底と指数部分に分けて扱うことができます。これによって、例えば数百、数千桁の数で合っても対数表示をすることで、非常に小さいbit数で表現することができます。
これは現在のコンピュータの主な構成要素である、CPUやメモリが64bitを基本単位として構成されている都合上、64bit以内で数が表現されていることは非常に都合がよく、プログラムの高速化やバグの削減に繋がります。
この辺りの話は今回の記事のテーマと大きく逸れてしまうので、詳しくはありませんが、今後もし需要があれば追加したいと思います。
Pythonを用いて対数の数式をグラフに描写する
それでは、ようやく本題に入っていきましょう。今回は、可視化のためにmatplotlibと数値計算のnumpyのライブラリを利用します。
まず、ライブラリをインポートします。
import numpy as np # logの数値計算用
import matplotlib.pyplot as plt # グラフに描写用
続いて、対数のグラフを描写していきましょう。
対数は任意の底を指定可能ですが、機械学習分野では底をネイピア数である$e$を利用することが非常に多いので、今回も$e$を底とした対数のことを、自然対数と呼びます。
今回は、$y=2x$のグラフを、対数化してみましょう。
plt.figure(figsize=(10, 10), dpi=50)
plt.xlim([0, 5])
plt.ylim([-1, 5])
x = np.linspace(0.1, 10., 100)
y = 2 * x
log_y = np.log(y)
plt.plot(x, y, label="y = 2x", color="red", linestyle="-.")
plt.plot(x, log_y, label="y = log(2x)", color="blue", linestyle="-.")
plt.legend()
plt.show()
赤色のグラフが、$y=2x$で、青色のグラフが$y = log_e (2x)$のグラフです。
一次関数なので、赤いグラフは線形の増加していますが、青いグラフでもこの特徴は一緒のようです。
もっと複雑な関数を描写してみましょう。
続いて、こんな多項式関数$f(x)$に、自然対数をとるとどのようになるでしょうか。
f(x) = 1.2x^5+x^4-9x^3+2x + 117
関数系はこのようになっています。これに、自然対数をとった結果、この方になります。
plt.figure(figsize=(20, 5), dpi=50)
plt.xlim([-4, 4])
plt.ylim([-20, 220])
x = np.linspace(-10, 10., 100)
y = 1.2 * x**5+x**4-9*x**3+2*x + 117
log_y = np.log(y)
plt.plot(x, y, label="$y = 1.2x^5+x^4-9x^3+2x+117$", color="red", linestyle="-.")
plt.plot(x, log_y, label="y = log(2x)", color="blue", linestyle="-.")
plt.legend()
plt.show()
ずいぶんのっぺりしていますね。青い線だけ切り出してみるとこのようになっています。
実元の関数である赤いグラフと、自然対数logをとったが青いグラフを見比べてみるとわかるのですが、対数を撮っても元の関数の大小関係が変わらないという性質があります。
そのため、元の関数の最大値や最小値を求めたい場合には、そのログをとった関数系の最大最小を調べても大丈夫という性質があります。