Mostrando entradas con la etiqueta Evaluación. Mostrar todas las entradas
Mostrando entradas con la etiqueta Evaluación. Mostrar todas las entradas

martes, 17 de marzo de 2026

Evaluación. Memoria

ENFEN. Fluidez verbal (VII)

El análisis de la entrada anterior permite que nos podamos replantear ahora la propuesta original de automatización de ENFEN-Fluidez.

Empezaré diciendo que el enfoque clínico es perfectamente válido en el ámbito profesional que le es propio, pero no en el educativo. Esto obliga a aclarar por qué utilizar herramientas de evaluación clínica como recursos de evaluación educativa, en qué circunstancias es admisible y cuales son los condicionantes que ese uso conlleva, si es que conlleva alguno.

La mayoría de los test clínicos (y la mayoría de los test empleados por los SEO lo son) están diseñados para la evaluación individual, lo que, en mi opinión, supone un hándicap como punto de partida, ya que este tipo de evaluación debe ser considerada una medida extraordinaria para nuestra intervención y sólo debemos optar por ella excepcionalmente y de forma justificada. Esto deriva del carácter contextual que debe tener toda intervención educativa para ser eficaz y justa; esto incluye nuestra intervención, sea ésta cual sea). También deriva de la constatación de los efectos negativos que para la inclusión tienen cierto tipo de intervenciones, una de ellas las actuaciones de evaluación individualizada por constituir una barrera a la presencia, con todo lo que de ella se deriva. Además hay que decir que la mayor parte de lo que pudiéramos obtener mediante la evaluación individualizada, lo podemos obtener mediante otras forma de trabajo, incluyendo la evaluación grupal contextualizada. La mayor parte, pero no todo.

Además en determinadas circunstancias y por razones de peso, la evaluación individualizada es necesaria, insustituible y está justificada, entre ellas, cuando...

  • ... no existen procedimientos alternativos que permitan obtener la misma información sin que sea necesario recurrir a ese tipo de actuación o los disponibles son muy costosos o complejos.
  • ... el proceso de evaluación está definido como constatación de hipótesis. Esto excluye la evaluación que se desarrolla en formatos descriptivos.
  • ... de los resultados que podemos obtener de la aplicación de determinadas pruebas que conllevan evaluación individualizada se derivan implicaciones relevantes para la intervención.

Además de estar justificada en esos casos la evaluación individualizada y la aplicación de pruebas originalmente clínicas, muchos de ellas lo son en función de para qué se emplean y cómo se analizan, pero permiten otros planteamiento y otros análisis compatible con los objetivos propios del enfoque educativo: facilitar el análisis causal de las dificultades de aprendizaje. Muchos de esos test se convierten en herramientas útiles para la evaluación educativa al ser reformulados y/o reinterpretados dentro de la transformación que de ellos hace en función de objetivos educativos.

En lo que sigue de entrada trataré de ejemplificar lo anterior en el desarrollo de la propuesta alternativa de automatización de ENFEN-Fluidez.

Dado que justificar el primero no ofrece mayor dificultad (hay pocos test que sean tan económicos y fáciles de aplicar y analizar como F1 y F2) y a la vez,en abstaracto, todas las del mundo; trataré de aterrizar empezando por replanear el enfoque de la elección de la prueba de forma coherente con el segundo de los criterios indicados antes: plantear la evaluación como trabajo en relación a una hipótesis como base para dar razón de ser al uso de ENFEN-Fluidez.

Aquí se produce un cambio radical de enfoque respecto a cómo se presupuso que sería el uso del test en el diseño del DocAp original: en ese caso el contexto venía definido en términos de procesamiento hacia adelante, convirtiendo ENFEN-Fluidez en un medio para objetivar la presencia de un déficit o, en su caso, constatar la normalidad de los resultados como ausencia del mismo. Ahora se plantea una forma de procesamiento hacia atrás en la que primero presumimos o constatamos (no entraremos en el cómo ni mediante qué medios) la presencia en el alumno de determinada problemática para la que ENFEN-Fluidez asumimos que aporta información relevante para la intervención educativa: para la categorización en términos de NEAE y/o para la identificación de necesidades educativas y/o para definición de estrategias de intervención educativa.

Me voy a tomar la libertad de no tratar aquí cómo constatamos ese déficit, ya que realmente no es un tema que sea necesario tratar en estos momentos. Tampoco lo voy a tratar las razones que avalan la idoneidad de ENFEN-Fluidez como recurso para la evaluación educativa de ciertas problemáticas, aunque realmente sí sería exigible una explicación detallada al respecto, pero en parte esta explicación se ha ido desgranando en entradas anteriores y conlleva más tiempo del que ahora dispongo y estoy dispuesto a dedicar. Diré que no carece de respaldo teórico la asociación de las dos dificultades que planteo con ENFEN-Fluidez, aunque otra cosa es que sea la única o la mejor opción.

El procedimiento de análisis de los datos se basa en el DocAp y lo desarrolla, aunque modificando alguno de sus planteamientos yajustándolo a los resultados obtenidos en nuestra pequeña muestra. Esto tiene importancia por dos razones:

  • Porque estoy asumiendo que es necesario constatar práctica y empíricamente la utilidad de un determinado recurso en función de objetivos propios y de la población y el contexto en que interviene el SEO.
  • Y porque se resalta la importancia de realizar este tipo de estudios como parte de las actuaciones de los SEO para la mejorar de su propia práctica.

Llegados a este punto estamos en condiciones de iniciar la construcción de nuestra propuesta de automatización, la cual consta de varias fases. Las primeras consisten en la recogida y el análisis de datos, las segundas tienen que ver con la elaboración del texto que sintetiza ese análisis y las terceras en el almacenamiento y devolución de información al usuario.

El primer bloque se incia (fase I) con la recopilación de datos de identificación de alumno: nombre, apellidos y edad como mínimos, aunque podemos ampliar el repertorio a centro escolar y curso o nivel. En realidad el único que realmente importa es el dato edad, ya que de él dependen procesos subsiguientes. Esto es importante para una cuestión que aquí y ahora no nos importa realmente: el tratamiento confidencial de los datos. dado que estamos trabajando en local, esa es una cuestión secundaria, cuyo tratamiento depende más de protocolos de custodia de los documentos que de con qué tecnologías se gestionan; pero en otros casos será una cuestión fundamental. De momento lo dejamos dicho.

El código de consta esta fase es el siguiente:


   
# Cuerpo principal o de ejecución

if __name__ == "__main__":

#Fase 1. Recoida de datos personales ------------------------------------------------------------
    
    print("--- DATOS PERSONALES DEL ALUMNO---")
    
# Solicitamos los datos al usuario
    nombre = input("Nombre: ")
    apellidos = input("Apellidos: ") 
    try: 	# Convertimos la edad a entero (int) para operar con el dato
    edad = int(input("Edad (sólo años): "))
    except ValueError:
        print("Error: Por favor, introduce un número válido para la edad (6 a 12 años).")
    centro_escolar = input("Centro escolar: ")
    curso = input("Curso: ")
	

Hasta aquí nada que decir, salvo la estructura try...except, que sirve para evitar algún error en un dato fundamental. Su conversión de string a integar, mediante la función int() se explica en el comentario.

La fase II consiste en identificar el motivo de uso de ENFEN-Fluidez, cuestión muy importante en esta propuesta y que conlleva cierta complejidad. Por ello he decidido desarrollarla mediante una función (def cod_hipotesis()) que recibe edad como parámetro y devuelve un código que identifica el tipo de hipótesis con la que vamos a trabajar en las fases siguientes.



def cod_hipotesis(edad):

    """
    Analiza la información disponible para plantear hipótesis para el análisis posterior y devuelve un código.
    Parámetro: edad (int)
    Retorna (return): string (Código de hipótesis de trabajo)
    """
    codigo = ""
    
    print("\n--- SEGUNDA FASE: ANÁLISIS DE INTERVENCIÓN ---")
    print("0. Ninguna de las siguientes")
    print("1. Hipótesis de TDAH")
    print("2. Dificultades de aprendizaje (Lectura)")
    opcion = input("Elija una opción (0 - 1 - 2): ")

#Lógica para hipótesis

    if opcion == "0":
        codigo = "0"
        return codigo
    else:
# --- Lógica para Hipótesis 1: TDAH ---
        if opcion == "1":
            codigo = "1"
            tiene_diag = input("¿Consta informe de especialista con diagnóstico o impresión diagnóstica de TDA-H? (s/n): ").lower() == 's'
            if tiene_diag:
                codigo += "A"  # Diagnóstico clínico informado por neuropediatra
            else:
                codigo += "B"  # Sintomatología observada en contexto familiar y/o escolar
                indicios_padres = input("¿Informan los padres de indicios compatibles con dificultades de atención y/o de hiperactividad  ? (s/n): ").lower() == 's'
                indicios_profe = input("¿Informa el profesorado de evidencias de dificultades de atención, hiperactividad o auto-regulación? (s/n): ").lower() == 's'
            
                if indicios_padres and indicios_profe:
                    codigo += "ab"
                elif indicios_padres:
                    codigo += "a"
                elif indicios_profe:
                    codigo += "b"
  
# --- Lógica para Hipótesis 2: Lectura ---
        elif opcion == "2":
            codigo = "2"
            if edad <= 7:
                codigo += "A"  # Para menores o iguales a 7 años
            else:
                codigo += "B"  # Para mayores de 7 años
            
        return codigo
  

Este código identifica la causa posible de las necesidades educativas en base a la (supuesta) información recogida en la anámnesis y el subtipo de la misma, en función de la fuente o de la edad. Posteriormente será utilizada para analizar los resultados en función del contexto que esa información ayuda a conformar.

La fase III consiste en recoger la puntuación que obtiene el alumno en las dos pruebas (F1 y F2). Aunque caben diferentes opciones, he decidido que sea recogida mediante input() desde el script principal, igual que los datos de identificación. De este modo forman parte de dicho script y pueden ser usados en la fase siguiente y en otras posteriores sin mayor dificultad.



#Fase 3. Obtención de la puntuación directa de F1 y F2

    print("\n--- RESULTADOS DE LA APLICACIÓN DE ENFEN-FLUIDEZ---")
    f1_pd = int(input(f"Resultado obtenido por {nombre} en F1: "))
    f2_pd = int(input(f"Resultado obtenido por {nombre} en F2: "))


La fase IV consiste en obtener la puntuación z derivada de la puntuación directa anterior. Para ello usamos una función (def calcular_z()), que contiene un diccionario de diccionarios con los estadísticos necesarios y recibe tres parámetros; la edad, el identificador de la prueba (factor) y la puntuación directa (puntuacion_directa).



def calcular_z(edad, factor, puntuacion_directa):

    baremos = {                                        # Diccionario con los estadísticos F1 y F2
        6:  {'f1': (5.28, 2.65),  'f2': (10.26, 3.81)},
        7:  {'f1': (6.65, 2.68),  'f2': (11.18, 3.34)},
        8:  {'f1': (8.66, 2.85),  'f2': (13.57, 3.95)},
        9:  {'f1': (9.25, 3.02),  'f2': (14.08, 3.87)},
        10: {'f1': (11.16, 3.09), 'f2': (16.79, 4.49)},
        11: {'f1': (11.73, 3.35), 'f2': (17.88, 4.72)},
        12: {'f1': (12.04, 3.19), 'f2': (17.81, 4.11)}
    }

    media, desviacion = baremos[edad][factor]       # Obtención de estadisticos en función de edad y prueba

    z = (puntuacion_directa - media) / desviacion    # Cálculo de Puntuación Z
    
    return round(z, 2)
    

´Primero obtenemos los estadísticos del diccionario mediante media, desviacion = baremos[edad][factor] de forma directa. Este procedimiento es adecuado en este caso porque controlamos directamente los datos de edad y factor y tenemos la seguridad de que no se va a producir error en el acceso a los datos. En otro caso sería más adecuado usar el método get(), como en el ejemplo siguiente, por ser más robusto y seguro:



datos_factor = baremos.get(edad, {}).get(factor)

if datos_factor:
    media, desviacion = datos_factor
else:
    print("Error: Edad o factor no encontrados")


Después se realiza el cálculo (z = (puntuacion_directa-media)/desviacion), que pasa (return round(z, 2)) a la variable del script desde la que se llama a la función ( f1_z = calcular_z (edad,"f1",f1_pd)).

La fase V sintentiza y codifica los resultados obtenidos, siendo la última del primer bloque. Esta codificación se ejecuta tambíén mediante una función y sirve para obtener una síntesis de datos que usaremos para construmir la base de datos de resultados sobre un documento csv que posteriormente servirá para el análisis de datos soporte de la invertigación-acción relativa la uso y la funcionalidad de ENFEN-Fluidez como herramienta de intervención del SEO.

Aunque no es estrictamente necesaria (y menos aun incorporarla a la base de datos), facilita la tarea poserior de análisis de datos, tanto grupales como individuales, así que he decidido implemantarla como parte del script.

Las categorías obedecen a criterios de utilidad descriptivo-analítica en función de los objetivos y el contexto en que aplicamos el recurso. Esto quiere decir que nos interesan determinados resultados en cuanto son significativos para establecer necesidades educativas en función del contexto hipotético en que nos movemos. Por ejemplo, si estamos trabajando con la hipótesis de incidencia de TDAH, nos interesa sólo si el sujeto obtiene puntuaciones inferiores a promedio, pero tiene importancia que dichas puntuaciones se den en ambos test o sólo en F1. Esto quiere decir que nos interesa saber si los valores z son iguales o inferiores a -1 Dt y si esto se produce en F1 y en F2 o sólo en F1 (sólo en F2 es irrelevante para el contexto TDAH). Esto es debido a que sólo déficit en F1 implica menor nivel de severidad que si la dificultad se observa también en F2.

En el segundo contexto (dificultad lectora) es de esperar discrepancia y F1 débil. Cualquier otro resultado es no confirmatorio, pero no determinante, por lo que resulta irrelevante para nuestros objetivos: no nos permite tomar decisiones de evaluación ni de intervención, que el lo mismo que sucede para un resultado dentro de normalidad (o superior, ya que unificamos ambos como N (normal) tanto en este contexto como en el de TDAH.

Esta es una forma de entender los resultados necesariamente restrictiva. No es la única y posiblemente tampoco la más correcta o la que mejores análisis produzca, pero sí es la que podemos usar en función del modo en que trabajamos con los datos: sólo determinados resultados (confirmatorios) son relevantes para nuestro análisis, en cuanto que están aceptados o confirmados por la teoría y la investigación. Si en su momento, de estas prácticas derivan nuevos soportes teóricos que permiten establecer otras hipótesis, determinados resultados pasarían a ser considerados relevantes.



def resulta_categ(f1_z, f2_z):
    
    # 1. Identificamos el grupo de cada factor True si es Bajo (B), False si es Normal (N)
    es_f1_bajo = f1_z <= -1
    es_f2_bajo = f2_z <= -1

    # 2. Lógica de la categorización
    
    if es_f1_bajo and es_f2_bajo:  				# Caso: Ambos Bajos
        return "EB"
    
    elif not es_f1_bajo and not es_f2_bajo:     # Caso: Ambos Normales
        return "EN"
    
    else:										# Caso: Desequilibrio (uno B y otro N)
        if es_f1_bajo:
            return "DF1d"
        else:
            return "DF2d"


Lo que estamos haciendo con esta función es categorizar los resultados dependiendo del nivel de desempeño, el cual toma como referencia el valor -1 Dt (esto permite que seas tú quien determine la referecnia cuantitativa que consideres más adecuada, aquí o en cualquier otro caso), derivando las dos primeras categorías de la pertenencia de ambos valores al mismo grupo (EB y EN) y las dos últimas por la discrepancia (DF1d, DF2d).

Una vez finalizada esta fase, entramos en el tercer bloque que afronta la recopilación de datos en un archivo csv y su publicación como informe individualizado.

Dentro de este bloque, la recopilación de resultados en un archivo csv constituye la fase VI y se concreta como función que recibe como parámetro la colección de datos recopilada en el script principal como diccionario (datos_archivar):


  datos_archivar = {
        'nombre': nombre,
        'apellidos': apellidos,
        'edad': edad,
        'centro': centro,
        'curso': curso,
        'codigo_h': codigo_h,
        'f1_pd': f1_pd,
        'f1_z': f1_z,
        'f2_pd': f2_pd,
        'f2_z': f2_z,
        'cat_z': cat_z
    }

Este es el parámetro datos que recibe la función def archivar_en_csv() mediante la cual se crear el archivo...



def archivar_en_csv(datos):
  
    # 1. Definir el nombre del archivo y la ruta (mismo directorio que el script)
    nombre_archivo = "bd_enfen_fluidez.csv"
    ruta_directorio = os.path.dirname(os.path.abspath(__file__))
    ruta_completa = os.path.join(ruta_directorio, nombre_archivo)
    
    # 2. Definir los encabezados del CSV
    encabezados = [
        'nombre',
        'apellidos',
        'edad',
        'centro',
        'curso',
        'codigo_h',
        'f1_pd',
        'f1_z',
        'f2_pd',
        'f2_z',
        'cat_z'
    ]

    # 3. Comprobar si el archivo ya existe para saber si escribir encabezados
    archivo_existe = os.path.isfile(ruta_completa)
    
    try:
        # Abrimos en modo 'a' (append/añadir) y newline='' para evitar líneas vacías
        with open(ruta_completa, mode='a', newline='', encoding='utf-8') as archivo:
            escritor = csv.DictWriter(archivo, fieldnames=encabezados)
            
            # Si el archivo es nuevo, escribimos la cabecera
            if not archivo_existe:
                escritor.writeheader()
            
            # Escribimos la fila con los resultados
            escritor.writerow(datos)
            
        print(f"✅ Datos archivados correctamente en: {nombre_archivo}")
        
    except Exception as e:
        print(f"❌ Error al guardar en CSV: {e}")

... y en la que, como contenidos fundamentales, primero se crea el encabezado del archivo csv mediante la lista encabezados[] y después se escribe el contenido mediante escritor.writerow(datos). En este documento se recopilarán todos los resultados de la aplicación del ENFEN-Fluidez, con idea de que sirva para realizar los estudios que se consideren convenientes mediante procedimientos de acceso al contenido de archivos de datos estructurados (por ejemplo).

Con la fase VII concluye este proyecto. En ella se construye el informe individualizado pero es suficientemente compleja como para que sea necesario sudividirla en varias partes. Esto facilita que se formule como función (principal) a la que se asocian varias funciones secundarias.

La función def generar_info (): también recibe como parámetro el contenido del conjunto datos pero los maneja de forma más compleja que la anterior, pudiendo diferenciarse varias partes en su desarrollo. Unas son asumidas directamente por la función y otras se derivan a funciones complementarias o secundarias.

En la primera de estas partes, además de crear el documento (doc = Document()) como archivo .docx (lo que supone cargar la biblioteca docx), creamos el título y copiamos los datos de identificación (por ejemplo: p.add_run(f"{datos['nombre']} {datos['apellidos']}\n"))

La segunda parte también es asumida por la función principal y consiste en explicar el concepto de Fluidez verbal, informar sobre ENFEN-Fluidez y sobre la utilidad de este (sub)test para la evaluación clínica y para la evaluación y la intervención educativa. Todo ello se realiza mediante un conjunto de instrucciones como la siguiente: p1 = doc.add_paragraph(), que contienen dentro del paréntesis el texto que deseamos sea escrito en el documento .docx.

La tercera parte del desarrollo del informe es responsabilidad de una función secundaria justifica_hipotesis (): que recibe como parámetro codigo_h desde la llamada a la subfunción que realizamos desde la función principal (parrafo_hipotesis = justifica_hipotesis(datos['codigo_h'])).



def justifica_hipotesis (codigo_h):

    # Caso para TDAH
    if codigo_h.startswith("1"):
        base = "La evaluación se fundamenta en la sospecha clínica de TDAH. "
        if "A" in codigo_h:
            detalle = "Al existir un diagnóstico previo de especialista, esta prueba sirve para cuantificar el impacto actual en las funciones ejecutivas."
        else:
            detalle = "Dada la sintomatología observada en casa y/o el colegio, se requiere objetivar la eficiencia del control atencional e inhibitorio."
        return base + detalle

    # Caso para Dificultades de Aprendizaje (Lectura)
    elif codigo_h.startswith("2"):
        base = "El motivo de evaluación son las dificultades en el proceso lector. "
        if "A" in codigo_h:
            detalle = "En edades tempranas (≤7 años), la fluidez verbal es un indicador crítico de la madurez léxica necesaria para la alfabetización."
        else:
            detalle = "En alumnos mayores de 7 años, se busca evaluar la automatización del acceso al léxico, clave para la comprensión lectora."
        return base + detalle

    return "Evaluación de cribado neuropsicológico general."
    

Esta función secundaria genera un texto específico basado en el código de hipótesis (pasado por parámetro) y en élla se diferencian las dos opciones que derivan de las dos categorías hipotéticas: TDAH o dificultades lectoras. Primero se extrae el primer elemento del código (v.g. if codigo_h.startswith("1"): y seguidamente el resto del contenido de dicho código. En función de ambos se va generando un texto u otro, que será lo que retorne la función a la principal (return base + detalle).

Se debe aclarar en este punto que la forma en que se concretan las hipótesis de trabajo no sólo son únicamente hipotéticas, además sólo lo son en el contexto previo de identificación de una determinada categoría de dificultades preeminentes derivadas de la anámnesis. Sin esta referencia carecen del contexto necesario para ser relevantes en el proceso de evaluación.

Una vez resuelta esta parte del informe, la que sigue se planea como parte de la función principal y se concreta como tabla que contiene los datos de ejecución de F1 y F2, incluyendo la puntuación directa (PD) y la puntuación típica calculada (Pz). En base a ella y a la codificación resultante de esos datos se planteará la parte final de esta función, la cual, dada su complejidad, se traslada a dos funciones secundarias que reciben (ambas) los mismos datos como parámetros ((codigo_h, cat_z)).

La primera función secundaria (analizar_resultados()) se encarga de realizar un breve análisis cualitativo de los resultados cuantitativos tomando como referencia la hipótesis de trabajo.



def analizar_resultados(codigo_h, cat_z):
  
    es_tdah = codigo_h.startswith("1")
    es_lectura = codigo_h.startswith("2")
    
# --- Casos para HIPÓTESIS TDAH ---
    if es_tdah:
        if cat_z == "EN":
            return "Los procesos de recuperación léxica y control inhibitorio evaluados se sitúan en niveles de normalidad. Es posible que ENFEN-Fluidez no permita, en este caso, objetivar  la incidencia del TDAH en los procesos requeridos en tareas de fluidez verbal."
        elif cat_z == "EB":
            return "Se observa un déficit global en fluidez que, en el marco del TDAH, sugiere dificultades importantes en la memoria de trabajo y en la velocidad de procesamiento."
        elif cat_z == "DF1d":
            return "Al ser F1 un marcador primario de TDAH por requerir mayor control inhibitorio y una búsqueda no rutinaria, esta disociación entre F1 y F2  se puede considerar compatible con TDAH, pudiendo interpretarse como indicador de un menor grado de severidad en términos de incidencia del trastorno en el procesamiento cognitivo requerido en tareas de Fluidez por comparación con resultados inferiores a promedio en F1 y F2."
        else: # Para DF2d
            return "Esta disociación es extremadamente infrecuente y sugiere dificultades de monitorización de la respuesta por inatención al resultar la tarea supuestamente poco relevante o novedosa."

# --- Casos para HIPÓTESIS LECTURA ---
    if es_lectura:
        if cat_z == "EN":
            return "Atendiendo a los resultados observados, la madurez léxica y el acceso al vocabulario se sitúan en niveles acordes a la edad cronológica del niño o niña. En este caso, las tareas de fluidez verbal posiblemente no permitan observar las causas de las dificutlades lectoras que presenta el alumno según los datos que constan en la anámnesis realidad."
        elif cat_z == "EB":
            return "El bajo rendimiento en ambas tareas de fluidez verbal indica una pobreza en el almacén léxico o una lentitud severa en la recuperación, lo que puede estar incidiendo negativamente en la decodificación y comprensión lectora."
        elif cat_z == "DF1d":
            return "El perfil sugiere que el acceso al léxico está comprometido en la ruta fonológica, lo que justifica la falta de automatización en la decodificación lectora e inciden negativamente en la fluidez."
        else: # Para DF2d
            return "El perfil sugiere que el acceso al léxico está comprometido en la ruta semántica, posiblemente por déficit general en el desarrollo del lenguaje derivado de distintas causas. No obstante esta manifestación de déficit es sumamente infrecuente, por lo que se debe interpretar con cautela."

    return "Perfil de cribado general sin hallazgos específicos vinculados a una hipótesis previa."


Como puedes ver no es una función demasiado compleja en términos de algoritmo, pero sí en cuanto al contenido. El que aquí se propone es es, una primera propuesta, que deberá ser revisado en función de los resultados del uso del test y que desde ya tú puedes adaptar en función de tus preferencias y conocimientos. Esto es totalmente coherente con el planteamiento de base: paradigma IA modelo experto. Y el experto eres tú.

La segunda función secundaria también ahonda en ese mismo planteamiento en dos sentidos: el mismo que en la anterior (tú decides el contenido) y como usuario del script: en este caso se proponen una colección de opciones de evaluación y de intervención, y es el OE quie selecciona aquellas que considera relevantes para el caso.



def propuestas (codigo_h, cat_z):
   
    opciones_validadas = {"evaluacion": [], "intervencion": []}
    
    # 1. Selección estricta del banco de datos según hipótesis
    if codigo_h.startswith("1"):  # MARCO TDAH
        banco_ev = [
            "Aplicar pruebas de atención sostenida y selectiva (ej. CPT, d2).",
            "Completar escalas de conducta para observación de impulsividad en aula.",
            "Realizar observación estructurada de la conducta en tareas de mesa."
        ]
        banco_int = [
            "Entrenamiento en autoinstrucciones para tareas de producción verbal.",
            "Uso de organizadores gráficos y tiempos de descanso tras tareas de carga atencional.",
            "Adaptación de materiales: fragmentar tareas largas en pasos cortos."
        ]
    elif codigo_h.startswith("2"):  # MARCO LECTURA
        banco_ev = [
            "Evaluación de procesos de decodificación y pseudopalabras (PROLEC-R / SE).",
            "Valoración de la velocidad de denominación (RAN/RAS).",
            "Evaluación de la conciencia fonológica y memoria fonológica de trabajo."
        ]
        banco_int = [
            "Refuerzo de la ruta fonológica mediante entrenamiento en conciencia fonémica.",
            "Lecturas repetidas y modelado para mejorar la prosodia y automatización.",
            "Uso de apoyos visuales y diccionarios de imágenes para reforzar el acceso léxico."
        ]
    else:
        # Si no hay hipótesis definida, retornamos listas vacías
        return opciones_validadas

    # 2. Interacción por CMD para validación directa
    
    print(f"\n--- VALIDACIÓN DE PROPUESTAS TECNICAS (Hipótesis: {codigo_h}) ---")
    print("Responda 's' para incluir la propuesta en el informe o cualquier otra tecla para omitirla.")

    print("\n[ BLOQUE: EVALUACIÓN ]")
    for prop in banco_ev:
        confirmar = input(f"¿Validar '{prop}'? (s/n): ").lower()
        if confirmar == 's':
            opciones_validadas["evaluacion"].append(prop)

    print("\n[ BLOQUE: INTERVENCIÓN ]")
    for prop in banco_int:
        confirmar = input(f"¿Validar '{prop}'? (s/n): ").lower()
        if confirmar == 's':
            opciones_validadas["intervencion"].append(prop)

    return opciones_validadas


Por varios motivos, esta función es significativamente más compleja que las anteriores desde diferentes puntos de vista: es evidente que lo es en cuanto al contenido, por lo que en esta propuesta no pretendo haber resuelto el proyecto, quedando pendente un análisis detallado del contenido presente y ausente. La segunda razón es que estas propuestas lo son en función de la hipótesis que deriva de la anámnesis, lo que hace que sean aun más necesaria la revisión que acabo de plantear.

Pero aun hay un tercer motivo de dificultad, en este caso "informática": esta función secundaria devuelve una colección de datos expresada como diccionario, motivo por el que la función primaria debe transformarlos para poder exponerlos como texto en el documento docx



#Acceso a función secundaria 3: propuestas (codigo_h, cat_z)

# 1. Llamada a la función
    dict_propuestas = propuestas(datos['codigo_h'], datos['cat_z'])

# 2. Preparar el texto para el informe. Creamos una lista de frases para luego unirlas
    lineas_informe = []

    doc.add_heading('Propuestas para la evaluación y para la intervención', level=1)
    
    if dict_propuestas["evaluacion"]:
        for item in dict_propuestas["evaluacion"]:
            lineas_informe.append(f"- {item}")
    
    if dict_propuestas["intervencion"]:
        for item in dict_propuestas["intervencion"]:
            lineas_informe.append(f"- {item}")

# 3. Unir todo en un solo string separado por saltos de línea
    texto_final = "\n".join(lineas_informe)

# 4. Añadir al documento de Word
    if texto_final:
        p_just = doc.add_paragraph(texto_final)
        p_just.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY
    else:
        doc.add_paragraph("No se seleccionaron propuestas técnicas.")

Script final Para finalizar esta larga y compleja entrada te dejo a continuación acceso al script completo. Recuerda que deberás importar todas las bibliotecas que se precisan para su funcionamiento en caso de no tenerlas ya descargadas. Puedes identificarlas al inicio del script.


#Bibliotecas

import sys
import csv
import os
from docx import Document
from docx.shared import Pt
from docx.enum.text import WD_ALIGN_PARAGRAPH
from datetime import datetime

#FUNCIONES ========================================================================

#FUNCIÓN Definir hipótesis --------------------------------------------------------

def cod_hipotesis(edad):

    """
    Analiza la hipótesis clínica y devuelve un código identificador.
    Parámetro: edad (int)
    Retorna: string (Código de hipótesis de trabajo)
    """
    codigo = ""
    
    print("\n--- SEGUNDA FASE: ANÁLISIS DE INTERVENCIÓN ---")
    print("0. Ninguna de las siguientes")
    print("1. Hipótesis de TDAH")
    print("2. Dificultades de aprendizaje (Lectura)")
    opcion = input("Elija una opción (0 - 1 - 2): ")

#Lógica para hipótesis

    if opcion == "0":
        codigo = "0"
        return codigo
    else:
# --- Lógica para Hipótesis 1: TDAH ---
        if opcion == "1":
            codigo = "1"
            tiene_diag = input("¿Consta informe de especialista con diagnóstico o impresión diagnóstica de TDA-H? (s/n): ").lower() == 's'
            if tiene_diag:
                codigo += "A"  # Diagnóstico clínico informado por neuropediatra
            else:
                codigo += "B"  # Sintomatología observada en contexto familiar y/o escolar
                indicios_padres = input("¿Informan los padres de indicios compatibles con dificultades de atención y/o de hiperactividad  ? (s/n): ").lower() == 's'
                indicios_profe = input("¿Informa el profesorado de evidencias de dificultades de atención, hiperactividad o auto-regulación? (s/n): ").lower() == 's'
            
                if indicios_padres and indicios_profe:
                    codigo += "ab"
                elif indicios_padres:
                    codigo += "a"
                elif indicios_profe:
                    codigo += "b"
# --- Lógica para Hipótesis 2: Lectura ---
        elif opcion == "2":
            codigo = "2"
            if edad <= 7:
                codigo += "A"  # Para menores o iguales a 7 años
            else:
                codigo += "B"  # Para mayores de 7 años
            
        return codigo

# FUNCIÓN Cálculo de puntuaciones típicas (z) ------------------------------------------------------

def calcular_z(edad, factor, puntuacion_directa):

    baremos = {                                                      # Diccionario con los estadísticos F1 y F2
        6:  {'f1': (5.28, 2.65),  'f2': (10.26, 3.81)},
        7:  {'f1': (6.65, 2.68),  'f2': (11.18, 3.34)},
        8:  {'f1': (8.66, 2.85),  'f2': (13.57, 3.95)},
        9:  {'f1': (9.25, 3.02),  'f2': (14.08, 3.87)},
        10: {'f1': (11.16, 3.09), 'f2': (16.79, 4.49)},
        11: {'f1': (11.73, 3.35), 'f2': (17.88, 4.72)},
        12: {'f1': (12.04, 3.19), 'f2': (17.81, 4.11)}
    }

    media, desviacion = baremos[edad][factor]       # Obtención de estadisticos en función de edad y prueba

    z = (puntuacion_directa - media) / desviacion    # Cálculo de Puntuación Z
    
    return round(z, 2)

# FUNCIÓN Categorización resultados  z ----------------------------------------------

def resulta_categ(f1_z, f2_z):

    """
    Categorizamos el desempeño como EB, EN, DF1d, DF2d.
    """
    # 1. Identificamos el grupo de cada factor True si es Bajo (B), False si es Normal (N)
    es_f1_bajo = f1_z <= -1
    es_f2_bajo = f2_z <= -1

    # 2. Lógica de Categorización Acumulativa
    
    # Caso: Ambos Bajos
    if es_f1_bajo and es_f2_bajo:
        return "EB"
    
    # Caso: Ambos Normales
    elif not es_f1_bajo and not es_f2_bajo:
        return "EN"
    
    # Caso: Desequilibrio (uno B y otro N)
    else:
        if es_f1_bajo:
            return "DF1d"
        else:
            return "DF2d"

#FUNCIONES SECUNDARIAS a generar_info () ---------------------------------------------------------------------------

# FUNCIÓN SECUNDARIA para crear el párrafo justificativo del hipótesis

def justifica_hipotesis (codigo_h):
    """
    Genera un texto específico basado en el código de hipótesis.
    """
    # Caso para TDAH
    if codigo_h.startswith("1"):
        base = "la evaluación se fundamenta en la sospecha clínica de TDAH. "
        if "A" in codigo_h:
            detalle = "Al existir un diagnóstico previo de especialista, esta prueba sirve para cuantificar el impacto actual del TDAH en las funciones ejecutivas."
        else:
            detalle = "Dada la sintomatología observada en casa y/o en el colegio, se requiere objetivar la eficiencia del control atencional e inhibitorio, potencialmente afectado en caso de TDAH."
        return base + detalle

    # Caso para Dificultades de Aprendizaje (Lectura)
    
    elif codigo_h.startswith("2"):
        base = "el motivo de evaluación son las dificultades en el proceso lector. "
        if "A" in codigo_h:
            detalle = "En edades tempranas (≤7 años), la fluidez verbal es un indicador crítico de la madurez léxica necesaria para la alfabetización."
        else:
            detalle = "En alumnos mayores de 7 años, se busca evaluar hasta qué punto la automatización del acceso al léxico, clave para la comprensión lectora, puede verse lastrada por la persistencia de dificultades de decodificación."
        return base + detalle

    return "Evaluación de cribado neuropsicológico general."

# FUNCIÓN SECUNDARIA 2: Análisis cualitativo ligado a la hipótesis

def analizar_resultados(codigo_h, cat_z):
  
    es_tdah = codigo_h.startswith("1")
    es_lectura = codigo_h.startswith("2")
    
    # --- Casos para HIPÓTESIS TDAH ---
    if es_tdah:
        if cat_z == "EN":
            return "Los procesos de recuperación léxica y control inhibitorio evaluados se sitúan en niveles de normalidad. Es posible que ENFEN-Fluidez no permita, en este caso, objetivar  la incidencia del TDAH en los procesos requeridos en tareas de fluidez verbal."
        elif cat_z == "EB":
            return "Se observa un déficit global en fluidez que, en el marco del TDAH, sugiere dificultades importantes en la memoria de trabajo y en la velocidad de procesamiento."
        elif cat_z == "DF1d":
            return "Al ser F1 un marcador primario de TDAH por requerir mayor control inhibitorio y una búsqueda no rutinaria, esta disociación entre F1 y F2  se puede considerar compatible con TDAH, pudiendo interpretarse como indicador de un menor grado de severidad en términos de incidencia del trastorno en el procesamiento cognitivo requerido en tareas de Fluidez por comparación con resultados inferiores a promedio en F1 y F2."
        else: # Para DF2d
            return "Esta disociación es extremadamente infrecuente y sugiere dificultades de monitorización de la respuesta por inatención al resultar la tarea supuestamente poco relevante o novedosa."

    # --- Casos para HIPÓTESIS LECTURA ---
    if es_lectura:
        if cat_z == "EN":
            return "Atendiendo a los resultados observados, la madurez léxica y el acceso al vocabulario se sitúan en niveles acordes a la edad cronológica del niño o niña. En este caso, las tareas de fluidez verbal posiblemente no permitan observar las causas de las dificutlades lectoras que presenta el alumno según los datos que constan en la anámnesis realidad."
        elif cat_z == "EB":
            return "El bajo rendimiento en ambas tareas de fluidez verbal indica una pobreza en el almacén léxico o una lentitud severa en la recuperación, lo que puede estar incidiendo negativamente en la decodificación y comprensión lectora."
        elif cat_z == "DF1d":
            return "El perfil sugiere que el acceso al léxico está comprometido en la ruta fonológica, lo que justifica la falta de automatización en la decodificación lectora e inciden negativamente en la fluidez."
        else: # Para DF2d
            return "El perfil sugiere que el acceso al léxico está comprometido en la ruta semántica, posiblemente por déficit general en el desarrollo del lenguaje derivado de distintas causas. No obstante esta manifestación de déficit es sumamente infrecuente, por lo que se debe interpretar con cautela."

    return "Perfil de cribado general sin hallazgos específicos vinculados a una hipótesis previa."

# FUNCIÓN SECUNDARIA 3: Propuesta de actuaciones para conformidad del orientador

def propuestas (codigo_h, cat_z):
   
    opciones_validadas = {"evaluacion": [], "intervencion": []}
    
    # 1. Selección estricta del banco de datos según hipótesis
    if codigo_h.startswith("1"):  # MARCO TDAH
        banco_ev = [
            "Aplicar pruebas de atención sostenida y selectiva (ej. CPT, d2).",
            "Completar escalas de conducta para observación de impulsividad en aula.",
            "Realizar observación estructurada de la conducta en tareas de mesa."
        ]
        banco_int = [
            "Entrenamiento en autoinstrucciones para tareas de producción verbal.",
            "Uso de organizadores gráficos y tiempos de descanso tras tareas de carga atencional.",
            "Adaptación de materiales: fragmentar tareas largas en pasos cortos."
        ]
    elif codigo_h.startswith("2"):  # MARCO LECTURA
        banco_ev = [
            "Evaluación de procesos de decodificación y pseudopalabras (PROLEC-R / SE).",
            "Valoración de la velocidad de denominación (RAN/RAS).",
            "Evaluación de la conciencia fonológica y memoria fonológica de trabajo."
        ]
        banco_int = [
            "Refuerzo de la ruta fonológica mediante entrenamiento en conciencia fonémica.",
            "Lecturas repetidas y modelado para mejorar la prosodia y automatización.",
            "Uso de apoyos visuales y diccionarios de imágenes para reforzar el acceso léxico."
        ]
    else:
        # Si no hay hipótesis definida, retornamos listas vacías
        return opciones_validadas

    # 2. Interacción por CMD para validación directa
    
    print(f"\n--- VALIDACIÓN DE PROPUESTAS TECNICAS (Hipótesis: {codigo_h}) ---")
    print("Responda 's' para incluir la propuesta en el informe o cualquier otra tecla para omitirla.")

    print("\n[ BLOQUE: EVALUACIÓN ]")
    for prop in banco_ev:
        confirmar = input(f"¿Validar '{prop}'? (s/n): ").lower()
        if confirmar == 's':
            opciones_validadas["evaluacion"].append(prop)

    print("\n[ BLOQUE: INTERVENCIÓN ]")
    for prop in banco_int:
        confirmar = input(f"¿Validar '{prop}'? (s/n): ").lower()
        if confirmar == 's':
            opciones_validadas["intervencion"].append(prop)

    return opciones_validadas

#FUNCIÓN Archivo de datos en csv------------------------------------------------------------

def archivar_en_csv(datos):
  
    # 1. Definir el nombre del archivo y la ruta (mismo directorio que el script)
    nombre_archivo = "bd_enfen_fluidez.csv"
    ruta_directorio = os.path.dirname(os.path.abspath(__file__))
    ruta_completa = os.path.join(ruta_directorio, nombre_archivo)
    
    # 2. Definir los encabezados del CSV
    encabezados = [
        'nombre',
        'apellidos',
        'edad',
        'centro',
        'curso',
        'codigo_h',
        'f1_pd',
        'f1_z',
        'f2_pd',
        'f2_z',
        'cat_z'
    ]
    
    # 3. Comprobar si el archivo ya existe para saber si escribir encabezados
    archivo_existe = os.path.isfile(ruta_completa)
    
    try:
        # Abrimos en modo 'a' (append/añadir) y newline='' para evitar líneas vacías
        with open(ruta_completa, mode='a', newline='', encoding='utf-8') as archivo:
            escritor = csv.DictWriter(archivo, fieldnames=encabezados)
            
            # Si el archivo es nuevo, escribimos la cabecera
            if not archivo_existe:
                escritor.writeheader()
            
            # Escribimos la fila con los resultados
            escritor.writerow(datos)
            
        print(f"✅ Datos archivados correctamente en: {nombre_archivo}")
        
    except Exception as e:
        print(f"❌ Error al guardar en CSV: {e}")


#FUNCIÓN. Escribir informe individualizado ----------------------------------------------------

def generar_info (datos):

# Obtener la fecha actual para el nombre del archivo

    fecha_actual = datetime.now()
    anio = fecha_actual.year
    mes = fecha_actual.strftime('%m') # Formato de dos dígitos (01, 02...)
    
# Construir el nombre del archivo
    primer_nombre = datos['nombre'].split()[0]
    inicial_apellido = datos['apellidos'][0].upper()
    nombre_final = f"{datos['nombre']}{inicial_apellido}_infofluidez{anio}{mes}.docx"

# Gestión del directorio para almacenar los informes
    directorio_destino = "informes"
    if not os.path.exists(directorio_destino):
        os.makedirs(directorio_destino)
    ruta_final = os.path.join(directorio_destino, nombre_final) # Ruta completa
    doc = Document()    # Creación del documento

# Escritura del título
    titulo = doc.add_heading('Informe individualizado de evaluación de la fluidez verbal', 0)
    titulo.alignment = WD_ALIGN_PARAGRAPH.CENTER

# Datos de identificación

    doc.add_heading('Datos de identificación', level=1)
    p = doc.add_paragraph()
    p.add_run(f"Alumno: ").bold = True
    p.add_run(f"{datos['nombre']} {datos['apellidos']}\n")
    p.add_run(f"Curso: ").bold = True
    p.add_run(f"{datos['curso']} - {datos['centro']}\n")
    p.add_run(f"Fecha de emisión: ").bold = True
    p.add_run(f"{fecha_actual.strftime('%d/%m/%Y')}")

# Escritura de párrafo descriptivo ENFEN-Fluidez

    doc.add_heading('ENFEN-Fluidez. Descripción', level=1)

# Primer párrafo: Definición de fluidez verbal

    p1 = doc.add_paragraph(
    "La fluidez verbal es una tarea de producción del lenguaje que requiere el recurso a mecanismos de "
    "acceso al léxico para evocar rápidamente los conceptos verbales necesarios. Se trata de una tarea "
    "compleja en la que intervienen procesos cognitivos  que involucran al procesamiento lingüístico "
    "(memoria semántica y fonológica) como la capacidad de producción verbal controlada y programada, "
    "la organización de la respuesta, la estrategia de búsqueda léxica y la monitorización para evitar la "
    "emisión de respuestas ya dadas. También implica el procesamiento no lingüístico, en concreto, la atención, "
    "la memoria de trabajo, la velocidad de procesamiento, la inhibición y la flexibilidad mental."
    )
    p1.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY

# Segundo párrafo: ENFEN-Fluidez como recurso para el evaluación clínica (neuropsicológica)

    p2 = doc.add_paragraph(
    "ENFEN-Fluidez es un recurso pertinente para evaluar la fluidez verbal en población infantil (6 a 12 años). "
    "Desde el punto de vista neuropsicológico, esta prueba forma parte de ENFEN, primera batería adaptada "
    "al castellano que permite evaluar las funciones ejecutivas en niños de manera global. En concreto los resultados "
    "obtenidos con esta subprueba se consideran indicadores fiables de la eficiencia cognitiva del lóbulo frontal "
    "y del estatus neurocognitivo general del niño."
    )
    p2.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY

# Tercer párrafo: Utilidad de ENFEN-FLuidez para el ámbito escolar

    p3 = doc.add_paragraph(
    "A nivel escolar, ENFEN-Fluidez es un recurso apropiado para la detección de dificultades de "
    "aprendizaje (DA) y la identificación de necesidades específicas de apoyo educativo (NEAE), ya que "
    "contribuye a la evaluación de desarrollo madurativo global de los niños de 6 a 12 años y del nivel "
    "de desarrollo de su lenguaje expresivo (madurez léxica y habilidades fonológicas). Además es sensible "
    "a las dificultades asociadas al TDAH."
    )
    p3.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY

# Cuarto párrafo: Implicaciones para la intervención educativa

    p4 = doc.add_paragraph(
    "Por todo ello se considera que ENFEN-Fluidez es un recuros útil para plantear medidas educativas y "
    "para orientar la intervención especializada de apoyo."
    )
    p4.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY

# Escritura de párrafo justificativo del uso de ENFEN-Fluidez en relación a la hipótesis

    doc.add_heading('Motivación del uso de ENFEN-Fluidez', level=1)

# Llamada a la función secundaria 1 justifica_hipotesis()

    parrafo_hipotesis = justifica_hipotesis(datos['codigo_h'])

    p_just = doc.add_paragraph(f"En el caso de {datos['nombre']} " + parrafo_hipotesis)
    p_just.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY

# Continuamos con la Tabla de resultados...

# Tabla de resultados
    doc.add_heading('Resultados cuantitativos', level=1)
    table = doc.add_table(rows=1, cols=3)
    table.style = 'Light Grid Accent 1'
    
    hdr_cells = table.rows[0].cells
    hdr_cells[0].text = 'Subtest'
    hdr_cells[1].text = 'PD'
    hdr_cells[2].text = 'Puntuación Z'

    # Factor 1
    row1 = table.add_row().cells
    row1[0].text = 'Fluidez fonológica (F1)'
    row1[1].text = str(datos['f1_pd'])
    row1[2].text = str(datos['f1_z'])

    # Factor 2
    row2 = table.add_row().cells
    row2[0].text = 'Fluidez semántica (F2)'
    row2[1].text = str(datos['f2_pd'])
    row2[2].text = str(datos['f2_z'])

# Acceso a funciones secundarias ------------------------------------------------------

# Análisis
    doc.add_heading('Análisis de los resultados cuantitativos', level=1)

# Acceso a función secundaria 2: analizar_resultados ()

    parrafo_analisis_resultados = analizar_resultados (datos['codigo_h'], datos['cat_z'])

    p_just = doc.add_paragraph(parrafo_analisis_resultados)
    p_just.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY

#Acceso a función secundaria 3: propuestas (codigo_h, cat_z)

# 1. Llamada a la función
    dict_propuestas = propuestas(datos['codigo_h'], datos['cat_z'])

# 2. Preparar el texto para el informe. Creamos una lista de frases para luego unirlas
    lineas_informe = []
    doc.add_heading('Propuestas para la evaluación y para la intervención', level=1)
    
    if dict_propuestas["evaluacion"]:
        for item in dict_propuestas["evaluacion"]:
            lineas_informe.append(f"- {item}")
    
    if dict_propuestas["intervencion"]:
        for item in dict_propuestas["intervencion"]:
            lineas_informe.append(f"- {item}")

# 3. Unir todo en un solo string separado por saltos de línea
    texto_final = "\n".join(lineas_informe)

# 4. Añadir al documento de Word
    if texto_final:
        p_just = doc.add_paragraph(texto_final)
        p_just.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY
    else:
        doc.add_paragraph("No se seleccionaron propuestas técnicas.")

# Guardar el informe final
    doc.save(ruta_final)
    print(f"\n✅ Proceso completado. Informe generado: {nombre_final}")

 
#==================================================================

# Cuerpo principal o de ejecución

#===================================================================

if __name__ == "__main__":

#Fase 1. Recogida de datos personales ------------------------------------------------------------
    
    print("--- DATOS PERSONALES DEL ALUMNO---")
    
# Solicitamos los datos al usuario
    nombre = input("Nombre: ")
    apellidos = input("Apellidos: ") 
    try: # Convertimos la entrada de edad a entero (int) para poder operar con ella
        edad = int(input("Edad (sólo años): "))
    except ValueError:
        print("Error: Por favor, introduce un número válido para la edad (6 a 12 años).")
    centro = input("Centro escolar: ")
    curso = input("Curso: ")
        
# Fase 2. Llamada a la función cod_hipotesis ------------------------------------------------------

    codigo_h = cod_hipotesis(edad)
    print(f"\n[SISTEMA] Evaluación completada para {nombre}.")
    print(f"[SISTEMA] Código generado: {codigo_h}")
    if codigo_h == "0":
        print(f"No procede aplicar ENFEN-Fluidez en la evaluación de {nombre}. Fin del proceso")
        sys.exit()  # Se interrumpe el script

#Fase 3. Obtención de la puntuación directa de F1 y F2

    print("\n--- RESULTADOS DE LA APLICACIÓN DE ENFEN-FLUIDEZ---")
    f1_pd = int(input(f"Resultado obtenido por {nombre} en F1: "))
    f2_pd = int(input(f"Resultado obtenido por {nombre} en F2: "))

#Fase 4. Obtención de puntuación z para F1 y para F2

    f1_z = calcular_z (edad,"f1",f1_pd)
    f2_z = calcular_z (edad,"f2",f2_pd)

#Fase 5. Categorización de los resultados

    cat_z = resulta_categ(f1_z, f2_z)

# Bloque 2. Fase 6. Guardar datos en csv

    datos_archivar = {
        'nombre': nombre,
        'apellidos': apellidos,
        'edad': edad,
        'centro': centro,
        'curso': curso,
        'codigo_h': codigo_h,
        'f1_pd': f1_pd,
        'f1_z': f1_z,
        'f2_pd': f2_pd,
        'f2_z': f2_z,
        'cat_z': cat_z
    }

    archivar_en_csv(datos_archivar)

    print (f"Se han archivado correctamente los datos de {nombre} en la base de datos de ENFEN-Fluidez")

# Fase 7. Informe individualizado

    print(f"A continuación se procede a generar el informe individualizado de {nombre}")
    
    generar_info (datos_archivar)

    print(f"Se ha generado el Informe Individualizado Fluidez de {nombre}") 


sábado, 7 de marzo de 2026

Evaluación. Memoria

ENFEN. Fluidez verbal (VI)

Además de para ejercitarnos en el análisis de datos, la entrada anterior nos ha servido para considerar nuestra muestra de resultados ENFEN-Fluidez como razonablemente conforme a norma. Ahora la continuación de aquel análisis nos servirá para comprobar la viabilidad de nuestro planteamiento de cómo y par qué usar ENFE-Fluidez en la evaluación psicopedagógica de los SEO.

A partir de este momento, este análisis se centra en el rendimiento del alumando de nuestra muestra en relación al esperado para la media del grupo normativo, motivo por el que se emplea la puntuación z. Se trata de confirmar si la diferencia F1-F2 se mantiene dentro de lo esperado o es superior. En este segundoa caso (y sólo en él) se considera posible un análisis complementario en los términos en que se difinió éste en función del signo de la diferencia (F1>F2 vs F2>F1).

El primer paso en el análisis es comparar las puntuaciones 'z' de F1 Y de F2 para determinar la existencia o no de discrepancias y, en su caso, el tamaño de estas discrepancias. Originalmente esta cuestión se planteó en campo Discrepancia con tres posibles valores: Nula, Moderada o Severa, pero ahora nos interesa sólo el contraste Nula vs. No nula. Después se analiza la posición de cada sujeto en relación al rendimiento esperado. La tabla que sigue muestra, en síntesis el resultado de este doble análisis.

Discrepancia N Alto Promedio Bajo
NULA 23 1 19 3
Moderada 5

Estos resultados muestran que ENFEN-Fluidez es fundamentalmente lo que dice ser: una prueba para evaluar la memoria verbal, una vez descontamos la incidencia del criterio semántico en la conformación del lexicón. La diferencia 23 vs. 5 no deja lugar a dudas al respecto, especialmente si tenemos en cuenta las características del alumnado de esta pequeña muestra. Lo que resulta hasta cierto punto sorprendente es la fortaleza de esta capacidad ante contextos negativos como son los que caraterizan a nuestra muestra, en la que sólo 8 alumnos se encuentran por debajo del rendimiento normativo medio, bien en F1, bien en F2 o en ambas pruebas, a pesar de ser todos ellos alumnos con necesidades específicas de apoyo educativo, la mayoría con necesidades educativas especiales y un grupo importante de ellos también con condiciones socio-familiares deprimidas.

Estos 8 casos se dividen en dos grupos de peso similar respecto a las dos dificultades observadas: 3 presentan un rendimiento global (F1 y F2) inferior a promedio y 5 presenta discrepancia entre F1 y F2, siendo esta discrepancia mayoritariamente (4/5) por F1-Débil por encima de la diferencia normativa. Como ya dijimos, nos planeamos que estas dos formas de manifestarse la dificultad indican bajo rendimiento en memoria verbal la primera y posible incidencia de factores relativos al proceso de aprendizaje la segunda.

Empezando por la primera dificultad, y contrariamente a lo planteado incialmente, ahora debemos considerar que también aquí se presentan implicaciones para la evaluación: este déficit (de memoria) exige confirmación, lo que sugiere, en principio y por no salirse del constructo, que es conveniente aplicar otra prueba de memoria de trabajo: WISC-Dígitos podría ser un buen candidato por robusted, simplicidad, similitud y complementariedad respecto a ENFEN-Fluidez.

A partir de aquí se podrían considerar diferentes escenarios en el análisis de los resultados y en las propuestas de intervención educativa y clínica; pero estas son cuestiones para otra propuesta. En esta nos quedemos en la recomendación para el proceso de evaluación: si un sujeto se sitúa en la categoría déficit en Fluidez, se recomienda una evaluación complementaria de la memoria secuencial mediante WISC-Dígitos.

El segundo resultado observado exige varios análisis, ya que también son varias las posibles implicaciones:

  • Que el déficit sea por F1-Débil
  • Que lo sea por F2-Débil
  • Que lo sea por la fortaleza de F-Fuerte: posición de F-Fuerte en valor +1z, frente a F-Débil normal

De primeras descartamos que la tercera sea indicador de dificultad de algún tipo, por lo que este resultado pasará a ser considerado como una forma más de normalidad.

De las dos que restan sólo la primera se confirma empíticamente: mayoritariamente (4/5) la discrepancia negativa lo es por F1-Débil (siendo F1 <=-1z). podríamos considerar estos resultados una forma acentuada de la discrepancia "normal" F2>F1; pero esto sólo desplaza el abordaje de explicación causal: ¿por qué en determinados casos la diferencia "normal" se acentúa superando los límites de dicha "normalidad"?. Deberemos volver a la hipótesis de un débil desarrollo de las capacidades de las habilidades metafonológicas, con implicaciones indirectas en el aprendizaje de la lectura. F1 se conformaría así como un indicador fiable de dificultades metafonológicas con posibles implicaciones en el aprendizaje lector por la ruta fonológica.

Desde la perspectiva de análisis que ahora se confirma relevante incidiríamos en la confirmación del déficit metafonológico mediante evaluación complementaria y, en segundo lugar, en el estudio de un posible déficit lector que, en función de la edad del alumno, se puede concretar como evaluación mediante PROLEC-R (Palabras-vs-Pseudopalabras) o como análisis del expediente escolar.

Para finalizar una breve, pero necesaria, referencia a la excepción 1/5 deribada de F2-Débil: se trata de un alumno que obtiene la misma PD en F1 y en F2, lo que en si mismo ya es excepcional en ENFEN-Fluidez. Debido a ello, parece recomendable confirmar que se trata de un resultado representativo del funcionamiento del sujeto.

Llegar a esta solución es relevante por sus implicaciones: la posiblidad F1>F2 que incialmente consideramos como una de las posibles hipótesis de trabajo, ahora proponemos tratarla como excepcional y "sospechosa". Esto supone que los datos empíricos no permiten sostener F2-Debil<=-1z como indicador de déficit semático; frente a ello, la evidencia de incidencia negativa del contexto sobre el desarrollo del lenguaje está plenamente demostrada en la literatura y es evidente que con nuestros resultados no estamos autorizados para negar esa evidencia; es por ello que lo que corresponde es considerar F2 como no pertinente para abordar este tipo de cuestiones.

Esta conclusión nos obliga a ser muy cautos respecto a la aceptación de determiandos plantamientos, por muy verosímiles que parezcan, mientras no estén sustentados en estudios específicos, a ser posible basados en datos empíricos. Sírvanos esto para ENFEN-Fluidez y para el resto de las pruebas.

martes, 3 de marzo de 2026

Evaluación. Memoria

ENFEN. Fluidez verbal (V)

Finalizaba la entrada anterior comprometiendo en el futuro el análisis de los datos que recogíamos con el script Python que ella contenía. Empiezo ésta retomando esa promesa en el marco del acceso a los datos estructurados mediante el módulo CSV (por ejemplo, aquí).

El conjunto de datos con el que me propongo trabajar se ajusta al empleo de esos procedimientos y al actual nivel de nuestro conocimiento sobre el tratamiento de datos, incluyendo que no es necesaria la limpieza de datos y el análisis a realizar es muy sencillo en cuanto a sus objetivos: nos limitaremos a la descripción de los datos.

Los datos de que disponemos son pocos, pero suficientes para nuestro propósito actual: analizar el funcionamiento de la prueba como recurso de automatización de la evaluación en el marco paradigma "experto" de la IA.

Empezaremos por describir los datos disponibles y por comprobar si su funcionamiento general se ajusta al observado por los datos normativos, concretamente...

  • si aumenta el rendimiento en F1 y F2 en función de la edad,
  • si se aprecia diferencia de rendimiento sistemáticamente favorable a F2
  • y si se aprecia relevancia de la variable género.

Estas tres comprobaciones son necesarias para confirmar que nuestra pequeña muestra no pertenece a una población diferente a la la muestra normativa. Las dos primeras cuestiones fueron tratadas en la entrada en la que se analizaron los datos muestrales, pero no la última. En ENFEN-Fluidez (y en las demás pruebas ENFEN), se da a entender que la variable sexo es irrelevante, por lo que en ningún momento se hace referencia a sus efectos. Explícitamente en estos mismos términos se expresan las fuentes consultadas: se aprecian diferencias en función de la edad y el nivel educativo, pero no del sexo. No obstante, pretendo comprobar que en nuestro caso tampoco se aprecian esas diferencias.

Empezaremos por analizar la incidencia de la variable edad en los resultados, entendiendo que, en nuestra práctica, edad y nivel de escolarización son equivalentes.

Nuestra muestra está formada por 28 alumnos y alumnas, número insuficiente para dotarlo de la mínima representatividad, pero suficiente para comprobar las similitudes y diferencias repecto al grupo normativo.

En nuestros datos están representadas las edades 6 a 12 años, a excepción del colectivo 10 años. La tabla que sigue contiene esta información.

Edad (años) N %
6 años 3 10,71
7 años 7 25,00
8 años 8 28,57
9 años 4 14,29
10 años 0 0
11 años 3 10,71
12 años 3 10,71

Los grupos etarios no están equitativamente representados, predominando los grupos etarios 7 y 8 años, pero el resto cuenta con un número mínimo, suficiente para realizar algunos cálculos que nos ayuden en los análisis posteriores. El primero de estos análisis es la evolución de las PD en F1 y F2 en las diferentes edades, a fin de contatar en nuestra muestra la misma tendencia quese observa en el grupo normativo.

Los gráficos anterior muestra las similitudes y las diferencias en la evolución de F1 y F2 como promedio etario entre nuestros datos y los normativos. En ellos podemos observar comportamiento tendencialmente similar entre ambos, aunque también algunas diferencias de interés en otro contexto de análisis, que no en este, en el que lo importante para nuestros objetivos actuales, es que ambos grupos muestran la misma tendencia evolutiva: a mayor edad, mayor rendimiento, tanto en F1 como en F2.

Lo único que no se ajusta a esta observación es el comportamiento de nuestro grupo 12 años en F1, que es marcadamente descendente respecto a 11 años y contradice lo esperado a nivel normativo, en el que se observa un incremento moderado respecto al grupo etario anterior. Es posible que la explicación de este comportamiento esté en la pecularidad de nuestra muestra, que se concretamente se acentúa en este subgrupo de edad: estamos ante una pequeña muestra de alumnos con necesidades educativas que, en concreto y por el momento en que se recogieron los datos, entra dentro de la condición de alumnado con antecedentes de importantes dificultades escolares, incluyendo la repetición de curso.

La segunda cuestión que nos interesa es la diferencia de enrdimiento entre F1 y F2, que es favorable para F2 en todos los grupos etarios en el baremos y también en nuestra muestra. Únicamente se observa un caso en que ambas puntuaciones son iguales, pero ninguno en el que F1 sea superior a F2. En resumen, nuestro grupo tiene en esto el mismo comportamiento que el normativo.

Para finalizar estudiamos el comportamiento de la variable sexo. Nuestra muestra está formada por un número muy similar de niños (15) y de niñas (13), incluyendo un reparto equitativo ambos subgrupos por edades. Realizados los cálculos pertinentes, los valores medios de F1, F2 y de la diferencia F1-F2 en niños y en niñas muestran gran similitud, como podemos observar en esta tabla.

Género Md en F1 Md en F2 Diferencia F1-F2
Niños 7,07 12,40 -5,33
Niñas 7,23 12,38 -5,15

No parece necesarios más cálculos para concluir que no existen diferencias en los resultados que obtienen niños y niñas, confirmándose también en nuestra muestra la irrelevancia estadística del género en el rendimiento en tareas de fluidez verbal.

Como resumen de estos análisis realizados podemos decir que nuestra muestra tiene el mismo comportamiento que el grupo normativo de ENFEN-Fluidez. Esto nos permite realizar análisis de niveles de rendimiento en los términos planteados en entradas anteriores. Estos análisis se expondrán en otra entrada.

jueves, 26 de febrero de 2026

Evaluación. Memoria

ENFEN. Fluidez verbal (IV)

Si queremos que nuestro análisis (y en consecuencia, la propia evaluación) sirva para algo más que para decir que el sujeto se sitúa en una puntuación normativa X, es necesario plantear a priori el procedimiento de análisis y de interpretación de los resultados.

Empezaremos por plantear qué referencia vamos a emplear, no tanto por ser importante como por plantear la diferencia en el modo de entender la naturaleza y el objetivo de la evaluación.

En la evaluación clinica de la fluidez verbal interesa conocer el decatipo, pero para la evaluación educativa puede ser suficiente conocer la puntuación z (dado que es la que nos permiten calcular los estadísticos que aporta la prueba: promedio y dedesviación estándar), que situa al alumno en relación al intervalo central del grupo etario. En base a esta referencia se desarrollarán los análisis que siguen.

Esto es así porque desde la perspectiva de la intervención educativa lo que nos interesa en primer lugar es si los resultados indican que el niño presenta o no cierto grado alteración en sus capacidades de recuerdo de palabras (memoria verbal). En un contexto de evaluación clínica, esta información es relevante en si misma, pero desde el punto de vista de la intervención educativa lo es cuando existen indicios de que puede ser un factor relevante para entender la problemática que presenta el alumno. Evidentemente, en ese caso no lo será como prueba única. Por ejemplo, se puede considerar conveniente aplicar también el test Dígitos de las escalas Wechsler a fin de obtener un mejor conocimiento del rendimiento del alumno en tareas de memoria.

Volviendo al rendimiento observado en las pruebas de Fluidez, el rendimiento observado en el grupo normativo de la prueba evidencian una diferencia en términos de puntucación directa entre F1 y F2, sistemáticamente favorable a F2. Esta diferencia se debe considerar normal siempre que se mantenga dentro de lo observado, y se debe a razones de funcionamiento del sistema cognitivo humano que explican coherentemente las ciencias neurocognitivas. Así que hasta aquí nada que decir que no quede dicho por la observación del rendimiento en relación al esperado para la edad.

No obstante este feonómeno permite un segundo nivel de análisis, no tan potente y sólido teóricamente como el primero, pero sí con un potencial interés en términos de comprensión de las dificultades que se puedan observar en el proceso de aprendizaje: cada una de las dos pruebas implican procesos diferentes de acceso al léxico aprendido. Si en términos de puntuación normalizada (punt. z) se observa diferencia entre ambas (F1 y F2), es que esa diferencia es evidentemente superior a la explicada por la naturaleza del sistema. En este caso esa diferencia debe tener (potencialmente) una explicación, que puede resultar relevante para comprender la naturaleza de las dificultades observadas (y esta observación es el punto de partida necesario) en el proceso de aprendizaje.

Una posible interpretación de esa diferencia con implicaciones útiles para la evaluación educativa es que F1 está revelando el grado de desarrollo de las habilidades metafonológicas, asociadas al proceso de aprendizaje de la lectura por la ruta fonológica. Frente a ella, F2 involucra procesos generales de aprendizaje/desarrollo léxico-semántico, asociados a la escolarización , pero también a la estimuación del medio socio-familiar (aprendizaje incidental).

Cuando F1-F2 no presentan diferencias 'z' podemos valorar el nivel de rendimiento en memoria verbal del sujeto como rendimiento inferior a promedio, rendimiento dentro de promedio o rendimiento superior a promedio. Pero cuando sí se constatan diferencias 'z' (superiores a las "normales) no podemos deducir necesariamente uno u otro tipo de déficit; tan sólo servirán para que nos planteemos la posibilidad de que exista tal relación; debiendo ser esta posibilidad objeto de investigación con los recursos y los procedimientos apropiados, aquellos que sí permiten valorar directamente los problemas que F1 vs. F2 sugieren.

La primera consecuencia de lo anteriormente dicho es que deberemos diferenciar en el análisis dos fases: la primera se refiere al nivel de rendimiento general en términos de Fluidez verbal; la segunda sólo será viable (y en los términos antes expuestos) cuando se cumpla la condición de base: F1 y F2 son z-discrepantes, esa discrepancia sugiere x vs. y, y los datos disponibles confirman/no confirman (x|y). Si no confirman por constatación de ausencia de la posible causa, la z-discrepancia carece de relevancia; pero si la no-confirmación es debida a ausencia de información, z-discrepancia deberá servir de base para plantear la recogida de información directa mediante prodecimientos válidos.

La primera fase del análisis se base en la aplicación del procesamiento hacia adelante (SI x ENTONCES y), pero para la segunda fase (para z-descrepancia F1-F2) deberemos aplicar el procesamiento hacia atrás. Mantener el primero procedimiento implicaría ahora asumir una causalidad difícil de constatar y muy compleja de desarrollar, mientras que el procesamiento hacia atrás se ajusta mejor a la dinámica del análisis que se plantea y resulta mucho más sencillo de implementar: se trata de confirmar una única hipótesis (la derivada de F débil) en dos fases: contatar que existen evidencias vs. que no existen, e indican (que no implican necesariamente) el procedimiento a seguir ante la ausencia de datos. En cualquier caso ambas fases del análisis son relativamente factibles de plantear y de desarrollar mediante un algoritmo.

Una posible plasmación en la práctica de lo anteriormente expuesto es este script:


import csv
import os

# Bases de datos cronológicas (6 a 12 años)
f1_md = [5.25, 6.65, 8.66, 9.25, 11.16, 11.73, 12.04]
f1_dt = [2.65, 2.68, 2.85, 3.02, 3.09, 3.35, 3.19]
f2_md = [10.26, 11.18, 13.57, 14.08, 16.79, 17.88, 17.81]
f2_dt = [3.81, 3.34, 3.95, 3.87, 4.49, 4.72, 4.11]

FILE_NAME = "registro_clinico_expert.csv"

def obtener_siguiente_id():
    """Genera un ID incremental tipo Al01, Al02 basándose en las líneas del CSV."""
    if not os.path.exists(FILE_NAME):
        return "Al01"
    with open(FILE_NAME, "r", encoding="utf-8") as f:
        lineas = f.readlines()
        if len(lineas) <= 1: return "Al01"
        ultimo_id = lineas[-1].split(",")[0]
        numero = int(ultimo_id.replace("Al", "")) + 1
        return f"Al{numero:02d}"

def inicializar_csv():
    """Crea el archivo con encabezados si no existe."""
    if not os.path.exists(FILE_NAME):
        with open(FILE_NAME, "w", newline="", encoding="utf-8") as f:
            writer = csv.writer(f)
            writer.writerow(["ID", "Edad", "PD_F1", "PD_F2", "Z1", "Z2", "Discrepancia", "Confirmado", "Diagnostico_Final"])

def guardar_datos_csv(datos):
    """Escribe una fila de datos en el archivo CSV."""
    with open(FILE_NAME, "a", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow(datos)

def ejecutar_sistema_experto_final():
    inicializar_csv()
    
    while True:
        print("\n" + "=".center(75, "="))
        print(f" SISTEMA EXPERTO: PROTOCOLO {obtener_siguiente_id()} ".center(75))
        print("=".center(75, "="))
        
        try:
            edad = int(input("Edad (6-12) [0 para salir]: "))
            if edad == 0: break
            
            pd_f1 = float(input("Puntuación Directa F1: "))
            pd_f2 = float(input("Puntuación Directa F2: "))
            
            # --- FASE 1: PROCESAMIENTO ADELANTE ---
            idx = edad - 6
            z1 = (pd_f1 - f1_md[idx]) / f1_dt[idx]
            z2 = (pd_f2 - f2_md[idx]) / f2_dt[idx]
            n1, n2 = (z1 >= -1.0) + (z1 > 1.0), (z2 >= -1.0) + (z2 > 1.0)
            
            etiquetas = ["BAJO", "PROMEDIO", "ALTO"]
            diff_unidades = abs(n1 - n2)
            severidad = ["NULA", "MODERADA", "SEVERA"][diff_unidades]

            print(f"\n[DATO] F1: {etiquetas[n1]} (Z:{z1:.2f}) | F2: {etiquetas[n2]} (Z:{z2:.2f})")

            # --- FASE 2: PROCESAMIENTO ATRÁS (CONFIRMATORIO) ---
            id_sujeto = obtener_siguiente_id()
            status_confirmado = "N/A"
            msg_final = ""
            
            if n1 == n2:
                msg_final = f"Rendimiento Armónico Memoria {etiquetas[n1]}"
                status_confirmado = "Sincrónico"
            else:
                if n1 < n2:
                    print(f"\n[META]: Validar Hipótesis de retraso metafonológico (F1).")
                    check = input("¿Evidencia directa de déficit en segmentación/lectura? (s/n): ").lower()
                else:
                    print(f"\n[META]: Validar Hipótesis de incidencia socio-familiar (F2).")
                    check = input("¿Evidencia directa de vulnerabilidad social/migración? (s/n): ").lower()
                
                if check == 's':
                    status_confirmado = "SÍ"
                    msg_final = f"Confirmado: Indicio de factor {'Fonológico' if n1 < n2 else 'Ambiental'}"
                else:
                    status_confirmado = "NO"
                    msg_final = "Específico" if diff_unidades >= 2 else "No Relevante"

            print("-" * 75)
            print(f"VALORACIÓN PARA {id_sujeto}: {msg_final}")

            # --- GUARDADO DE DATOS ---
            guardar_datos_csv([id_sujeto, edad, pd_f1, pd_f2, round(z1, 2), round(z2, 2), severidad, status_confirmado, msg_final])
            print(f"[REGISTRO] Datos guardados correctamente en {FILE_NAME}")

        except (ValueError, IndexError):
            print(">> Error: Entrada no válida.")

        if input("\n¿Siguiente caso? (s/n): ").lower() != 's': break

if __name__ == "__main__":
    ejecutar_sistema_experto_final()


Resumiendo, se piden los datos de edad, F1-Pd y F2-Pd; con esos datos y los que contienen las listas definidas en el script se calculan las puntuaciones z de cada prueba. Si ambas puntuaciones se sitúan dentro del mismo rango el análisis se limita a valorar el rendimiento en Fluidez-Memoria verbal. Si (y sólo si) se observan z-discrepancia se aplica la segunda fase del análisis: confirmar la existencia de indicios de problemáticas específicas para F-débil; si es F1, problemas específicos en las habilidades segmentales y de lectura (ruta fonológica); si es F2, factores (contextuales) con incidencia negativa en el desarrollo (del lenguaje).

Este script permite la recogida de múltiples datos y su archivo en un documento .csv. En otro momento se retomará este documento para el análisis de datos.

Evaluación. Memoria

ENFEN. Fluidez verbal (III)

En esta entrada vamos a tratar con cierto detalle la configuración del procedimiento de análisis de los resultados y la propuestas de automatización del informe tal y como se plantean (inicialmente, vamos a decir ahora) en el DocAp que presenté en la entrada anterior. Pretendo desarrollar este análisis tomando como referencia, además de lo evidente (el soporte Calc el código OOo Basic disponibles), la documentación expuesta en las entradas sobre el paradigma experto-IA (ver entradas en Orient-IA).

Con este análisis pretendo reflexionar sobre hasta qué punto los sistemas de corrección y lo que en este blog se ha planteado en múltiples ocasiones al proponer recursos de evaluación comparten, en gran medida, ese enfoque de trabajo, aunque con limitaciones, deficiencias e insuficiencias añadidas.

Sobre cómo abordan las plataformas la automatización de sus análisis algo hemos dicho en entradas anteriores y algo diremos también aquí, pero el objetivo es centrarme más bien en lo que he planeado con cierta frecuencia como soluciones de automatización tipo DocAp. Cierto es, además, que esta propuesta de solución también ha bebido de esas fuentes, como no puede ser de otro modo, ya que las plataformas de corrección son referentes obligados en términos de forma y de contenido.

En cuanto a estas cuestiones, la fuente o base de conocimiento se explicita en los informes resultantes como análisis descriptivo de la prueba, siempre al inicio del documento y de forma variablemente extensa y detallada. Replicar este contenido en un procedimiento DocAp no ha ofrecido especial dificultad, aunque lo que me genera dudas es su utilidad y, por tanto, su pertinencia. A veces tengo la impresión de que este tipo de contenido sirven de poco y da la impresión de estar ahí para ocultar el escaso contenido de algunos informes. En todo caso, de tener utilidad real la tiene para el profesional (generalmente al profano poco le aporta), siendo que es precisamente éste quien (se supone) menos la necesita.

La segunda cuestión ya presenta mayor complejidad y requiere, por ello, mayor atención: me refiero a las reglas que determinan la relevancia de los datos y el modo en que éstos se analizan. Todavía no estamos aplicando procedimientos del tipo de los explicitados en esta entrada como estrategias de razonamiento, pero son la base para ese paso. Aquí, y en referencia a este DocAp (ENFEN-Fluidez) me tengo que detener ahora.

Diré, en primer lugar, que los datos relevantes son, obviamente, el número de palabras correctamente expresadas por el sujeto, datos estos que se enmarcan dentro de la edad del sujeto, puesto que el análisis está mediatizado por esa única variable. La consecuancia es que el DocAp debe recopilar esa información cuantitativa como base para realizar el posterior análisis de datos. Para ello se desarrolla el siguiente procedimiento:


Sub PuntuarPrueba

Dim oHoja As Object, oCelda As Object
Dim iEdad As Integer, iF1Pd As Integer, iF2Pd As Integer, iDif As Integer
Dim mDif(6) As Double
Dim dDifEsperada As Double
Dim iDifValora As Integer

MF1_Decatipo
MF2_Decatipo

mDif() = Array(4.98,4.53,4.91,5.63,6.15,5.77)

oHoja = ThisComponent.getSheets().getByName("Datos")
oCelda = oHoja.getCellRangeByName("B9")
iEdad = oCelda.getValue()

Select case iEdad
	Case 6
		dDifEsperada = mDif(0)	
	Case 7
		dDifEsperada = mDif(1)	
	Case 8
		dDifEsperada = mDif(2)	
	Case 9
		dDifEsperada = mDif(3)	
	Case 10
		dDifEsperada = mDif(4)	
	Case 11
		dDifEsperada = mDif(5)	
	Case 12
		dDifEsperada = mDif(6)	
End Select

oCelda = oHoja.getCellRangeByName("B10")
iF1Pd = oCelda.getValue()
oCelda = oHoja.getCellRangeByName("B13")
iF2Pd = oCelda.getValue()

iDif = iF2Pd - iF1Pd

If iDif - dDifEsperada > 0  Then
	iDifValora = 1
Else
	iDifValora = 0
End If

oCelda = oHoja.getCellRangeByName("B17")
oCelda.setValue(iDifValora)

	vHoja(0,True)
	PasoHoja (1)
	vHoja(1,False)

End Sub

Mediante este script accedemos a tres celdas ubicadas en la hoja Datos, las cuales contienen el dato edad (B9) y las puntuaciones directas de F1 (B10) y F2 (B13). Lo que sigue se desarrollar mediante llamadas a sendas funciones que calculan los valores de las PD como decatipos según los datos de baremos de la prueba. Me refiero, por ejemplo, a este script para el cálculo del valor decatipo de F1.



Sub MF1_Decatipo

Dim oHoja As Object, oCelda As Object

Dim mF16a(13) As Integer, mF17a(14) As Integer, mF18a(16) As Integer, mF19a(17) As Integer, mF110a(18) As Integer, mF111a(21) As Integer
Dim mF1() As Integer
Dim iEdad As Integer, iF1pd As Integer, iF1Decatipo As Integer, i As Integer, iF1Categoria As Integer

oHoja = ThisComponent.getSheets().getByName("Datos")

mF16a() = Array(1,2,3,4,4,5,6,7,8,8,9,9,9,10)
mF17a() = Array(1,1,1,2,3,3,4,5,5,6,7,8,8,9,10)
mF18a() = Array(1,1,1,1,2,3,4,4,5,6,7,7,8,9,9,9,10)
mF19a() = Array(1,1,1,1,2,3,3,4,5,6,6,7,7,8,8,9,9,10)
mF110a = Array(1,1,1,1,1,1,2,3,3,4,5,6,6,7,7,8,8,9,10)
mF111a() = Array(1,1,1,1,1,1,1,2,2,3,3,4,5,5,6,6,7,8,8,9,9,10)

oCelda = oHoja.getCellRangeByName("B9")
iEdad = oCelda.getValue()

Select Case iEdad
	Case 6
		mF1() = mF16a()
	Case 7
		mF1() = mF17a()
	Case 8
		mF1() = mF18a()
	Case 9
		mF1() = mF19a()
	Case 10
		mF1() = mF110a()
	Case >= 11
		mF1() = mF111a()
End Select

oCelda = oHoja.getCellRangeByName("B10")
iF1pd = oCelda.getValue()

For i = 0 To UBound(mF1())
	mF1(i)
	If i = iF1pd Then
		iF1Decatipo = mF1(i)
		Exit For
	End If
Next

oCelda = oHoja.getCellRangeByName("B11")
oCelda.setValue(iF1Decatipo)

Select Case iF1Decatipo
	Case <= 2
		iF1Categoria = 0
	Case 3
		iF1Categoria = 1
	Case 4
		iF1Categoria = 2
	Case 5
		iF1Categoria = 3
	Case 6
		iF1Categoria = 3
	Case 7
		iF1Categoria = 4
	Case 8
		iF1Categoria = 5
	Case >= 9
		iF1Categoria = 6
End Select

oCelda = oHoja.getCellRangeByName("B12")
oCelda.setValue(iF1Categoria)

End Sub

Aunque este procedimiento no sólo es válido, sino que se puede considerar el único ajustado al procedimiento normativo de análisis del test, implica también aceptar como únicamente válido el modelo clínico subyacente, lo que no es compartido por quienes consideran que la evaluación eductiva, que está orientada a la detección de necesidades específicas de apoyo educativo, se debe diferenciar de la evaluación clínica.

Además, desde una perspectiva de carácter procedimental se puede plantear que en realidad poca información y/o información poco relevente podemos sacar de un análisis como el que se deriva de la aplicación de este tipo de script.

Para finalizar con esta línea de análisis falta analizar cual es la propuesta interpretativa que se planea en estos momentos y en función de ese enfoque, la cual está contenida en el script InfoIndiv(mResultados() del módulo ModExternos, que reproduzco a continuación.



Sub InfoIndiv(mResultados() As Variant)

Dim sRuta As String
Dim mArg()
Dim oNuevoDoc As Object, oTexto As Object

Dim sDatosAlumno As String, sPresenta As String, sPrueba As String
Dim sF1presenta As String, sF1Resulta As String, sF1PDz As String, sF1DecatCat As String, sF1DeCatAnalisis
Dim sF2presenta As String, sF2Resulta As String, sF2PDz As String, sF2DecatCat As String
Dim sF1F2Compara As String
Dim sValora As String, sImplica As String
Dim sTextoInforme As String

'Crear nuevo documento

sRuta = "private:factory/swriter"
oNuevoDoc = StarDesktop.loadComponentFromURL( sRuta, "_default", 0, mArg())

'Construcción del contenido 

'Datos de identificación

sDatosAlumno = "Alumno/a: " & mResultados(0) & " " & mResultados(1) & " Curso: " & mResultados(5)

sPresenta = "ENFE. Funciones ejecutivas. Fluidez"

'Análisis de la prueba ENFEN

sPrueba = "ENFEN (Portellano, Martínez y Zumárraga (2009)) es una batería de pruebas que tienen como objetivo evaluar el nivel de madurez y el rendimiento cognitivo en actividades relacionadas con las funciones ejecutivas. " &_
		  "A nivel psicométrico, la bataría ENFEN está formada por un conjunto de test normativos, cuyas puntuaciones tipificadas se expresan como decatipos (media 5,5; Dt 2). Cada test de la prueba cuenta con un baremos por edades (de 6 años a 11/12 años), lo que nos permite transformar las PD en el decatipo correspondiente en función de la edad. " &_
		  "ENFEN también nos proporciona los estadísticos básicos de cada grupo de edad (Md y Dt), lo que permite analizar la PD del individuo en relación a los resultados medios de su grupo de edad." & Chr(13) & Chr(13) &_
		  "La Fluidez verbal se incluyen en ENFEN como proceso en el que están implicadas funciónes ejecutivas básicas, dada la incidencia de procesos atencionales y de memoria de trabajo. También es posible entender la fluidez verbal como indicador de la capacidad de acceder a la memoria verbal a largo plazo para recuperar la información verbal almacenada en ella. " &_
		  " Además también nos aporta datos relativos al nivel de desarrollo del lenguaje del sujeto." & Chr(13) & Chr(13) &_
		  "En ENFEN se hace uso de dos pruebas de Fluidez verbal, una por clave fonológica (F1) y otra por clave semántica (F2); esto permite realizar comparaciones del rendimiento en ambas en términos normativos y a nivel ipsativo. " &_
		  "A nivel normativo, los datos observados en ambos test son coherentes con los estudios realizados al respecto, mostrando la existencia de una diferencia invariablemente positiva a favor de F2, la cual se mantiene estable en el proceso evolutivo. " &_
		  "Esto se puede entender como consecuencia de la mayor dificultad de la clave fonológica en la recuperación de la información en comparación con el uso de la clave semántica; pero también en el procesamiento del contenido de la memoria a corto plazo."

'Análisis de los resultados en F1

sF1presenta = "Analizamos a continuación los resultados de " & mResultados(0) & " en la prueba de Fluidez Fonológica (F1)" & Chr(13) & Chr(13) &_
			  "La Fluidez fonológica se evalúa en ENFEN solicitando al sujeto la producción de palabras que empiecen por la letra/el sonido 'M'. " &_
			  "En ENFEN se incluye esta prueba para evaluar las funciones ejecutivas por resultar inusual la generación de palabras en base a un criterio fonológico, siendo la habitual el uso de estrategias de base léxico-semántica. Por ello esta exigencia obliga a la persona " &_
			  "a generar estrategias no habituales, requiriendo una organización eficiente de la recuperación verbal, autocontrol e inhibición de las respuestas inapropiadas. " &_
			  "Dado que se exige recuperación de información verbal, también se pone a prueba tanto el mecanismo de acceso al léxico como la propia memoria verbal a largo plazo. Además, el uso de claves fonológicas implica procesos de decodificación y codificación, fundamentales en la lecto-escritura. " &_
			  "Por todo ello la evaluación de la fluidez verbal es de interés para la evaluación de las dificultades de aprendizaje."
			  
'Valoración de la PD en F1

sF1PDz = CalculoZ("F1",mResultados(0),mResultados(8),mResultados(9))

'Valoración del decatipo del sujeto

sF1DecatCat = CatDecatipo(mResultados(11))

sF1DeCatAnalisis = "El decatipo correspondiente a la PD antes analizada es, según el baremo de su grupo etario, " & mResultados(10) & " el cual permite calificar su rendimiento como de nivel " & sF1DecatCat & "."

'Creación del texto de análisis de F1

sF1Resulta = sF1presenta & Chr(13) & Chr(13) & sF1PDz  & Chr(13) & Chr(13) & sF1DeCatAnalisis

'Escritura del contenido

oTexto = oNuevoDoc.Text

oTexto.insertString(oTexto.getEnd(),sDatosAlumno & Chr(13) & Chr(13), False)
oTexto.insertString(oTexto.getEnd(),sPresenta & Chr(13) & Chr(13), False)
oTexto.insertString(oTexto.getEnd(),sPrueba & Chr(13) & Chr(13), False)
oTexto.insertString(oTexto.getEnd(),sF1Resulta & Chr(13) & Chr(13), False)
'oTexto.insertString(oTexto.getEnd(),sTextoInforme, False)

End Sub


Como puedes ver, se trata de una subrutina que genera un documento en base a Writer. Como subrutina es activada desde el script DocumentosExternos mediante la llamada InfoIndiv(mDatos()) que pasa a la subrutina el contenido de la matriz mDatos().

Esta subrutina no está completamente desarrollada (o lo está parcialmente) ya que se limita al análisis de F1, pero contiene suficiente información como para servirnos de base para este análisis.

Empezaré diciendo que aparentemente resulta más compleja de lo que sería deseable, ya que contiene un número muy elevado de variables, lo que indica que posiblemente no se haya realizado un buen análisis previo de estrategias de automatización de los datos. Sobre esta cuestión trataremos en una próxima entrada, ya que ahora interesa que nos centremos en lo que tenemos delante y la alternativa que emerga de este análisis sea suficientemente compleja como para merecer ser expuesta en una entrada diferente.

Volviendo sobre lo observable, la estructura de contenido es la siguiente: datos de identificación del sujeto + descripción de la prueba (2 niveles: general + específico) + análisis de resultados.

Los dos primeros componentes no son de mayor interés ni ofrecen dificultades de implementació, al margen de las dudas ya expuestas sobre su utilidad; pero contienen un volumen total de información nada desdeñable, especialmente en casos como el actual en el que primero se decribe la prueba en su conjunto (ENFEN-Fluidez) y después cada una de las subpruebas que la conforman (en este caso sólo F1. Fluidez fonológica). Sin entrar en el interés que estas descripciones puedan tener, lo cierto es que es muy posible que existan otras formas más adecuadas y útil de manejar toda esta información sin que resulte abrumadora (y hasta distractora) al inicio del informe.

No obstante, se presentan dudas en la tercera fase, en la que se debería concretar la implementación de las reglas de interpretación de los resultados. Es aquí donde este modelo revela sus limitaciones precisamente por la manifiesta ausencia de esas reglas, limitándose a presentar datos (sF1Resulta=sF1presenta&Chr(13)&Chr(13)&sF1PDz&Chr(13)&Chr(13)&sF1DeCatAnalisis) que resultan de la aplicación de determinads funciones como CatDecatipo() a la que llama en sF1DecatCat = CatDecatipo(mResultados(11)). Esta, y no la ausencia de análisis de F2, es la principal carencia de este script.

Esta estrategia, evidentemente muy básica, se puede denominar como "expositiva", pero ponerle un nombre no es suficiente para encubrir lo que no deja de ser la evidencia de una carencia: la falta de criterios de análisis revela la ausencia de teorización sobre la prueba y el significado de los resultados que obtenemos con ella. Implica, en definitiva, carecer de una estrategia de interpretación condicionada.

Al carecer de dicha condicionalidad no es posible identificar en el DocAp ninguna estrategia de análisis, lo que parece (y es) contraproducente con el objetivo que animó la creación del instrumento. Pero "curiosamente" se trata de una "estrategias" de uso mucho más frecuente de lo esperable: al carecer de una teorización sobre el significado de las puntuaciones o al no querer comprometerla, con demasiada frecuencia se opta por la mera exposición de los datos, especialmente en los sistemas de corrección automatizada. En ellos se puede añadir el adorno de alguna categorización, lo cual tampoco compromete gran cosa, dado que corre a cuenta del aparato estadístico de la prueba. El resto queda a la libre y profesional interpretación del especialista, expediente éste perfectamente válido en otros contextos, pero aquí simplemente útil por admitido.

Esta socorrida "solución expositiva" puede ser válida para herramientas de automatización como los sistemas de corrección on-line, lo que dice mucho sobre la utilidad real de los informes que emiten, pero no lo es cuando somos nosotros mismos los que, como profesionales y especialistas, diseñamos nuestras propias herramientas de automatización, bajo nuestros criterios y en función de nuestros objetivos. En estos casos o somos capaces de implementar procedimientos y reglas de análisis o la herramienta que creemos servirá de bien poco.

Cierto es, no obstante, que también podemos limitar conscientemente nuestro proyecto de "automatización" a explicar cuestiones generales sobre el instrumento y sus características, y a formalizar la exposición de resultados. Hacer esto puede ser un objetivo válido y suficiente para algunos y/o en determinadas circunstancias, pero evidentemente deja pendiente el pleno desarrollo de lo que el modelo experto IA promete.

La concreción de esta promesa en el caso concreto de ENFEN-Fluidez queda pendiente para la próxima entrada.

lunes, 23 de febrero de 2026

Evaluación. Memoria

ENFEN. Fluidez verbal (II)

El análisis que de ENFEN-Fluidez realizamos en la entrada anterior es justificación suficiente para el desarrollo de este DocAp, aunque no condiciona el modo en que se concrete. Explicarlo es el cometido de esta entrada.

Como recurso de evaluación, sitúo ENFEN-Fluidez en el segundo nivel de intervención dentro del proceso de evaluación; aquel que implica la intervención individualizada con el alumno, por contraposición al primer nivel o de evaluación de base grupal y/o del alumno en el contexto del aula. Cierto que la simplicidad de la aplicación de esta prueba no impide radicalmente su aplicación en el grupo, pero parece más apropiado aplicarla como parte de la evaluación individual.

Otra cosa es si podemos pensarla dentro de un contexto de colaboración con servicios clínicos externos, lo cual es perfectamente factible, pero realmente esa es una cuestión secundaria: aplicar ENFEN-Fluidez está suficientemente justificada por si misma en función de lo que aporta para la identificación diferenciada de dificultades de aprendizaje, por lo que aporta respecto a la evaluación de las capacidades de memoria verbal, y por lo que aporta para la identificación de posibles dificultades de naturaleza escolar y la incidencia en que ellas tienen factores ambientales y/o del desarrollo de procesos básicos de aprendizaje.

Aunque ambas cuestiones no dejan de tener interés para el diseño de la intervención, lo cierto es que en términos operativos, ahora resultan poco relevantes, dado el objetivo de la entrada. Corresponde, eso sí, explicar en qué consiste el DocAp.

Lo primero es decir, precisamente, que se trata de un Docap; esto es un recurso que integra una serie de procesos (que veremos después) basándose en los servicios de LibreOffice, y que es posible gracias al empleo del lenguaje OOo Basic.

Como DocAp se puede calificar como DocAp complejo dado que requiere de la intervención de dos servicios, aunque tal y como se configura podríamos identificarlo como DocAp simple, puesto que la versión que aquí presento no se ha desarrollado del todo, por lo que sólo se hace uso de Calc, quedando Writer como soporte complementario, únicamente "a modo de prueba".

La automatización es, pues, parcial, aunque lo es por motivos que explicaré en su momento; no precisamente por carecer de los medios técnicos para alcanzar niveles óptimos de desarrollo como DocAp: no culminar la lógica implícita (de automatización) es una decisión tomada conscientemente, a pesar de disponer de los medios para hacerlo. Nos quedamos a las puertas de automatizar la generación del informe de resultados (1) para dedicar una entrada específica a tratar este tema en el marco del análisis las opciones disponibles, concretamente de la viabilidad de lo que podríamos llamar de forma un tanto grandilocuente modelo experto de automatización (2).

Por eso, hasta aquí me limito a presentar en esta entrada la automatización de la aplicación y la puntuación del test, quedando pendiente el análisis de resultados y la generación del informe individualizado. Todo ello se concreta un soporte Calc que deriva de otro utilizado hace tiempo para digitalizar y recoger datos de la escala ENFEN al completo (no exclusivamente de las pruebas de fluidez). En el original no existía prácticamente automatización, pero en el actual sí, heredando en ello el modelo aplicado en una antigua versión Filemaker que sí automatizaba la puntuación, un somero análisis de los datos y la emisión de un breve informe personalizado de resultados.

El DocAp actual consta formalmente de tres hojas (Id, Pruebas y Datos), de las cuales sólo la primera está visible al abrir el documento. Pero la complejidad real del DocAp está en el código, responsable de su funcionamiento, visible desde el IDE y que contiene lo siguiente:

Como ves, se diferencian 6 módulos y 22 script. Este conjunto de elementos hace posible que se desarrollen los procesos de automatización del DocAp y que explicaré resumidamente en base a lo que la visualización de la interface permite entrever.

En hoja Id encuentras un formulario basado en celdas, destinado a recoger los datos de identificación del alumno, y lo que es la síntesis de resultados de la aplicación del test.

Además tienes dos comandos: uno (APLICAR TEST) para continuar con la aplicación de la prueba y otro (BORRAR) para borrar el contenido antiguo, si es que está aun visible. Como sabes, ambos están asociados a la ejecución de sendos script.

La segunda hoja queda accesible al activar el botón APLICAR TEST y contiene, como cabe esperar, el sistema de recogida de datos y el de puntuación del test. Ambos funcionan mediante los comandos respectivos: Contador F1 Y Contador F2 para capturar las respuestas (el número de respuestas) y PUNTUAR para realizar la puntuación del test en función de los estadísticos de la prueba.

En este caso sí me interesa detenerme en la explicación del funcionamiento de estos comandos, ya que presenta cierta diferencia respecto a los procedimientos conocidos de puntuación de la ejecución. Esto es así porque en estas pruebas de fluidez lo que nos interesa es capturar el número de respuestas correctas que emita el sujeto, y nada más. De ahí que hayamos ideado un procedimiento de contador de aciertos que se concreta en dos script, uno por cada prueba (Fonológica - Semántica) asociados a sendos comandos (aquí el script del contador F1)...



Sub ContadorF1

Dim oHoja As Object, oCelda As Object
Dim i As Integer

'Acceso a la hoja Pruebas
oHoja = ThisComponent.getSheets().getByName("Pruebas")

'Acceso a la celda contador
oCelda = oHoja.getCellRangeByName("G2")
i = oCelda.getValue

i = Contador(i)

oCelda.setValue(i)

End Sub

... y ambos script a la función Contador()

Function Contador(i As Integer) As Integer

Contador = i + 1

End Function


El comando PUNTUAR presenta un código más complejo, que conforma los tres script (un script y dos subrutinas) que contiene el módulo ModPuntuar, al que te remito: básicamente consiste en lo siguiente:

  • El comando PUNTUAR permite acceder al script PuntuarPrueba, el cual captura el valor del contador de las celdas F1 (G2) y F2 (G12) y se lo pasa a sendas subrutinas, una para puntuar cada una de las pruebas atendiendo a la edad del niño y a los datos estadísticos de los respectivos baremos.
  • Finalmente traslada los datos resultantes también a la hoja Datos.

Dada la extensión de estos script, remito al IDE para su lectura y análisis. La explicación que sea pertinente para retomar la actualización del soporte se realizará en ese momento.

Para finalizar ahora esta entrada, sólo resta señalar que la hoja Datos contiene una sencilla tabla de datos con los de identificación y los resultados de ambos test.

A partir de estos datos será posible crear una base de datos acumulativa, y desarrollar un modelo de informe de resultados, única fase de la automatización de este test que aunque ha sido desarrollada, no se muestra accesible mediante un botón de comando.

No obstante, si lo deseas y a modo de borrador, puedes generar un modelo de informe sobre Writer activando directamente el script DocumentosExternos ubicado en el módulo ModExternos.

Documento. Descarga del DocAp de la prueba

Notas:

1 En realidad también queda pendiente la generación de la base de datos, pero en este caso es más una cuestión de simplificación del procedimiento, mucho menos justificable que lo anterior.
2 Tiempo habrá de bajar expectativas, pero lo cierto es que, en esencia, es precisamente de lo que se trata aquí: ¿es posible diseñar contantemente alternativas de automatización basadas en el conocimiento (teóricamente) del experto?. ¿cuáles son realmente las alternativas disponibles?. Se comprenderá que, así presentada la cuestión, sea conveniente abordar este tema de forma específica. Bien vale una entrada... cuanto menos.