はじめに
機械学習でも登場する情報理論におけるエントロピーを1つずつ確認していくシリーズです。
この記事では、対数関数を扱います。
【今回の内容】
対数の定義
対数(logarithm)の定義を数式とグラフで確認します。
対数の性質については「
対数の性質の導出 - からっぽのしょこ
」を参照してください。
定義
まずは、対数の定義を数式で確認します。
対数は、次の式で定義されます。
を底、
を真数、
を指数と呼びます。底は0より大きい1ではない値
、真数は0より大きい値
である必要があります。
底が のとき二進対数、
のとき常用対数、ネイピア数
のとき自然対数と呼びます。
底が の対数関数
は、底が
の指数関数
の逆関数です。
可視化
次は、対数関数をグラフで確認します。
利用するパッケージを読み込みます。
# 利用パッケージ library(tidyverse)
この記事では、基本的にパッケージ名::関数名()
の記法を使うので、パッケージを読み込む必要はありません。ただし、作図コードがごちゃごちゃしないようにパッケージ名を省略しているため、ggplot2
を読み込む必要があります。
また、ネイティブパイプ演算子|>
を使っています。magrittr
パッケージのパイプ演算子%>%
に置き換えても処理できますが、その場合はmagrittr
も読み込む必要があります。
対数関数の作図
対数の底を指定して、対数関数を計算します。
# 底を指定 a <- 2 #a <- 10 #a <- exp(1) # 対数関数を計算 log_df <- tibble::tibble( x = seq(from = -1, to = 10, by = 0.001), # 真数(変数) log_a_x = logb(x, base = a) # 底がaの対数 ) log_df
## # A tibble: 11,001 × 2 ## x log_a_x ## <dbl> <dbl> ## 1 -1 NaN ## 2 -0.999 NaN ## 3 -0.998 NaN ## 4 -0.997 NaN ## 5 -0.996 NaN ## 6 -0.995 NaN ## 7 -0.994 NaN ## 8 -0.993 NaN ## 9 -0.992 NaN ## 10 -0.991 NaN ## # … with 10,991 more rows
任意の底の対数 は
logb()
で計算できます。base
引数に底を指定します。
のとき非数
NaN
、 のとき負の無限大
-Inf
になります。
対数関数のグラフを作成します。
# 対数関数を作図 ggplot() + geom_line(data = log_df, mapping = aes(x = x, y = log_a_x), na.rm = TRUE) + labs(title = "logarithmic function", subtitle = parse(text = paste("a==", a)), x = expression(x), y = expression(log[a]*x))
対数関数は の範囲で単調増加します。
3つの対数関数を計算します。
# 対数を計算 log_df <- tibble::tibble( x = seq(from = 0, to = 5, by = 0.001), # 真数(変数) log_2 = log2(x), # 二進対数 log_10 = log10(x), # 常用対数 log_e = log(x) # 自然対数 ) |> tidyr::pivot_longer( cols = !x, # 新列に格納する(しない)現列 names_to = "a", # 現列名を格納する新列名 names_prefix = "log_", # 現列名の頭から取り除く文字列 #names_transform = list(a = factor), # 現列名の格納後の型 values_to = "log_x" # 現値を格納する新列名 ) |> dplyr::mutate( a = factor(a, levels = c("2", "e", "10")) # 因子レベルを設定 ) log_df
## # A tibble: 15,003 × 3 ## x a log_x ## <dbl> <fct> <dbl> ## 1 0 2 -Inf ## 2 0 10 -Inf ## 3 0 e -Inf ## 4 0.001 2 -9.97 ## 5 0.001 10 -3 ## 6 0.001 e -6.91 ## 7 0.002 2 -8.97 ## 8 0.002 10 -2.70 ## 9 0.002 e -6.21 ## 10 0.003 2 -8.38 ## # … with 14,993 more rows
二進対数 は
log2()
、常用対数 は
log10()
、自然対数 は
log()
で計算できます。
それぞれ別の列として計算して、pivot_longer()
で1つの列にまとめます。
凡例の並び順(色付け順)を指定する場合は因子レベルを設定します。
3つの対数関数のグラフを作成します。
# 対数関数を作図 ggplot() + geom_line(data = log_df, mapping = aes(x = x, y = log_x, color = a)) + geom_hline(yintercept = 0, linetype = "dotted") + # 水平線 geom_vline(xintercept = 1, linetype = "dotted") + # 垂直線 labs(title = "logarithmic functions", x = expression(x), y = expression(log[a]*x))
底に関わらず、 の範囲は定義されず、0のとき負の無限大、0から1のとき負の実数、1のとき0 、1より大きいとき正の実数になります。
(数式(LaTeXコマンド)では定義されないことをどう表記するのでしょうか?)
指数関数との関係
続いて、対数関数と指数関数をグラフで比較します。
3つの指数関数を計算します。
# 対数を計算 exp_df <- tibble::tibble( x = seq(from = -5, to = 5, by = 0.001), # 真数(変数) exp_2 = 2^x, # 二進対数の逆関数 exp_10 = 10^x, # 常用対数の逆関数 exp_e = exp(x) # 自然対数の逆関数 ) |> tidyr::pivot_longer( cols = !x, # 新列に格納する(しない)現列 names_to = "a", # 現列名を格納する新列名 names_prefix = "exp_", # 現列名の頭から取り除く文字列 #names_transform = list(a = factor), # 現列名の格納後の型 values_to = "exp_x" # 現値を格納する新列名 ) |> dplyr::mutate( a = factor(a, levels = c("2", "e", "10")) # 因子レベルを設定 ) exp_df
## # A tibble: 30,003 × 3 ## x a exp_x ## <dbl> <fct> <dbl> ## 1 -5 2 0.0312 ## 2 -5 10 0.00001 ## 3 -5 e 0.00674 ## 4 -5.00 2 0.0313 ## 5 -5.00 10 0.0000100 ## 6 -5.00 e 0.00674 ## 7 -5.00 2 0.0313 ## 8 -5.00 10 0.0000100 ## 9 -5.00 e 0.00675 ## 10 -5.00 2 0.0313 ## # … with 29,993 more rows
二進対数(底が2)、常用対数(底が10)、自然対数(底がネイピア数)に対応した指数関数を計算して、1列にまとめます。
恒等関数を用意します。
# 恒等関数を格納 identity_df <- tibble::tibble( x = seq(from = min(exp_df[["x"]]), to = max(exp_df[["x"]]), length.out = 101), f_x = x ) identity_df
## # A tibble: 101 × 2 ## x f_x ## <dbl> <dbl> ## 1 -5 -5 ## 2 -4.9 -4.9 ## 3 -4.8 -4.8 ## 4 -4.7 -4.7 ## 5 -4.6 -4.6 ## 6 -4.5 -4.5 ## 7 -4.4 -4.4 ## 8 -4.3 -4.3 ## 9 -4.2 -4.2 ## 10 -4.1 -4.1 ## # … with 91 more rows
対数関数と指数関数のグラフは、 の直線で対称になります。
直線を描画するために、恒等関数 の値をデータフレームに格納します。
3つの対数関数と指数関数のグラフを作成します。
# 対数関数と指数関数を作図 ggplot() + geom_line(data = log_df, mapping = aes(x = x, y = log_x, color = a, linetype = "log")) + # 対数関数 geom_line(data = exp_df, mapping = aes(x = x, y = exp_x, color = a, linetype = "exp")) + # 指数関数 geom_line(data = identity_df, mapping = aes(x = x, y = f_x, linetype = "x")) + # 恒等関数 geom_vline(xintercept = 0, linetype = "dotted") + # 対数関数の漸近線 geom_hline(yintercept = 0, linetype = "dotted") + # 指数関数の漸近線 scale_linetype_manual(breaks = c("log", "exp", "x"), values = c("solid", "dotdash", "dashed"), labels = c(expression(log[a]*x), expression(a^x), expression(x)), name = "function") + # 凡例表示用 coord_fixed(ratio = 1, ylim = c(-5, 5)) + # 描画範囲 theme(legend.text.align = 0) + # 図の体裁 labs(title = "Logarithmic functions and Exponential functions", x = expression(x), y = expression(f(x)))
対数関数は に漸近し、指数関数は
に漸近し、対数関数と指数関数が
の直線で対称なのが分かります。
複数の底を指定して、それぞれ対数関数を計算します。
# 底を指定 a_vals <- c(0.2, 0.4, 0.6, 0.8) #a_vals <- c(2, 4, 6, 8) # 対数関数を計算 log_df <- tidyr::expand_grid( a = a_vals, # 底 x = seq(from = 0, to = 10, length.out = 101) # 変数 ) |> # 底の数に応じて変数を複製 dplyr::mutate( log_x = logb(x = x, base = a), # 対数関数 a = factor(a) # 色分け用に因子化 ) log_df
## # A tibble: 404 × 3 ## a x log_x ## <fct> <dbl> <dbl> ## 1 0.2 0 Inf ## 2 0.2 0.1 1.43 ## 3 0.2 0.2 1 ## 4 0.2 0.3 0.748 ## 5 0.2 0.4 0.569 ## 6 0.2 0.5 0.431 ## 7 0.2 0.6 0.317 ## 8 0.2 0.7 0.222 ## 9 0.2 0.8 0.139 ## 10 0.2 0.9 0.0655 ## # … with 394 more rows
複数個の底をa_vals
として値を指定します。
底をa
列、真数(変数)をx
列として、expand_grid()
で全ての組み合わせを作成することで、底の個数分に変数の値を複製します。
底と変数の組み合わせごとに対数を計算します。
複数の底ごとに指数関数を計算します。
# 指数関数 exp_df <- tidyr::expand_grid( a = a_vals, # 底 x = seq(from = -max(log_df[["x"]]), to = max(log_df[["x"]]), length.out = 101) # 変数 ) |> # 底の数に応じて変数を複製 dplyr::mutate( exp_x = a^x, # 指数関数 a = factor(a) # 色分け用に因子化 ) exp_df
## # A tibble: 404 × 3 ## a x exp_x ## <fct> <dbl> <dbl> ## 1 0.2 -10 9765625. ## 2 0.2 -9.8 7077926. ## 3 0.2 -9.6 5129937. ## 4 0.2 -9.4 3718074. ## 5 0.2 -9.2 2694784. ## 6 0.2 -9 1953125 ## 7 0.2 -8.8 1415585. ## 8 0.2 -8.6 1025987. ## 9 0.2 -8.4 743615. ## 10 0.2 -8.2 538957. ## # … with 394 more rows
対数のときと同様にして、底と変数の組み合わせごとに指数を計算します。
先ほどのコードで対数関数と指数関数のグラフを作成します。
## 資料作成用:(再掲) # 恒等関数を格納 identity_df <- tibble::tibble( x = seq(from = min(exp_df[["x"]]), to = max(exp_df[["x"]]), length.out = 101), f_x = x ) # 対数関数を作図 ggplot() + geom_line(data = log_df, mapping = aes(x = x, y = log_x, color = a, linetype = "log")) + # 対数関数 geom_line(data = exp_df, mapping = aes(x = x, y = exp_x, color = a, linetype = "exp")) + # 指数関数 geom_line(data = identity_df, mapping = aes(x = x, y = f_x, linetype = "x")) + # 恒等関数 geom_vline(xintercept = 0, linetype = "dotted") + # 対数関数の漸近線 geom_hline(yintercept = 0, linetype = "dotted") + # 指数関数の漸近線 scale_linetype_manual(breaks = c("log", "exp", "x"), values = c("solid", "dotdash", "dashed"), labels = c(expression(log[a]*x), expression(a^x), expression(x)), name = "function") + # 凡例表示用 coord_fixed(ratio = 1, ylim = c(-10, 10)) + # 描画範囲 theme(legend.text.align = 0) + # 図の体裁 labs(title = "Logarithmic functions and Exponential functions", x = expression(x), y = expression(f(x)))
底が のときと
のときで曲線の形が大きく異なるのを確認できます。
底と曲線の関係をアニメーションで確認します。
・作図コード(クリックで展開)
底の範囲と間隔を指定して、それぞれ対数関数と指数関数を計算します。
# 底用の値を作成 a_vals <- seq(from = 0.1, to = 2.5, by = 0.2) # フレーム数を指定 frame_num <- length(a_vals) # 底ごとに対数関数と指数関数を計算 anim_df <- tidyr::expand_grid( a = a_vals, # 底 x = seq(from = -10, to = 10, by = 0.01) # 変数 ) |> # 底ごとに変数を複製 dplyr::mutate( log_x = dplyr::if_else( condition = a != 1, true = logb(x = x, base = a), false = NA_real_ ), # 対数 exp_x = a^x # 指数 ) anim_df
## # A tibble: 26,013 × 4 ## a x log_x exp_x ## <dbl> <dbl> <dbl> <dbl> ## 1 0.1 -10 NaN 10000000000. ## 2 0.1 -9.99 NaN 9772372210. ## 3 0.1 -9.98 NaN 9549925860. ## 4 0.1 -9.97 NaN 9332543008. ## 5 0.1 -9.96 NaN 9120108394. ## 6 0.1 -9.95 NaN 8912509381. ## 7 0.1 -9.94 NaN 8709635900. ## 8 0.1 -9.93 NaN 8511380382. ## 9 0.1 -9.92 NaN 8317637711. ## 10 0.1 -9.91 NaN 8128305162. ## # … with 26,003 more rows
先ほど同様にして計算します。ただし、(変数(真数)が0未満のときのNaN
は無視できるが底が1のときのInf
は作図に影響するので、)底が1
のときの対数を計算しないようにします。
対数関数と指数関数のアニメーションを作成します。
# 恒等関数を格納 identity_df <- tibble::tibble( x = seq(from = min(anim_df[["x"]]), to = max(anim_df[["x"]]), length.out = 101), f_x = x ) # 対数関数のアニメーションを作図 anim <- ggplot() + geom_line(data = anim_df, mapping = aes(x = x, y = log_x, color = factor(a), linetype = "log"), na.rm = TRUE) + # 対数関数 geom_line(data = anim_df, mapping = aes(x = x, y = exp_x, color = factor(a), linetype = "exp")) + # 指数関数 geom_line(data = identity_df, mapping = aes(x = x, y = f_x, linetype = "x")) + # 恒等関数 geom_vline(xintercept = 0, linetype = "dotted") + # 対数関数の漸近線 geom_hline(yintercept = 0, linetype = "dotted") + # 指数関数の漸近線 gganimate::transition_reveal(along = a) + # フレーム:(過去フレームの曲線も描画) #gganimate::transition_manual(frames = a) + # フレーム:(フレームごとの曲線を描画) scale_color_hue(guide = "none") + # 凡例を非表示 scale_linetype_manual(breaks = c("log", "exp", "x"), values = c("solid", "dotdash", "dashed"), labels = c(expression(log[a]*x), expression(a^x), expression(x)), name = "function") + # 凡例表示用 coord_fixed(ratio = 1, ylim = c(-10, 10)) + # 描画範囲 theme(legend.text.align = 0) + # 図の体裁 labs(title = "Logarithmic functions and Exponential functions", subtitle = "a = {round(frame_along, digits = 2)}", # (transition_reveal関数用) #subtitle = "a = {round(as.numeric(current_frame), digits = 2)}", # (transition_manual関数用) x = expression(x), y = expression(f(x))) # 最終フレームの停止フレームを指定 ep <- 10 # gif画像を作成 #gganimate::animate(plot = anim, nframe = frame_num+ep, end_pause = ep, fps = 10, width = 600, height = 600)
gganimate
パッケージを利用して、アニメーション(gif画像)を作成します。
transition_reveal()
またはtransition_manual()
のフレーム制御の引数(第1引数)に底の値列a
を指定して、底ごとに作図します。transition_reveal()
を使うと過去のフレームの曲線も描画します。transition_manual()
を使うとフレーム(底の値)ごとに曲線を描画します。
animate()
のplot
引数にグラフオブジェクトanim
、nframes
引数にフレーム数frame_num
を指定して、gif画像を作成します。また、fps
引数に1秒当たりのフレーム数を指定できます。
この記事では、対数の定義を確認しました。次の記事では、対数の性質を導出します。
参考文献
- 『わかりやすい ディジタル情報理論』(改訂2版)塩野 充・蜷川 繁,オーム社,2021年.
おわりに
エントロピーを勉強するのに必要だったので書き(勉強し)ました。中高レベルの数学の内容は、良サイトがたくさんあるのでそちらをあたられた方がいいと思います。Rを使って再現したい人にはおすすめできるかもしれません。
分かるようで分かりにくい対数が少し分かった気もします。グラフが綺麗ですね。
【次の内容】