hanalyze-0.1.0.0: demo/io/PotentialMultiKR.hs
{-# LANGUAGE OverloadedStrings #-}
-- | 多出力 RBF カーネルリッジ回帰デモ。
--
-- データ: data/io/potential_wide.csv (21 dose 行 × 100 z 出力列)
-- モデル: ŷ_j(d) = Σ_i K_h(d, d_i) · α_{ij} ; α = (K + λI)⁻¹ Y
-- HP : LOOCV 解析解で h, λ をグリッド最適化
-- 出力 : trash/potential_multikr.html
module Main where
import qualified Data.Text as T
import qualified Data.Vector as V
import qualified Numeric.LinearAlgebra as LA
import Text.Printf (printf)
import qualified Hanalyze.DataIO.CSV as IO
import qualified Hanalyze.DataIO.Convert as Conv
import qualified Hanalyze.Model.Kernel as K
import Hanalyze.Viz.ReportBuilder
zGrid :: [Double]
zGrid =
let step = 200.0 / 99.0
in [ fromIntegral i * step | i <- [0 .. 99 :: Int] ]
main :: IO ()
main = do
Right df <- IO.loadAuto "data/io/potential_wide.csv"
let yColNames = [ T.pack (printf "y_z%03d" (i :: Int)) | i <- [1..100] ]
Just doseV = Conv.getDoubleVec "dose" df
yCols = map (\c -> case Conv.getDoubleVec c df of
Just v -> v
Nothing -> error ("missing column: " ++ T.unpack c))
yColNames
n = V.length doseV
q = length yCols
ys = LA.fromLists
[ [ (yCols !! j) V.! i | j <- [0 .. q - 1] ]
| i <- [0 .. n - 1] ]
hs = K.defaultHGrid doseV
lams = K.defaultLamGrid
(fit, bestH, bestL, looMSE) =
K.autoTuneKernelRidgeMulti K.Gaussian doseV ys hs lams
yhat = K.fittedKernelRidgeMulti fit
r2v = K.r2Multi ys yhat
res = ys - yhat
rmse = sqrt (LA.sumElements (res * res) / fromIntegral (n * q))
putStrLn "=== Multi-output Kernel Ridge (RBF, dose only) ==="
printf " N (rows) = %d\n" n
printf " q (outputs) = %d\n" q
printf " best h = %.4f\n" bestH
printf " best lambda = %.6g\n" bestL
printf " LOO MSE = %.6f\n" looMSE
printf " RMSE (train) = %.4f\n" rmse
printf " R^2 mean = %.4f (min %.4f, max %.4f)\n"
(V.sum r2v / fromIntegral q)
(V.minimum r2v) (V.maximum r2v)
let xObs = V.toList doseV
yObs = [ [ (yCols !! j) V.! i | j <- [0 .. q - 1] ]
| i <- [0 .. n - 1] ]
alpha2 = [ LA.toList (LA.flatten (K.krmAlpha fit LA.? [i]))
| i <- [0 .. n - 1] ] -- n × q (行抽出)
dMin = minimum xObs - 2.0
dMax = maximum xObs + 2.0
dMid = 0.5 * (dMin + dMax)
imo = mkInteractiveMOKernelRBF "dose" "potential V" "z [nm]"
zGrid xObs yObs
xObs alpha2 bestH
(dMin, dMid, dMax)
sections =
[ secModelOverview "Multi-output Kernel Ridge (RBF)"
"$\\hat{y}_j(d) = \\sum_i \\exp(-\\frac{(d-d_i)^2}{2h^2}) \\, \\alpha_{ij}$"
Nothing
, secStatRow
[ ("N", T.pack (show n))
, ("q (outputs)", T.pack (show q))
, ("best h", T.pack (printf "%.3f" bestH))
, ("best λ", T.pack (printf "%.2g" bestL))
, ("LOO MSE", T.pack (printf "%.4g" looMSE))
, ("RMSE", T.pack (printf "%.4f" rmse))
, ("R^2 mean", T.pack (printf "%.4f"
(V.sum r2v / fromIntegral q :: Double)))
]
, secInteractiveMultiOut "予測曲線 (dose スライダ)" imo
]
cfg = defaultReportConfig "Potential — Multi-output Kernel Ridge (RBF)"
renderReport "trash/potential_multikr.html" cfg sections
putStrLn "Wrote trash/potential_multikr.html"