SMO Support Vector Machines and different kernel functions: polynomic, radia-basis and string kernels

This commit is contained in:
Antonio Garrote 2010-03-07 18:22:04 +01:00
parent c1c7ba0ac5
commit f91328f5e4
4 changed files with 146 additions and 1 deletions

View file

@ -4,12 +4,13 @@
;; ;;
(ns clj-ml.classifiers (ns clj-ml.classifiers
(:use [clj-ml utils data]) (:use [clj-ml utils data kernel-functions])
(:import (java.util Date Random) (:import (java.util Date Random)
(weka.classifiers.trees J48) (weka.classifiers.trees J48)
(weka.classifiers.bayes NaiveBayes) (weka.classifiers.bayes NaiveBayes)
(weka.classifiers.bayes NaiveBayesUpdateable) (weka.classifiers.bayes NaiveBayesUpdateable)
(weka.classifiers.functions MultilayerPerceptron) (weka.classifiers.functions MultilayerPerceptron)
(weka.classifiers.functions SMO)
(weka.classifiers Evaluation))) (weka.classifiers Evaluation)))
@ -65,9 +66,24 @@
cols-val)] cols-val)]
(into-array cols-val-a)))) (into-array cols-val-a))))
(defmethod make-classifier-options [:support-vector-machine :smo]
([kind algorithm map]
(let [cols-val (check-options {:fit-logistic-models "-M"}
map
[""])
cols-val-a (check-option-values {:complexity-constant "-C"
:tolerance "-L"
:epsilon-roundoff "-P"
:folds-for-cross-validation "-V"
:random-seed "-W"}
map
cols-val)]
(into-array cols-val-a))))
;; Building classifiers ;; Building classifiers
(defmacro make-classifier-m (defmacro make-classifier-m
([kind algorithm classifier-class options] ([kind algorithm classifier-class options]
`(let [options-read# (if (empty? ~options) {} (first ~options)) `(let [options-read# (if (empty? ~options) {} (first ~options))
@ -95,6 +111,21 @@
([kind algorithm & options] ([kind algorithm & options]
(make-classifier-m kind algorithm MultilayerPerceptron options))) (make-classifier-m kind algorithm MultilayerPerceptron options)))
(defmethod make-classifier [:support-vector-machine :smo]
([kind algorithm & options]
(let [options-read (if (empty? options) {} (first options))
classifier (new SMO)
opts (make-classifier-options :support-vector-machine :smo options-read)]
(.setOptions classifier opts)
(when (not (empty? (get options-read :kernel-function)))
;; We have to setup a different kernel function
(let [kernel (get options-read :kernel-function)
real-kernel (if (map? kernel)
(make-kernel-function (first (keys kernel))
(first (vals kernel)))
kernel)]
(.setKernel classifier real-kernel)))
classifier)))
;; Training classifiers ;; Training classifiers

View file

@ -0,0 +1,81 @@
;;
;; Kernel functions for SVM classifiers
;; @author Antonio Garrote
;;
(ns clj-ml.kernel-functions
(:use [clj-ml utils data])
(:import (weka.classifiers.functions.supportVector PolyKernel RBFKernel StringKernel)))
(defmulti make-kernel-function-options
"Creates ther right parameters for a kernel-function"
(fn [kind map] kind))
(defmethod make-kernel-function-options :polynomic
([kind map]
(let [cols-val (check-option-values {:cache-size "-C"
:exponent "-E"
:use=lower-order-terms "-L"}
map
[""])]
(into-array cols-val))))
(defmethod make-kernel-function-options :radial-basis
([kind map]
(let [cols-val (check-option-values {:cache-size "-C"
:gamma "-G"}
map
[""])]
(into-array cols-val))))
(defmethod make-kernel-function-options :string
([kind map]
(let [pre-values-a (if (get map :use-normalization)
(if (get map :use-normalization)
["-N" "yes"]
["-N" "no"])
[""])
_foo (println (str "pre a" pre-values-a " map " map))
pre-values-b (if (get map :pruning)
(if (= (get map :pruning)
:lambda)
(conj (conj pre-values-a "-P") "1")
(conj (conj pre-values-a "-P" ) "0"))
pre-values-a)
_foo (println (str "pre b" pre-values-b))
cols-val (check-option-values {:cache-size "-C"
:internal-cache-size "-IC"
:lambda "-L"
:sequence-length "-ssl"
:maximum-sequence-length "-ssl-max"}
map
pre-values-b)]
(into-array cols-val))))
(defmulti make-kernel-function
"Creates a new kernel function"
(fn [kind & options] kind))
(defmethod make-kernel-function :polynomic
([kind & options]
(let [dist (new PolyKernel)
opts (make-kernel-function-options :polynomic (first-or-default options {}))]
(.setOptions dist opts)
dist)))
(defmethod make-kernel-function :radial-basis
([kind & options]
(let [dist (new RBFKernel)
opts (make-kernel-function-options :radial-basis (first-or-default options {}))]
(.setOptions dist opts)
dist)))
(defmethod make-kernel-function :string
([kind & options]
(let [dist (new StringKernel)
opts (make-kernel-function-options :string (first-or-default options {}))]
(.setOptions dist opts)
dist)))

View file

@ -2,6 +2,7 @@
(:use [clj-ml classifiers data] :reload-all) (:use [clj-ml classifiers data] :reload-all)
(:use [clojure.test])) (:use [clojure.test]))
(deftest make-classifiers-options-c45 (deftest make-classifiers-options-c45
(let [options (make-classifier-options :decission-tree :c45 {:unpruned true :reduced-error-pruning true :only-binary-splits true :no-raising true (let [options (make-classifier-options :decission-tree :c45 {:unpruned true :reduced-error-pruning true :only-binary-splits true :no-raising true
:no-cleanup true :laplace-smoothing true :pruning-confidence 0.12 :minimum-instances 10 :no-cleanup true :laplace-smoothing true :pruning-confidence 0.12 :minimum-instances 10
@ -79,6 +80,11 @@
res (classifier-evaluate c :dataset ds tds)] res (classifier-evaluate c :dataset ds tds)]
(is (= 26 (count (keys res)))))) (is (= 26 (count (keys res))))))
(deftest make-classifier-svm-smo-polykernel
(let [svm (make-classifier :support-vector-machine :smo {:kernel-function {:polynomic {:exponent 2.0}}})]
(is (= weka.classifiers.functions.supportVector.PolyKernel
(class (.getKernel svm))))))
(deftest classifier-evaluate-cross-validation (deftest classifier-evaluate-cross-validation
(let [c (make-classifier :decission-tree :c45) (let [c (make-classifier :decission-tree :c45)

View file

@ -0,0 +1,27 @@
(ns clj-ml.kernel-functions-test
(:use [clj-ml kernel-functions] :reload-all)
(:use [clojure.test]))
(deftest make-kernel-function-polynomic
(let [kernel (clj-ml.kernel-functions/make-kernel-function :polynomic {:exponent 0.3})
options (.getOptions kernel)]
(is (= (aget options 2)
"-E"))
(is (= (aget options 3)
"0.3"))))
(deftest make-kernel-function-radial-basis
(let [kernel (clj-ml.kernel-functions/make-kernel-function :radial-basis {:gamma 0.3})
options (.getOptions kernel)]
(is (= (aget options 2)
"-G"))
(is (= (aget options 3)
"0.3"))))
(deftest make-kernel-function-string
(let [kernel (clj-ml.kernel-functions/make-kernel-function :string {:lambda 0})
options (.getOptions kernel)]
(is (= (aget options 6)
"-L"))
(is (= (aget options 7)
"0.0"))))