;;;; A file of general machine learning utility functions. Always load first. ;;; Variables defining a data set. See any -DATA file for an example (defvar *domains* nil "An ordered list specifying the domain of each feature") (defvar *feature-names* nil "An ordered list of the names for each feature") (defvar *categories* nil "List of categories in a data set") (defvar *raw-examples* nil "List of examples in a data file") ;;;;================================================================================================= ;;;; General Utilities ;;;;================================================================================================= (defmacro trace-print (test-var &rest format-form) ;; Print using the format string only if test-var (usually a trace-* variable)is nonNIl `(if ,test-var (format t ,@format-form))) (defun seconds-since (time) ;;; Return seconds elapsed since given time (initially set by get-internal-run-time) (/ (- (get-internal-run-time) time) internal-time-units-per-second)) (defun mix-up (list) "Randomize the order of elements in this list." (mapcar #'(lambda (pair) (rest pair)) (sort (mapcar #'(lambda (item) (cons (random 1.0) item)) list) #'(lambda (a b) (> (first a) (first b)))))) (defun pick-one (list) "Pick an item randomly from the list" (nth (random (length list)) list)) (defun append-symbols (&rest symbols) "Appends to symbol names and return resulting symbol" (intern (format nil "~{~A~}" symbols))) ;;;;================================================================================================= ;;;; Experimental Utilities ;;;;================================================================================================= (defun train-and-test (system num-train &optional num-test (examples *raw-examples*) (mix-up? t) print-detailed-test-results) "Perform standard train and test on the examples by using the first num-train examples to train and the remaining to test. Randomize order of examples if mix-up? set. Assumes functions of the form system-TRAIN and system-TEST" (if mix-up? (setf examples (mix-up examples))) (let* ((train-function (append-symbols 'train- system)) (training-examples (subseq examples 0 num-train)) (testing-examples (if num-test (subseq examples (- (length examples) num-test)) (subseq examples num-train))) (start-time (get-internal-run-time)) (training-result (funcall train-function training-examples))) (format t "~%~%Train time: ~,2Fs" (seconds-since start-time)) (test-system system training-result testing-examples print-detailed-test-results))) (defun test-system (system training-result test-examples &optional print-detailed-results) "Test the system on the given data and print % correct. If PRINT-DETAILED-RESULTS set then print info about each example" (let ((test-function (append-symbols 'test- system)) (num-examples (length test-examples)) (num-correct 0) answer) (dolist (example test-examples) (setf answer (funcall test-function example training-result)) (when (eq answer (first example)) (incf num-correct)) (trace-print print-detailed-results "~%Real category: ~A; Classified as: ~A ~A" (first example) answer (if (eq answer (first example)) "" "**WRONG**"))) (format t "~%~%~A classified ~,2F% of the ~D test cases correctly." test-function (* 100 (/ num-correct num-examples)) num-examples)))