packages feed

HLearn-classification-0.0.1: src/HLearn/Evaluation/CrossValidation.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE BangPatterns #-}

module HLearn.Evaluation.CrossValidation
    where

import qualified Data.Map as Map
import qualified Data.Set as S
-- import qualified Data.Vector as V

import Debug.Trace
import Data.DList

import HLearn.Algebra
import HLearn.DataContainers
-- import HLearn.Evaluation.Metrics
import HLearn.Models.Classification
import HLearn.Models.Distributions
import qualified Control.ConstraintKinds as CK

-------------------------------------------------------------------------------
-- standard k-fold cross validation

-- crossValidation :: 
--     ( HomTrainer modelparams datapoint model
--     , PerformanceMeasure perfmeasure model container datapoint ret
--     , Semigroup ret
--     , CK.Functor container
--     , CK.FunctorConstraint container datapoint
--     , CK.FunctorConstraint container model
--     , CK.Foldable container
--     , CK.FoldableConstraint container model
--     , CK.FoldableConstraint container datapoint
--     , CK.Partitionable container
--     , CK.PartitionableConstraint container datapoint
--     )
--     => modelparams -> container datapoint -> perfmeasure -> Int -> ret
-- crossValidation modelparams dataset perfmeasure k = reduce $ do
--     testdata <- datasetL
--     let trainingdata = testdata
--     let model = train' modelparams trainingdata
--     let score = measure perfmeasure model testdata
--     return score
--     where
--         datasetL = CK.partition k dataset

crossValidation :: 
    ( HomTrainer modelparams datapoint model
    , Semigroup ret
    , Semigroup (container datapoint)
    , CK.Functor container
    , CK.FunctorConstraint container datapoint
    , CK.FunctorConstraint container model
    , CK.Foldable container
    , CK.FoldableConstraint container model
    , CK.FoldableConstraint container datapoint
    , CK.Partitionable container
    , CK.PartitionableConstraint container datapoint
    ) => modelparams -> container datapoint -> (model -> container datapoint -> ret) -> Int -> ret
crossValidation modelparams dataset perfmeasure k = reduce $ do
    (testdata, trainingdata) <- genTestList datasetL
    let model = train' modelparams trainingdata
    let score = perfmeasure model testdata
    return score
    where
        datasetL = CK.partition k dataset

crossValidation_par modelparams dataset perfmeasure k = (parallel reduce) $ do
    (testdata, trainingdata) <- genTestList datasetL
    let model = train' modelparams trainingdata
    let score = perfmeasure model testdata
    return score
    where
        datasetL = CK.partition k dataset

crossValidation_monoid :: 
    ( HomTrainer modelparams datapoint model
    , Semigroup model
    , Semigroup ret
    , Semigroup (container datapoint)
    , CK.Functor container
    , CK.FunctorConstraint container datapoint
    , CK.FunctorConstraint container model
    , CK.Foldable container
    , CK.FoldableConstraint container model
    , CK.FoldableConstraint container datapoint
    , CK.Partitionable container
    , CK.PartitionableConstraint container datapoint
    ) => modelparams -> container datapoint -> (model -> container datapoint -> ret) -> Int -> ret
crossValidation_monoid modelparams dataset perfmeasure k = reduce $ do
    (testdata,model) <- zip datasetL $ listAllBut modelL
    let score = perfmeasure model testdata
    return score
    where
        modelL = fmap (train' modelparams) datasetL
        datasetL = CK.partition k dataset

crossValidation_monoid_par modelparams dataset perfmeasure k = (parallel reduce) $ do
    (testdata,model) <- zip datasetL $ listAllBut modelL
    let score = perfmeasure model testdata
    return score
    where
        modelL = fmap (train' modelparams) datasetL
        datasetL = CK.partition k dataset


crossValidation_group :: 
    ( HomTrainer modelparams datapoint model
    , Group model
    , Semigroup ret
    , Semigroup (container datapoint)
    , CK.Functor container
    , CK.FunctorConstraint container datapoint
    , CK.FunctorConstraint container model
    , CK.Foldable container
    , CK.FoldableConstraint container model
    , CK.FoldableConstraint container datapoint
    , CK.Partitionable container
    , CK.PartitionableConstraint container datapoint
    ) => modelparams -> container datapoint -> (model -> container datapoint -> ret) -> Int -> ret
crossValidation_group modelparams dataset perfmeasure k = reduce $ do
    testdata <- datasetL
    let model = fullModel <> (inverse $ train' modelparams testdata)
    let score = perfmeasure model testdata
    return score    
    where
        fullModel = reduce modelL
        modelL = fmap (train' modelparams) datasetL
        datasetL = CK.partition k dataset

crossValidation_group_par modelparams dataset perfmeasure k = (parallel reduce) $ do
    testdata <- datasetL
    let model = fullModel <> (inverse $ train' modelparams testdata)
    let score = perfmeasure model testdata
    return score    
    where
        fullModel = (parallel reduce) modelL
        modelL = fmap (train' modelparams) datasetL
        datasetL = CK.partition k dataset


listAllBut2 :: (Semigroup a) => [a] -> [a]
listAllBut2 !xs = [reduce $ testL i | i <- itrL]
    where
        itrL = [0..(length xs)-1]
        testL i = (take (i) xs) ++ (drop (i+1) xs)

listAllBut :: (Semigroup a) => [a] -> [a]
listAllBut !xs = [reduce $ testL i | i <- itrL]
    where
        itrL = [0..(length xs)-1]
        testL i = (fromList $ take (i) xs) `mappend` (fromList $ drop (i+1) xs)

instance CK.Foldable DList where
    foldr = Data.DList.foldr

genTestList :: (Semigroup a) => [a] -> [(a,a)]
genTestList xs = zip xs $ listAllBut xs


-- class PerformanceMeasure measure model container datapoint outtype | measure -> outtype where
--     measure :: measure -> model -> container datapoint -> outtype
-- 
-- data Accuracy = Accuracy
-- 
-- instance
--     ( CK.Functor container
--     , CK.FunctorConstraint container Double
--     , CK.FunctorConstraint container (label,DPS)
--     , CK.Foldable container
--     , CK.FoldableConstraint container Double
--     , CK.FoldableConstraint container [Double]
--     , CK.FoldableConstraint container datapoint
--     , CK.FoldableConstraint container (LDPS label)
--     , CK.FoldableConstraint container [LDPS label]
--     , Classifier model DPS label
--     ) => PerformanceMeasure Accuracy model container (LDPS label) (Gaussian Double)
--         where
--         
--     measure metricparams model testdata = train1dp ((foldl1 (+) checkedL)/(fromIntegral $ numdp) :: Double)
--         where
--             checkdp (label,dp) = indicator $ label==(classify model dp)
--             checkedL = CK.toList $ CK.fmap checkdp testdata
--             numdp = length $ CK.toList testdata

accuracy :: 
    ( CK.Functor container
    , CK.FunctorConstraint container Double
    , CK.FunctorConstraint container (label,datapoint)
    , CK.Foldable container
    , CK.FoldableConstraint container Double
    , CK.FoldableConstraint container [Double]
    , CK.FoldableConstraint container datapoint
    , CK.FoldableConstraint container (Labeled datapoint label)
    , CK.FoldableConstraint container [Labeled datapoint label]
    , Classifier model datapoint label
    , Eq label
    ) => model -> container (Labeled datapoint label) -> (Gaussian Double)
accuracy model testdata = train1dp ((foldl1 (+) checkedL)/(fromIntegral $ numdp) :: Double)
    where
        checkdp (label,dp) = indicator $ label==(classify model dp)
        checkedL = CK.toList $ CK.fmap checkdp testdata
        numdp = length $ CK.toList testdata


-- data CVType = CV_Normal | CV_Monoid | CV_Group
-- 
-- data CVParams = CVParams
--     { folds :: Int
--     , metric :: Metric metric model ds label outtype
--     }
-- 
-- data CVResults = CVResults
--     {
--     }
-- 
-- instance Model CVParams CVResults where
--     
-- instance HomTrainer CVParams (LDPS label) CVResults where
--     train' CVParams ldps = undefined
-- 
-- instance Monoid CVResults
-- 
-- instance Semigroup CVResults

-- crossValidation :: 
--     ( NFData model
--     , NFData outtype
--     , Semigroup outtype
--     , DataSparse label ds label
--     , DataSparse label ds DPS
--     , DataSparse label ds (Labeled DPS label)
--     , DataSparse label ds (Weighted (Labeled DPS label))
--     , DataSparse label ds [(label,probability)]
--     , HomTrainer modelparams model DPS label
--     , Metric metric model ds label outtype
--     ) =>
--      metric
--      -> modelparams
--      -> ds (Labeled DPS label)
--      -> Double
--      -> Double
--      -> Int
--      -> Random outtype
-- crossValidation metric modelparams inputdata trainingRatio labeledRatio rounds = foldl1' (<>) $
--     [ do
--         (trainingdata,testdata) <- randSplit trainingRatio inputdata
--         (lds,uds) <- randSplit labeledRatio trainingdata
--         let uds' = fmap snd uds
--         model <- trainBatchSS modelparams lds uds'
--         return $ deepseq model $ measure metric model testdata
--     | i <- [1..rounds]
--     ]