Mostrando entradas con la etiqueta Funciones. Mostrar todas las entradas
Mostrando entradas con la etiqueta Funciones. Mostrar todas las entradas

miércoles, 26 de noviembre de 2025

Evaluación.

Automatización de la evaluación

Corrección del test



La aplicación de la prueba no es la única fase que nos interesa automatizar; es más, es posible que ni siquiera interese automatizarla o no merezca la pena el esfuerzo que implica. Pero de lo que sí podemos estar seguros es que sí es posible e interesante automatizar la corrección del test. 

De hecho es la automatización de este subproceso la que mayor interés despierta en las editoriales. Al menos así es para algunas que ofrecen servicios de corrección on-line que asocian a la adquisición de los cuadernillo (doble negocio) y llegan a omitir los datos que permitirían lo corrección y/o la puntuación de la prueba para forzar al uso de sus servicios de corrección. Una práctica totalmente legal, por lo visto, pero moralmente más que cuestionable, pienso. 

Es cierto que estas plataformas de corrección ofrecen un servicio que va más allá de la mera corrección de la prueba, incluyendo la valoración de los resultados y la devolución de un informe técnico-descriptivo de los mismos. De paso la empresa, si así lo desea, puede recopilar gratuitamente los datos que precisa para mejorar la baremación de la prueba, ahorrándose los gastos correspondientes.

Dejando estas cuestiones al margen y volviendo a lo que nos interesa, decir que automatizar la corrección de una prueba puede realizarse mediante el servicio Calc sin necesidad de emplear script OOo Basic. Para las formas más básicas de corrección, puede ser suficiente con las funciones que incorpora la propia hoja de cálculo. 

De hecho, de este modo se han construido muchos soportes de digitalización de la evaluación, sin ser conscientes de estar avanzando en la automatización de la prueba. Esta automatización es necesariamente parcial, pero real. Por ese motivo el tratamiento de muchos de los recursos de evaluación que presento en las secciones correspondientes del blog se inicia con esos soportes Calc.

No obstante, para realizar el análisis de datos (la fase  siguiente en este proceso hacia la automatización) es necesario algo más que las funciones Calc, lo que lleva a la creación de código. Y una vez "metidos en harina", resolver la corrección de la prueba mediante script puede resultar más lógico y hasta más sencillo que hacerlo mediante funciones Calc. También contribuyen a ello los distintos tipos de ítem. 

Quien dice programar en OOo Basic dice también hacerlo en otros lenguajes. Python es una buena alternativa.

sábado, 4 de octubre de 2025

Lenguajes. Python.


Funciones built-in en Python




Al igual que en OOo Basic, también Python dispone de una colección de funciones incorporadas en el propio lenguaje (funciones built-in). Te las presento en esta entrada.

Puedes encontrar un listado y la explicación de su funcionamiento [en esta página]

A continuación te presento el listado de contenidos para facilitarte el acceso a la explicación de aquella que te interese especialmente (1).



NOTA (1) Listado ordenado alfabéticamente en columnas copiado de la referencia indicada.

sábado, 13 de septiembre de 2025

Lenguajes. Python.

Funciones de cadena en Python: división y unión de elementos


Para separar y unir los elementos que componen una cadena de texto Python dispone de algunas funciones específicas que facilitan esta tarea. Dedicaremos entra entrada a experimentar con esas funciones que tanta utilidad van a tener en la automatización del trabajo con textos.


Vamos a empezar por la segmentación de una cadena, proceso en el que empleamos la función split(). Esta función nos permite dividir una cadena en segmentos en función de un separador (el que nosotros decidamos), que en caso de no especificar ninguno será directamente el espacio que separa las palabras. Un ejemplo.

Supongamos el siguiente texto asignado a la variable:

texto = "Una narración breve en prosa es un texto corto que cuenta una historia usando el lenguaje no métrico o rítmico, y que puede ser un cuento, un microrrelato o una fábula\n. Estas formas literarias se caracterizan por su concisión y la condensación de eventos en un formato limitado, buscando captar la atención del lector mediante la intensidad de la historia, un final inesperado o una enseñanza moral." 

Tomando este texto como objetivo, vamos a analizarlo en términos de posible segmentación. 
  • En primer lugar, podemos dividirlo en función de las palabras (lista1); para ello emplearemos split() sin determinar separador (lista1 = texto.split())
  • La segunda división puede ser dividirlo en función del punto (lista2), para lo que explicitaremos el elemento divisor (lista2 = texto.split('.'))
  • En tercer lugar, podemos dividir el texto en función del salto de línea (\n), que equivale a los párrafos que componen el texto. En este caso tenemos dos opciones (el resultado es el mismo):
    • Mediante la identificación directa del separador (lista3 = texto.split('\n'))
    • O mediante el uso de la función splitlines() (lista4 = texto.splitlines())
Podemos obtener un resultado confirmatorio de la ejecución de las diferentes instrucciones obteniendo el número de elementos de las distintas listas (v.g. n_pal = len(lista1)n_seg = len(lista2)) y mostrar a continuación el resultado de len() por pantalla (v.g. print (f'Número de elementos de la lista 1 ->  {n_pal}')), o también puedes hacerlo mostrando directamente los diferentes segmentos de las distintas listas mediante un bucle que las recorre:

i = 0
for i in range(n_pal):
    print(lista1[i])

Pasemos ahora a explicar el proceso inverso, consistente en unir lo que hemos separado previamente. Para ello disponemos de dos procedimiento que explico a continuación.

La primera forma consiste en utilizar un bucle cuya expresión más simple (pero no la única) es la siguiente, que incluye declaración de variables y escritura del resultado por pantalla:

i = 0
texto_1 = ""
for i in range(n_pal):
    texto_1 = texto_1 + lista1[i] + ' '
print(texto_1)

El núcleo de este procedimiento es la asignación recursiva del contenido de la lista sobre la variable contenedora (texto_1 = texto_1 + lista1[i] + ' ')

La segunda fórmula se basa en el uso de la función join()  que  nos ahorra el bucle y cuya sintaxis es la siguiente...

variable_de_asignación_de_cadena =  "separador".join(lista)

... que traducido a un caso concreto se muestra como sigue (incluyendo declaración de variable contenedora e instrucción de escritura por pantalla:

texto1 = ""
texto1 = " | ".join(lista1)
print(texto1)

viernes, 8 de noviembre de 2024

Datos. OOo Basic.

Puntuaciones típicas derivadas

Dado que las puntuaciones típicas (puntuaciones z) (pt en adelante) pueden ser de difícil interpretación, podemos expresar esta normalización de las puntuaciones de forma que resulte más fácilmente interpretable. Para ello utilizamos las puntuaciones típicas derivadas (pt_d en adelante). En esta entrada desarrollaré una función OOo Basic para su cálculo.


Sin entrar en demasiados detalles sobre conceptos estadísticos que no corresponden en este blog (1), diremos que una pt_d es la transformación de una pt, habiendo establecido a priori un valor para el promedio (md) de esa distribución y una desviación típica o estándar (dt en adelante). En función de la pt_d con que trabajemos, esos valores serán diferentes, pero el sistema o fórmula para el cálculo o conversión de la pt a pt_d es siempre el mismo aunque se puede expresar de formas diferentes: pt_d = dt * pt + med (2)

Son varias las escalas de puntuaciones típicas derivadas, aunque las usadas con más frecuencia son:
  • Las puntuaciones CI. md  100, dt  15
  • Las puntuaciones escalares (pe). md 10, dt 3 (límites 1-19)
  • Las puntuaciones T. md 50, dt 10
  • Las puntuaciones S (estaninos o eneatipos). md 5, dt 2 (límites 1-9)
  • Las puntuaciones decatipo. md 5.5, dt 2 (límites 1-10)
Partiendo de estas referencias, me propongo crear una función que calcule y devuelva (return) la puntuación típica derivada de una puntuación z (pt) (3). Este es el código de la función CalptDev()

Function CalptDev(pz As single, tipoptd As String) As Integer

Dim mPtDeriv() As String, mPtMed () As Single, mPtDt () As Integer
Dim i As Integer
Dim cat As String
Dim vPtDev

mPtDeriv() = Array ("CI","pe","T","S","Dc")
mPtMed () = Array(100,10,50,5,5.5)
 mPtDt () = Array(15,3,10,2,2)

Select Case tipoptd
Case = "CI"
cat = mPtDeriv(0)
Case = "pe"
cat = mPtDeriv(1)
Case = "T"
cat = mPtDeriv(2)
Case = "S"
cat = mPtDeriv(3)
Case = "Dc"
cat = mPtDeriv(4)
End Select

For i = 0 To UBound(mPtDeriv())
If cat = mPtDeriv(i) Then
vPtDev = pz * mPtDt (i) + mPtMed (i)
End If
Next

CalptDev = vPtDev

End Function

Como podemos ver, CalptDev() recibe dos parámetros (pz As single, tipoptd As String): el valor z (pt) a convertir en pt_d y el tipo de puntuación típica derivada (CI, T, S...)

Cuenta además con tres matrices (mPtDeriv(), mPtMed () mPtDt()) que contienen los datos de las puntuaciones típicas derivadas: identificador, promedio y desviación típica, los cuales son establecidos posteriormente mediante la función Array (v.g. mPtDeriv() = Array ("CI","pe","T","S","Dc")). También cuenta con tres variables: un contador (i) para correr el bucle For, una variable (cat) cuya función explico a continuación, y la variable que recogerá el resultado de la función (vPtDev) y que se asocia al return (CalptDev = vPtDev).

Lo primero que hacemos es concretar el tipo de escala asociando la variable cat  al contenido de la matriz mPtDeriv() en función del valor del parámetro tipoptd a mediante el condicional Select Case. De este modo hacemos uso de la matriz indicada para asignar contenido a la variable que nos permitirá establecer la equivalencia entre la entrada del citado parámetro con las posiciones de las matrices, usando (por segunda vez) la matriz mPtDeriv() como referencia.

Esto se desarrolla en la estructura For que sigue, mediante la cual, según el valor de cat, y en el momento en que sea igual al contenido de la matriz mPtDeriv(), y por medio de un condicional If (If cat = mPtDeriv(i) Then), se procede a aplicar la fórmula del cálculo de la puntuación típica derivada  pt_d = pt * dt + med (vPtDev = pz * mPtDt (i) + mPtMed (i)).

Obsérvese el uso de las matrices que contienen los valores dt y med (mPtMed () mPtDt()) y el papel que juega en este procedimiento el posicionamiento de los datos, o lo que es lo mismo, la importancia del contador i en este procedimiento. Es gracias a todo ello que podemos automatizar la correcta aplicación de los valores (dt y med) que corresponden sin necesidad de aplicar otras estructuras condicionales más complejas y, demás, de forma repetida.

Para facilitar el uso de esta función y ofrecer un modelo de funcionamiento concreto, muestro a continuación el código de un script de llamada y paso de parámetros a esta función. Observa que se utilizan procedimientos para la entrada dinámica de datos (4):

Sub ptDerivada

Dim pt As Single, pt_deriv As String, ptDer As Integer

pt = CSng(InputBox ("Puntuación z","Valor de la puntuación típica"))

pt_deriv = InputBox(" Puntuación CI (CI)" & Chr(13) & "Punt. escalar (pe)" & Chr(13) & "Punt. T (T)" & Chr(13) & "Punt S o estanino (S)" & Chr(13) & "Puntuación decatipo (Dc)","Escala o índice de la puntuación típica derivada","CI")

ptDer = CalptDev(pt,pt_deriv)

MsgBox ("Puntuación típica " &  pt & CHr(13) & "Puntuación " & pt_deriv & " " & ptDer,0,"PUNTUACIÓN TÍPICA DERIVADA")

End Sub


NOTAS

(1) Sobre el tema se pueden consultar otras fuentes en la web. Entre otras recomiendo por su corrección y sencillez expositiva [A Ruiz Bueno (UB)] a título de introducción al tema.
(2) Otra fórmula en que es frecuente expresar esta transformación es pt_d = med +/- pt * dt. el uso de los signos alternativos +/- hace referencia a que del resultado de la operación pt * dt puede resultar un valor positivo, si pt es +pt, o negativo si es -pt; esto es: si la puntuación z (valor concreto de pt[ver entrada anterior] deriva de una puntuación directa superior o inferior a la media grupal.
(3) Aunque no se trata de crear ahora un docap, sí será necesario crear un script simple que llame a la función, ya que, como sabemos, las funciones no devuelven nada si no son llamadas desde un script, subrutina u otra función.
(4) IMPORTANTE: el valor de la puntuación z que se solicita asociado a la variable pt, (pt = CSng(InputBox ("Puntuación z","Valor de la puntuación típica"))) que será muy probablemente un valor decimal y debe escribirse separando por coma la unidad de la parte decimal; la función de conversión CSng() se encarga de convertir este valor (String) en Single. NO se debe emplear el punto como separador, ya que provoca un resultado incorrecto. 

lunes, 28 de octubre de 2024

Lenguajes. Python.

Cadenas f


En otra entrada pudimos ver un modo peculiar de escribir el contenido de una instrucción print()print(f"{self.nombre} se sienta cuando se lo ordeno (y quiere, claro)."). Se trata de la llamada cadena f, formato en uso desde la versión Python 3.6, que sustituye al método format(), y que, al igual que éste, permite utilizar directamente variables dentro de cadenas.


Pero antes de continuar es necesaria una aclaración: tanto format() como las cadenas f nos remiten a las variables alfanuméricas, y más concretamente a los string como objetos, instancias de una clase (la clase string), por lo que format() se considera método específico de esta clase, al igual que otros muchos, como upper() y lower()tittle() y otros muchos otros. Ahora no me voy a detener en ellos, pero te dejo acceso a esta página en la que puedes entrar en mas detalle sobre esos métodos y la forma en que se usan. También te recomiendo esta otra página, mucho más completa, en la que puedes encontrar información técnica sobre los string y esta otra relacionada con la anterior y más genérica aun, sobre la biblioteca estándar de Python.

Volviendo a las cadenas f y su uso para concatenar cadenas incluyendo variables, recuerda que ya en OOo Basic nos mostramos especialmente interesados en este tipo de operaciones, debido a que, por funciones, trabajamos con frecuencia con documentos y necesitamos métodos prácticos y funcionales para componer textos. Un ejemplo de ello es construir un documento-tipo y personalizarlo a partir de información contenida en variables. 

El procedimiento combinar correspondencia es una forma de abordarlo que ya hemos utilizado como solución en otras propuesta. También hemos utilizado procedimientos de construir textos mediante la unión de cadenas y variables en Python, pero no haciendo uso de las cadenas f, así que me parece de interés que nos detengamos brevemente en ellas para comprender su funcionamiento.

Las cadenas f permiten introducir variables dentro de cadenas, simplificando y sobre todo, clarificando procedimientos de mayor más comunes, pero menos eficiente. Veamos cómo proceder suponiendo la creación de un script que genera un texto personalizado a partir de un documento-base como los que generamos como docap mediante OOo Basic. Aunque me limitaré a un único párrafo (por no alargar innecesariamente la propuesta), utilizaré los dos procedimientos disponibles en Python (el ordinario de concatenación y las cadenas f) para comprobar la funcionalidad de ambos procedimientos.

El texto-base es el siguiente:

Observaciones: Este informe se realiza a demanda de la Dirección del centro (12/10/2022) por petición de  tutoría, formulada mediante PROPUESTA DEL EQUIPO DOCENTE DE SOLICITUD DE EVALUACIÓN PSICOPEDAGÓGICA (10/10/2022).

Este texto, aunque no excesivamente, es suficientemente complejo para que resulte interesante explorar las opciones de concatenación de texto según lo formulado antes como propuesta: contiene el volumen suficiente de texto fijo y de texto variable (a tratar mediante variables), y supone un ejercicio de concatenación de variables tipo string.

Suponiendo las variables siguientes y sus valores asignados...

demandante = "la Dirección del centro"
fechaDemanda = "12/10/2022"
peticion = "tutoría"
fechaPeticion = "12/10/2022"
fechaInforEqDoc = "11/10/2022"

... la formulación mediante cadenas concatenadas es como sigue:


print("Observaciones: Este informe se realiza a demanda de ", 
demandante, "(", fechaDemanda,") por petición de ", peticion, "(", fechaPeticion, "), mediante PROPUESTA DEL EQUIPO DOCENTE DE SOLICITUD DE EVALUACIÓN PSICOPEDAGÓGICA (",fechaInforEqDoc,")")

... mientras que usando cadenas f se construye del siguiente modo:


print(f"Observaciones: Este informe se realiza a demanda de {demandante}, ({fechaDemanda} ) por petición de {peticion} ({fechaPeticion}, mediante PROPUESTA DEL EQUIPO DOCENTE DE SOLICITUD DE EVALUACIÓN PSICOPEDAGÓGICA ({fechaInforEqDoc})")

En ambos casos el resultado es el mismo:

Observaciones: Este informe se realiza a demanda de la Dirección del centro, (12/10/2022 ) por petición de tutoría (12/10/2022, mediante PROPUESTA DEL EQUIPO DOCENTE DE SOLICITUD DE EVALUACIÓN PSICOPEDAGÓGICA (11/10/2022)

... pero el uso de la cadena f permite que nos olvidemos del tedioso y confuso proceso de  abrir y cerrar comillas (que en la concatenación clásica identifico mediante la escritura en dos colores), fuente de errores, lo que hace que sea más sencillo y fluido escribir el texto final dentro de la función print().