From f2e96cff2155852f480e0dc03b9b4186ca38db4b Mon Sep 17 00:00:00 2001 From: Marcus Kammer Date: Tue, 15 Oct 2024 18:40:14 +0200 Subject: [PATCH] Move assessment code to the corresponding files --- dev.metalisp.survey.asd | 4 +- src/assessment/assessment.lisp | 99 ---------------------------------- src/assessment/sus.lisp | 50 +++++++++++++++++ src/assessment/visawi.lisp | 53 ++++++++++++++++++ 4 files changed, 106 insertions(+), 100 deletions(-) create mode 100644 src/assessment/sus.lisp create mode 100644 src/assessment/visawi.lisp diff --git a/dev.metalisp.survey.asd b/dev.metalisp.survey.asd index 8190e87..a46af0d 100644 --- a/dev.metalisp.survey.asd +++ b/dev.metalisp.survey.asd @@ -17,7 +17,9 @@ (:file "stats") (:module "assessment/" :components - ((:file "assessment"))) + ((:file "assessment") + (:file "sus") + (:file "visawi"))) (:file "survey") (:file "questionnaire") (:file "surveys") diff --git a/src/assessment/assessment.lisp b/src/assessment/assessment.lisp index 97db289..42e66d7 100644 --- a/src/assessment/assessment.lisp +++ b/src/assessment/assessment.lisp @@ -133,93 +133,6 @@ ENTRY: Entry from a response." (defgeneric calculator-group-stats (calculator results)) -;;; sus specific code - -(defun sus-response-entry-negative-p (key-str) - (let ((number (string-integer key-str))) - (if (evenp number) - t - nil))) - -(defun sus-recode-values (values) - (let ((counter 0)) - (mapcar (lambda (x) - (setq counter (1+ counter)) - (if (evenp counter) - (- 5 x) - (1- x))) - values))) - -(defun sus-score (values) - (let ((values (remove-if #'keywordp values))) - (list :SCORE (* (apply #'+ values) 2.5)))) - -(defun sus-recode-value (value negative-p) - (if negative-p - (- 5 value) - (1- value))) - -(defun sus-response-entry-process (entry) - (response-entry-process #'sus-response-entry-negative-p #'sus-recode-value entry)) - -(defclass sus-calculator (calculator) ()) - -(defmethod calculator-calc-results ((calc sus-calculator) responses) - (loop :for response :in responses - :for timestamp = (first response) - :for values = (reverse-pairs (aggregate-values-per-category #'sus-response-entry-process - (rest response))) - :collect (cons :TIMESTAMP - (cons timestamp - (append values (sus-score values)))))) - -(defmethod calculator-group-stats ((calc sus-calculator) results) - nil) - -(defun visawi-value-matching (value) -(case value - (1 7) - (2 6) - (3 5) - (4 4) - (5 3) - (6 2) - (7 1))) - -(defun visawi-recode-value (value negative-p) - "Recode response score from negative question. -VALUE is a integer. -NEGATIVE-P is a Predicate. -Returns an integer." - (if negative-p - (visawi-value-matching value) - value)) - -(defun visawi-entry-process (entry) - (response-entry-process #'response-entry-negative-p #'visawi-recode-value entry)) - -(defclass visawi-calculator (calculator) ()) - -(defmethod calculator-calc-results ((calc visawi-calculator) responses) - (loop :for response :in responses - :for timestamp = (first response) - :collect (cons :timestamp - (cons timestamp (mean-score-per-category #'visawi-entry-process - (rest response)))))) - -(defmethod calculator-group-stats ((calc visawi-calculator) results) - (if (> (length results) 1) - (flet ((merge-entry (acc entry) - (loop :for (key value) :on entry :by #'cddr - :do (push value (getf acc key))) - acc)) - (let ((merged-values (reduce #'merge-entry - (mapcar #'cddr results) - :initial-value '()))) - (reverse (loop :for (key value) :on merged-values :by #'cddr - :collect (list key (calculate-statistics value)))))) - nil)) - ;;; Displayer (defclass displayer () @@ -235,15 +148,3 @@ Returns an integer." (when group-stats (with-section (with-title-bar "Group Analysis") (render-nested-plist-tbl group-stats))))) - -(defclass sus-assessment (assessment) ()) - -(defmethod initialize-instance :after ((a sus-assessment) &key) - (setf (assessment-calculator a) (make-instance 'sus-calculator) - (assessment-displayer a) (make-instance 'displayer :name "SUS"))) - -(defclass visawi-assessment (assessment) ()) - -(defmethod initialize-instance :after ((a visawi-assessment) &key) - (setf (assessment-calculator a) (make-instance 'visawi-calculator) - (assessment-displayer a) (make-instance 'displayer :name "VISAWI"))) diff --git a/src/assessment/sus.lisp b/src/assessment/sus.lisp new file mode 100644 index 0000000..d38d90e --- /dev/null +++ b/src/assessment/sus.lisp @@ -0,0 +1,50 @@ +;;;; -*- mode: common-lisp; coding: utf-8; -*- + +(in-package :ml-survey/assessment) + +(defun sus-response-entry-negative-p (key-str) + (let ((number (string-integer key-str))) + (if (evenp number) + t + nil))) + +(defun sus-recode-values (values) + (let ((counter 0)) + (mapcar (lambda (x) + (setq counter (1+ counter)) + (if (evenp counter) + (- 5 x) + (1- x))) + values))) + +(defun sus-score (values) + (let ((values (remove-if #'keywordp values))) + (list :SCORE (* (apply #'+ values) 2.5)))) + +(defun sus-recode-value (value negative-p) + (if negative-p + (- 5 value) + (1- value))) + +(defun sus-response-entry-process (entry) + (response-entry-process #'sus-response-entry-negative-p #'sus-recode-value entry)) + +(defclass sus-calculator (calculator) ()) + +(defmethod calculator-calc-results ((calc sus-calculator) responses) + (loop :for response :in responses + :for timestamp = (first response) + :for values = (reverse-pairs (aggregate-values-per-category #'sus-response-entry-process + (rest response))) + :collect (cons :TIMESTAMP + (cons timestamp + (append values (sus-score values)))))) + +(defmethod calculator-group-stats ((calc sus-calculator) results) + nil) + +(defclass sus-assessment (assessment) ()) + +(defmethod initialize-instance :after ((a sus-assessment) &key) + (setf (assessment-calculator a) (make-instance 'sus-calculator) + (assessment-displayer a) (make-instance 'displayer :name "SUS"))) diff --git a/src/assessment/visawi.lisp b/src/assessment/visawi.lisp new file mode 100644 index 0000000..f6e457d --- /dev/null +++ b/src/assessment/visawi.lisp @@ -0,0 +1,53 @@ +;;;; -*- mode: common-lisp; coding: utf-8; -*- + +(in-package :ml-survey/assessment) + +(defun visawi-value-matching (value) +(case value + (1 7) + (2 6) + (3 5) + (4 4) + (5 3) + (6 2) + (7 1))) + +(defun visawi-recode-value (value negative-p) + "Recode response score from negative question. +VALUE is a integer. +NEGATIVE-P is a Predicate. +Returns an integer." + (if negative-p + (visawi-value-matching value) + value)) + +(defun visawi-entry-process (entry) + (response-entry-process #'response-entry-negative-p #'visawi-recode-value entry)) + +(defclass visawi-calculator (calculator) ()) + +(defmethod calculator-calc-results ((calc visawi-calculator) responses) + (loop :for response :in responses + :for timestamp = (first response) + :collect (cons :timestamp + (cons timestamp (mean-score-per-category #'visawi-entry-process + (rest response)))))) + +(defmethod calculator-group-stats ((calc visawi-calculator) results) + (if (> (length results) 1) + (flet ((merge-entry (acc entry) + (loop :for (key value) :on entry :by #'cddr + :do (push value (getf acc key))) + acc)) + (let ((merged-values (reduce #'merge-entry + (mapcar #'cddr results) + :initial-value '()))) + (reverse (loop :for (key value) :on merged-values :by #'cddr + :collect (list key (calculate-statistics value)))))) + nil)) + +(defclass visawi-assessment (assessment) ()) + +(defmethod initialize-instance :after ((a visawi-assessment) &key) + (setf (assessment-calculator a) (make-instance 'visawi-calculator) + (assessment-displayer a) (make-instance 'displayer :name "VISAWI")))