Notxor tiene un blog

Defenestrando la vida

MiniMult corregido

Notxor
2017-02-05

He estado estos días trabajando un poco en el tema de corregir el MiniMult de forma automática con resultados irregulares. De momento me encuentro con ese regustillo a chapuza cuando no haces las cosas como piensas que se deberían hacer. Pero al final funciona, que era de momento el objetivo. Me voy a explicar por partes, comenzando por el final y luego dando saltos como es mi costumbre últimamente (es lo que tiene este cerebro que me ha tocado).

Funcionar, funciona

MiniMultCorregido.png

Como se puede ver en la imagen anterior el sistema devuelve las puntuaciones T del MiniMult corregidas. Ahora explicaré cómo lo he ido haciendo y las chapuzas que he tenido que hacer por el camino.

Obtener las puntuaciones directas

Para obtener las puntuaciones directas lo que debemos hacer primero es contar con unas plantillas que nos permitan saber si cada contestación del sujeto puntúa en una determinada escala. Como ya hablé de cómo había pensado guardarlas en formato de lista sólo voy a repasarlo un poco por encima:

(defvar minimult-plantilla
  '(
    ("L"  11 "F" 1) ... ("L"  53 "F" 1)
    ("F"   9 "V" 1) ... ("F"  71 "V" 1)
    ("K"  11 "F" 1) ... ("K"  70 "F" 1)
    ("Hs"  1 "F" 1) ... ("Hs" 62 "F" 1)
    ("D"   1 "F" 1) ... ("D"  65 "F" 1)
    ("Hy"  1 "F" 1) ... ("Hy" 62 "F" 1)
    ("Pd"  3 "F" 1) ... ("Pd" 71 "V" 1)
    ("Pa"  5 "V" 1) ... ("Pa" 68 "V" 1)
    ("Pt"  2 "F" 1) ... ("Pt" 68 "V" 1)
    ("Sc"  3 "F" 1) ... ("Sc" 66 "V" 1)
    ("Ma"  4 "V" 1) ... ("Ma" 60 "V" 1)
    ("Si" 13 "V" 1) ... ("Si" 70 "V" 1)
    )
  "Plantilla de corrección con valores posicionales.
1. Nombre de escala
2. Número de pregunta
3. Valor puntuable
4. Cantidad de puntos si coincide la respuestas con el valor puntuable.")

En el código de la definición de la variable minimult-plantilla he puesto sólo la primera y la última de las respuestas de cada escala. Ponerlo todo sería confuso y no aportaría nada. Para saber el resto basta con repasar la serie sobre el MiniMult y se encontrará una tabla con la plantilla. Luego el código que corrige el test recorrerá esta variable de principio a fin comprobando y guardando las coincidencias para obtener las puntuaciones directas.

;; Recorrer toda la plantilla en un bucle while
(let ((contador 0)
  (largo-plantilla (length minimult-plantilla))
  (escala "")
  (pregunta 0)
  (respuesta "-")
  (valor 0)
  (elemento '()))
  (while (< contador largo-plantilla)
    ;; Obtener la plantilla y sus valores
    (setq elemento (nth contador minimult-plantilla))
    (setq escala (nth 0 elemento))
    (setq pregunta (nth 1 elemento))
    (setq respuesta (nth 2 elemento))
    (setq valor (nth 3 elemento))
    ;; Poner el contador de la escala a 0
    (if (null (lax-plist-get minimult-resultados escala))
       (setq minimult-resultados (lax-plist-put minimult-resultados escala 0)))
    ;; Sumar el VALOR a los resultados para ESCALA si procede
    (if (equal (substring minimult-respuestas (1- pregunta) pregunta) respuesta)
       (lax-plist-put minimult-resultados escala
           (+ (lax-plist-get minimult-resultados escala) valor)))
    ;; Avanzar a la siguiente entrada de la plantilla
    (setq contador (1+ contador)))
  ...)

Básicamente el bucle while recorre toda la plantilla, comprueba si hay un valor para la escala en los resultados, comprueba si la respuesta del sujeto en la posición que dice esa entrada de la plantilla coincide con la plantilla y si es así, le suma el valor que dice la plantilla a la escala. Todo lo guarda en una lista de propiedades (plist) que se llama minimult-resultados.

Esta parte del código creo que fácilmente entendible por cualquiera que lo lea y no le daré más vueltas.

Convertir puntuaciones directas

Uno de los problemas del MiniMult resulta de resumir el número de preguntas que hay para cada escala. Eso hace que haya que convertir las puntuaciones directas obtenidas en él, a las puntuaciones directas que se hubieran obtenido en el MMPI-2 para poder continuar con la corrección normal del test.

Cuando se corrige el MiniMult a mano, encontramos una tabla de conversión entre puntuaciones. En lugar de utilizar esa tabla me he decidido por hacer un cálculo. Sabiendo el máximo de puntos que se pueden obtener en la escala reducida y en la escala completa se aplica una sencilla fórmula:

Nf = Ntmax × ( Nd / Ndmax )

donde la Nf es la nota estimada en el test, Ntmax es la máxima nota que se podría obtener en el test, Nd es la puntuación obtenida por el sujeto y Ndmax la máxima que podría obtener en el MiniMult. Los valores sobre los que se ha calculado la prueba (creo que ya la he puesto otra vez por aquí) son los siguientes:

Escala Ntmax Ndmax
L 15 4
F 60 13
K 30 16
Hs 32 12
D 57 19
Hy 60 22
Pd 50 18
Pa 40 14
Pt 48 15
Sc 78 17
Ma 46 11
Si 67 9

Esta parte del código la he dividido en dos partes, una que aplica la fórmula y otra que la va llamando para convertir cada puntuación.

(defun minimult-convertir-MMPI (puntos mmpi minimult)
  "Convierte PUNTOS a puntuaciones directas del MMPI-2."
  (fround (* mmpi (/ puntos minimult))))

(defun minimult-convertir-directas ()
  "Convierte las puntuaciones directas de las escalas."
    (lax-plist-put minimult-resultados "L"
           (minimult-convertir-MMPI (lax-plist-get minimult-resultados "L")
                               15.0 4.0))
    ...
           (minimult-convertir-MMPI (lax-plist-get minimult-resultados "Si")
                               67.0 9.0)))

Para convertir las puntuaciones directas hago una llamada para cada escala. Me hubiera gustado hacer algo más presentable, como guardar las puntuaciones en un diccionario pero me he encontrado con algunos problemas y bugs por mis actuales carencias con Lisp. Al final opté por lo más fácil, pero lo menos flexible y lo más chapucero.

Como se puede apreciar las llamadas las realizo añadiendo a los valores una parte decimal. Lisp tiene por costumbre mantener el tipo de las variables cuando realiza cálculos. Si le pasas a la división enteros sólo devolverá la parte entera de la división, pero en este caso necesitamos que realice los cálculos con decimales y luego redondee a entero con fround.

Ajustar las escalas con K

Una vez obtenidas las puntuaciones directas estimadas se realiza el ajuste K de las puntuaciones de las escalas que lo necesitan, que son las siguientes:

Hs → 0.5 K
Pd → 0.4 K
Pt → 1 K
Sc → 1 K

El código queda así:

(defun minimult-corregir-K (factor-K)
  "Añade factor de corrección K a las escalas que lo necesitan."
  (lax-plist-put minimult-resultados "Hs"
         (fround (+ (lax-plist-get minimult-resultados "Hs")
                (* 0.5 factor-K))))
  (lax-plist-put minimult-resultados "Pd"
         (fround (+ (lax-plist-get minimult-resultados "Pd")
                (* 0.4 factor-K))))
  (lax-plist-put minimult-resultados "Pt"
         (fround (+ (lax-plist-get minimult-resultados "Pt")
                 factor-K)))
  (lax-plist-put minimult-resultados "Sc"
         (fround (+ (lax-plist-get minimult-resultados "Sc")
                 factor-K))))

La llamada a corregir las puntuaciones directas con el factor K se realiza de la siguiente forma:

(minimult-corregir-K (lax-plist-get minimult-resultados "K"))

Y con estos pasos ya hemos obtenido las puntuaciones directas estimadas en el test.

Calcular las puntuaciones T

Al final hay que calcular las puntuaciones T, pero teniendo en cuenta que las puntuaciones se agrupan de forma distinta para hombres y mujeres. Para ello he hecho dos funciones distintas, aunque originalmente estaba pensado una sola que tomara los valores correspondientes de una variable u otra teniendo en cuenta el sexo.

El código es el siguiente:

(if (equal (org-entry-get (point) "Sexo" t) "Hombre")
    (minimult-calcular-T-hombre)
  (minimult-calcular-T-mujer))

Igual que hice para convertir las puntuaciones de MiniMult se aplica la fórmula

Nt = Ntmin + (Ntmax - Ntmin) × (Nd - Ndmin) / (Ndmax - Ndmin)

Donde Nt son las puntuaciones T y las Nd son las puntuaciones directas. El cálculo se realiza en la función siguiente:

(defun minimult-calcular-T (puntos max-t min-t max-d min-d)
  "Convierte PUNTOS a puntuaciones T."
  (fround (+ min-t (* (- max-t min-t) (/ (- puntos min-d) (- max-d min-d))))))

y luego se le llama desde otras funciones para convertir las puntuaciones de mujeres y hombres similares a como hice la función minimult-convertir-directas, con los valores que se explican en el siguiente punto.

Tablas, sexo y rock'and roll

Cuando corriges a mano el MMPI manejas muchas tablas que convierten las puntuaciones. Tablas de corrección de K, tablas de conversión de puntuaciones directas → T para hombres y mujeres.

Observando esas tablas se observa que la distribución de las puntuaciones es homogénea. Sin embargo, están limitadas y en el manual de corrección sólo figuran las puntuaciones entre 30T y 120T y no siempre la puntuación mínima es 0. Y tampoco siempre la puntuación máxima que se puede obtener en la escala está por debajo de 120. Por eso, me decanté en calcular la puntuación en lugar de crear unas larguísimas tablas.

La primera fórmula que he puesto en este post es un caso particular de la fórmula que he mostrado en el punto anterior. El caso particular de que las dos puntuaciones mínimas son 0.

Mirando las puntuaciones en las tablas del manual del MMPI-2, los valores serían los siguientes:

Para varones:

Escala máx.T min.T máx.D min.D
L 92 30 15 0
F 120 36 47 0
K 83 31 30 6
Hs 102 31 38 6
D 120 30 57 12
Hy 119 31 56 13
Pd 120 31 57 15
Pa 118 30 35 4
Pt 120 30 71 18
Sc 119 30 84 16
Ma 118 31 49 12
Si 98 30 69 10

Para mujeres:

Escala máx.T min.T máx.D min.D
L 94 30 15 0
F 119 35 38 0
K 86 31 30 6
Hs 100 30 38 7
D 113 30 57 14
Hy 119 31 57 14
Pd 120 31 56 15
Pa 119 32 36 5
Pt 119 31 74 20
Sc 120 30 83 17
Ma 120 31 50 11
Si 97 30 69 11

Si comparamos las dos tablas vemos que las puntuaciones son muy parecidas pero no iguales.

Al final, y como todas las puntuaciones que se manejan son siempre en forma de enteros, aunque todos los cálculos se han realizado en con decimales, se han ido redondeando al entero más cercano siempre y al final al convertirlas en cadena para guardarlas en la lista de propiedades del org se utiliza la siguiente instrucción:

(defun minimult-guardar-resultados (lista-escalas)
  "Guarda la LISTA-ESCALAS por pares (propiedad valor)."
  (when lista-escalas
    (org-entry-put (point) (pop lista-escalas) (format " %d" (pop lista-escalas)))
    (minimult-guardar-resultados lista-escalas)))

En entrada org se guarda la escala y con una cadena de formato " %d" se convierte la puntuación a cadena truncando la parte decimal (que en todos los casos, dado el redondeo que se ha venido haciendo, es .0).

Cosas mejorables y dificultades

No soy nada productivo con el código en elisp. Aún no domino el lenguaje, ni sus usos y costumbres. Su forma de guardar variables temporales, el que muchas veces se me olvida el quote al definir listas y que los cálculos matemáticos utilizan notación prefija me dificultan muchas veces avanzar. Cometo muchos errores aún y todavía cuando salta el error y me muestra el depurador la pila de llamadas, me cuesta un momento comprender cuál es el error y dónde debo buscarlo.

Cuando me encuentre más suelto con el lenguaje y el entorno, quizá haría las cosas de otras formas más elegantes.

Por algún sitio he leído eso de que Lisp es un lenguaje de programación programable y que puede simular ser otra cosa. En este caso con Emacs estaría simulando que es un editor cuya interface, datos y acciones se enfocan en el texto. Algunos dirían algo parecido sobre AutoCAD y el dibujo técnico.

Llegados a este punto vamos a ver cómo avanza el proyecto: ¿seré capaz de hacer que Emacs, que básicamente es texto, dibuje el perfil gráfico del test? ... Alguna idea llevo de cómo se podría hacer y voy a ver si consigo hacerlo. A pesar de todas mis dificultades y carencias, cada vez me encuentro más cómodo con el lenguaje y el entorno.

Categoría: emacs programación tests

Comentarios

Debido a algunos ataques mailintencionados a través de la herramienta de comentarios, he decidido no proporcionar dicha opción en el Blog. Si alguien quiere comentar algo, me puede encontrar en esta cuenta de Mastodon, también en esta otra cuenta de Mastodon y en Diaspora con el nick de Notxor.

Si usas habitualmente XMPP (si no, te recomiendo que lo hagas), puedes encontrar también un pequeño grupo en el siguiente enlace: notxor-tiene-un-blog@salas.suchat.org

Disculpen las molestias.