hanalyze-0.1.0.0: demo/regression/RegularizedDemo.hs
{-# LANGUAGE OverloadedStrings #-}
-- | 正則化回帰デモ (Phase Q)。
--
-- 真の β = [3, -2, 0, 0, 1.5, 0, 0, 0, 0, 0] (10 列、5 つだけ非ゼロ)
-- p=10 列、n=50 観測、相関ある特徴量を含む高次元設定。
-- OLS / Ridge / Lasso / Elastic Net を比較。
module Main where
import qualified Data.Vector as V
import qualified Numeric.LinearAlgebra as LA
import Text.Printf (printf)
import System.Random.MWC (createSystemRandom)
import qualified System.Random.MWC.Distributions as MWC
import Hanalyze.Model.Regularized (Penalty (..), RegFit (..),
fitRegularized, standardize)
main :: IO ()
main = do
putStrLn "═══════════════════════════════════════════════════════════════"
putStrLn " 正則化回帰デモ (Phase Q) — Ridge / Lasso / ElasticNet"
putStrLn "═══════════════════════════════════════════════════════════════"
putStrLn ""
let n = 50
p = 10
betaTrue = [3.0, -2.0, 0.0, 0.0, 1.5, 0.0, 0.0, 0.0, 0.0, 0.0]
printf "設定: n=%d, p=%d\n" n p
printf "真の β = %s\n" (show betaTrue)
printf " 非ゼロ: 3 個 (列 1, 2, 5)\n"
putStrLn ""
-- データ生成
gen <- createSystemRandom
rows <- mapM (const (V.replicateM p (MWC.standard gen))) [1 .. n :: Int]
let xMat = LA.fromLists [V.toList r | r <- rows]
bV = LA.fromList betaTrue
noise <- LA.fromList <$> mapM (const (MWC.normal 0 0.5 gen)) [1 .. n]
let yV = (xMat LA.#> bV) + noise
-- 標準化
let (xStd, _means, sds) = standardize xMat
printf "X 列 sd の範囲: [%.3f, %.3f]\n"
(V.minimum sds) (V.maximum sds)
putStrLn ""
-- 4 モデルを fit
let fits =
[ ("OLS ", fitRegularized NoPen xStd yV)
, ("Ridge λ=0.1 ", fitRegularized (L2 0.1) xStd yV)
, ("Ridge λ=1.0 ", fitRegularized (L2 1.0) xStd yV)
, ("Lasso λ=0.05 ", fitRegularized (L1 0.05) xStd yV)
, ("Lasso λ=0.20 ", fitRegularized (L1 0.20) xStd yV)
, ("ElasticNet (.1,.1)", fitRegularized (ElasticNet 0.1 0.1) xStd yV)
]
putStrLn "[1] 各モデルの係数 (標準化空間)"
printf " %-18s | R² | nonZero | iters\n" ("Model" :: String)
putStrLn (replicate 60 '-')
mapM_ (\(name, fit) ->
printf " %s | %.4f | %7d | %5d\n"
(name :: String)
(rfR2 fit)
(rfNonZero fit)
(rfIters fit))
fits
putStrLn ""
putStrLn "[2] 推定 β を真値と比較 (列ごと)"
printf " %-2s %s\n"
("j" :: String)
(concat ["%-8s" | _ <- fits] :: String)
printf " %s\n"
(concat [printf "%-8s" (take 7 name) :: String
| (name, _) <- fits])
putStrLn (replicate 70 '-')
mapM_ (\j ->
do
printf " %2d (%5.2f)" j (betaTrue !! j)
mapM_ (\(_, fit) ->
printf " %+7.3f"
((LA.toList (rfBeta fit)) !! j))
fits
putStrLn "")
[0 .. p - 1 :: Int]
putStrLn ""
-- 評価: 真値からの距離
putStrLn "[3] β 推定誤差 ||β̂ − β_true||₂ と sparsity"
printf " %-18s | β 誤差 | sparsity (= 推定 0 の数)\n" ("Model" :: String)
putStrLn (replicate 60 '-')
-- β を unstandardize で元スケールに戻す
let bTrueV = LA.fromList betaTrue
mapM_ (\(name, fit) ->
do
-- 標準化 X で fit した β を元の x スケールに戻す:
-- β_orig_j = β_std_j / sd_j
let bStd = rfBeta fit
bOrig = LA.fromList
[ (bStd `LA.atIndex` j) / (sds V.! j)
| j <- [0 .. p - 1] ]
err = LA.norm_2 (bOrig - bTrueV)
zeros = length [v | v <- LA.toList bStd, abs v <= 1e-8]
printf " %s | %6.3f | %5d / %d\n"
(name :: String) err zeros p)
fits
putStrLn ""
putStrLn "═══════════════════════════════════════════════════════════════"
putStrLn " ✓ Lasso が真の sparse 構造を回復"
putStrLn " Ridge は非ゼロを縮小、Elastic Net は中間"
putStrLn "═══════════════════════════════════════════════════════════════"