Rの関数:ksmooth {stats}

Rの関数から ksmooth {stats} を確認します。

関数 ksmooth とは

ksmooth は、ナダラヤ・ワトソン推定量(Nadaraya-Watson estimator)を用いたカーネル回帰平滑化(Kernel Regression Smoother) を実行するための関数です。

散布図において、説明変数 \(x\) に対する応答変数 \(y\) の非線形な関係性を捉える際、パラメトリックなモデル(多項式回帰など)を仮定せず、局所的な加重平均を用いて滑らかな曲線を推定します。

特定の \(x\) の地点における \(y\) の予測値を計算するにあたり、対象地点に近い観測データには大きな重みを、遠い観測データには小さな重みを与えて平均値を求めます。

重みの与え方を決定する関数が「カーネル(Kernel)」であり、影響を及ぼす範囲を決定するパラメータが「バンド幅(Bandwidth)」です。

関数 ksmooth の引数

  1. x

    • 説明変数を表す数値ベクトルです。
  2. y

    • 応答変数を表す数値ベクトルです。
    • x と同じ長さである必要があります。
  3. kernel

    • 平滑化に使用するカーネル関数の種類を指定する文字列です。
    • "box":

      • ボックスカーネル(一様カーネル)。指定されたバンド幅の範囲内にある全データに等しい重みを与え、範囲外の重みをゼロとします。単純な移動平均に相当します。
    • "normal" (デフォルト):

      • 正規(ガウシアン)カーネル。距離に応じて正規分布の形状に従い、滑らかに重みを減衰させます。
  4. bandwidth

    • 平滑化の度合い(ウィンドウの幅)を決定する数値です。
    • デフォルト: 0.5
    • 値が大きいほど、x軸(説明変数)方向に広範囲のデータを利用して平均を計算するため、結果はより滑らかになります。逆に値が小さいと局所的な変動を拾いやすくなります。正規カーネルの場合、四分位点が \(\pm 0.25 \times \text{bandwidth}\) となるようにスケーリングされます。
  5. range.x

    • 平滑化された曲線を評価(出力)する \(x\) 軸の範囲を指定するベクトルです。
    • デフォルト: range(x)(入力データ x の最小値から最大値までの範囲)。
  6. n.points

    • 平滑化された曲線を評価する点の数(解像度)です。
    • デフォルト: max(100L, length(x))。100点、あるいはデータ数と同数のいずれか大きい方が選択されます。
  7. x.points

    • 平滑化された値を計算する具体的な \(x\) の座標点を指定するベクトルです。
    • 当該引数が指定された場合、range.x および n.points の指定は無視され、関数は x.points で指定された座標にて計算を行います。出力前に内部で昇順にソートされます。

シミュレーションコード

以下に、ksmooth 関数の機能を確認するためのサンプルデータを用いたシミュレーションコードを示します。

本シミュレーションでは、滑らかなサイン波にノイズ(標準偏差0.5の正規分布)を付加した非線形データを生成します。

当該データに対し、カーネルの種類(Box と Normal)およびバンド幅(狭い、適切、広い)を変更しながら ksmooth を適用し、推定される曲線の形状がどのように変化するかを視覚的に比較・検証します。

(注意) 本シミュレーションにおいて「適切」なバンド幅としている 1.5 は、予めバンド幅0.3から5.0の間の複数のバンド幅で試行した結果を利用しています。

# パッケージの読み込み
library(ggplot2)
library(tidyr)

# 乱数シードの固定
seed <- 20260410
set.seed(seed)

# 1. 観測データの生成
n_obs <- 200
x_vals <- runif(n_obs, min = 0, max = 10)
# 意図的な非線形構造(サイン波)をベースとする
true_signal <- sin(x_vals)
# 観測ノイズを付加
y_obs <- true_signal + rnorm(n_obs, mean = 0, sd = 0.5)

df_sim <- data.frame(
  X = x_vals,
  Y = y_obs,
  TrueSignal = true_signal
)

# 2. ksmooth 関数による平滑化の実行

# 平滑化曲線を評価するX座標を統一して生成(描画を滑らかにするため300点)
eval_points <- seq(0, 10, length.out = 300)

# パターンA: ボックスカーネル (移動平均的挙動)
# バンド幅 1.0
res_box <- ksmooth(x_vals, y_obs, kernel = "box", bandwidth = 1.0, x.points = eval_points)

# パターンB: 正規カーネル + 狭いバンド幅 (過剰適合: ノイズを拾う)
res_norm_narrow <- ksmooth(x_vals, y_obs, kernel = "normal", bandwidth = 0.3, x.points = eval_points)

# パターンC: 正規カーネル + 適切なバンド幅 (良好な適合)
res_norm_optimal <- ksmooth(x_vals, y_obs, kernel = "normal", bandwidth = 1.5, x.points = eval_points)

# パターンD: 正規カーネル + 広いバンド幅 (過小適合: 構造を潰す)
res_norm_wide <- ksmooth(x_vals, y_obs, kernel = "normal", bandwidth = 5.0, x.points = eval_points)


# 3. データの整形と可視化

# 予測結果をデータフレームに格納
df_smooth <- data.frame(
  X_eval = eval_points,
  Box_BW1.0 = res_box$y,
  Norm_Narrow = res_norm_narrow$y,
  Norm_Optimal = res_norm_optimal$y,
  Norm_Wide = res_norm_wide$y
)

# ggplot2 で描画するために縦持ち (Long format) に変換
df_plot <- pivot_longer(
  df_smooth, 
  cols = -X_eval,
  names_to = "Method",
  values_to = "Estimate"
)

# ファセット表示用のラベルを設定
df_plot$Method <- factor(
  df_plot$Method,
  levels = c("Box_BW1.0", "Norm_Narrow", "Norm_Optimal", "Norm_Wide"),
  labels = c(
    "1. ボックスカーネル (Bandwidth = 1.0)",
    "2. 正規カーネル: 狭い (Bandwidth = 0.3)",
    "3. 正規カーネル: 適切 (Bandwidth = 1.5)",
    "4. 正規カーネル: 広い (Bandwidth = 5.0)"
  )
)

# プロットの作成
p1 <- ggplot() +
  # 観測データ (灰色の点)
  geom_point(data = df_sim, aes(x = X, y = Y), color = "gray70", size = 1.5, alpha = 0.6) +
  
  # 真の信号 (黒の破線)
  geom_line(data = df_sim, aes(x = X, y = TrueSignal), color = "black", linetype = "dashed", linewidth = 0.5) +
  
  # ksmooth による平滑化結果 (青の実線)
  geom_line(data = df_plot, aes(x = X_eval, y = Estimate), color = "blue", linewidth = 1.2) +
  
  facet_wrap(~Method, ncol = 2) +
  labs(
    title = "ksmooth 関数によるカーネル回帰の比較",
    x = "説明変数 (X)",
    y = "応答変数 (Y)"
  ) +
  theme_minimal() +
  theme(strip.text = element_text(size = 11, face = "bold"))

print(p1)
Figure 1

Figure 1 の青線が推定結果、黒破線が真の波形です。カーネルの種類とバンド幅の選択が結果を大きく左右することを確認できます。

左上の 1. ボックスカーネル (Bandwidth = 1.0) では、局所的な単純平均を計算するため、階段状に近いカクカクとした粗い曲線となっています。

等重み付けによる境界部分の不連続性が、滑らかさの欠如として視覚的に表れています。

右上の 2. 正規カーネル: 狭い (Bandwidth = 0.3) では、重みが狭い範囲に集中するため、少数の観測値に強く引っ張られています。

結果としてノイズの上下動をそのままトレースしてしまい、過剰適合(オーバーフィッティング)の状態に陥っています。

左下の 3. 正規カーネル: 適切 (Bandwidth = 1.5) では、ノイズの変動を吸収しつつ、背後にある真のサイン波の構造(黒破線)をほぼ抽出しています。

右下の 4. 正規カーネル: 広い (Bandwidth = 5.0) では、遠くの観測値にも大きな重みを与えるため、波形の山や谷が全体的に平均化されてしまいます。

故に本来の構造が潰れてしまい、過小適合(アンダーフィッティング)の典型的な例となっています。

以上です。