martes, 12 de mayo de 2020

Programando un comando de estimación en Stata: Funciones Mata.

David M. Drukker, Director Ejecutivo de Econometría.

Mostraré cómo escribir una función en Mata, el lenguaje de programación matricial que forma parte de Stata. Esta publicación utiliza conceptos introducidos en Programación de un comando de estimación en Stata: Mata 101.

Esta es la décimo segunda publicación de la serie Programando un comando de estimación en Stata. Te recomiendo que empieces por el principio.

Funciones Mata

Los comandos funcionan en Stata. Las funciones funcionan en Mata. Los comandos operan en objetos Stata, como variables, y los usuarios especifican opciones para alterar el comportamiento. Las funciones de Mata aceptan argumentos, operan en los argumentos y pueden devolver un resultado o alterar el valor de un argumento para contener un resultado.

Considere myadd() definido a continuación.


myadd() acepta dos argumentos, X y Y, coloca la suma de X y Y dentro de A, y devuelve A. Por ejemplo,

Ejemplo 1: Definir y usar una función




Después de definir myadd(), creo las matrices C y D, y paso C y D a myadd(), que devuelve su suma. Mata asigna la suma devuelta a W, la cual muestro. Tenga en cuenta que dentro de la función myadd(), C y D se conocen respectivamente como X e Y.

Solo se puede acceder a la A creada en myadd() dentro de myadd(), y no entra en conflicto con una A definida fuera de myadd(); es decir, A es local a la función myadd(). Ahora ilustraré que A es local para myadd().

Ejemplo 2: A es local a myadd()



Habiendo ilustrado que la A definida dentro de myadd() es local a myadd(), debo señalar que las matrices C y D que definí en el ejemplo 1 están en la memoria global de Mata. Al igual que en los programas ado, no queremos utilizar nombres fijos en la memoria global de Mata en nuestros programas para no destruir los datos de los usuarios. Afortunadamente, este problema se resuelve fácilmente escribiendo funciones Mata que escriben sus resultados en Stata y no devuelven resultados. Proporcionaré discusiones detalladas de esta solución en los comandos que desarrollé en publicaciones posteriores.

Cuando una función Mata cambia el valor de un argumento dentro de la función, eso cambia el valor de ese argumento fuera de la función; en otras palabras, los argumentos se pasan por dirección. Las funciones de Mata pueden calcular más de un resultado almacenando estos resultados en argumentos. Por ejemplo, sumproduct() devuelve tanto la suma como el producto basado en elementos de dos matrices.



sumproduct() retorna la suma de los argumento X y Y en el argumento S y el producto por elementos en P.

Ejemplo 3: Devolviendo resultados en argumentos






Después de definir sumproduct(), uso I() para crear A y uso rowshape() para crear B. Luego creo W y Z; cada uno es un valor escalar perdido. Debo crear W y Z antes de pasarlos como argumentos; de lo contrario, estaría haciendo referencia a argumentos que no existen. Después de llamar a sumproduct(), muestro W y Z para ilustrar que ahora contienen la suma y el producto de X y Y por elementos.

En myadd() y sumproduct(), no especifiqué qué tipo de cosa debe ser cada argumento, ni especifiqué qué tipo de cosa devolvería cada función. En otras palabras, utilicé declaraciones implícitas. Las declaraciones implícitas son más fáciles de escribir que las declaraciones explícitas, pero hacen que los mensajes de error y el código sean menos informativos. Recomiendo declarar explícitamente devoluciones, argumentos y variables locales para que su código y sus mensajes de error sean más legibles.

myadd2() es una versión de myadd() que declara explícitamente el tipo de cosa devuelta, el tipo de cosa que debe ser cada argumento y el tipo que debe ser cada cosa local a la función.



myadd2() devuelve una matriz numérica que se construye agregando la matriz numérica X a la matriz numérica Y. El objeto local A de la función es también una matriz numérica. Una matriz numérica es una matriz real o una matriz compleja; no puede ser una matriz de cadena.

La declaración explícita de devoluciones, argumentos y variables locales hace que el código sea más informativo. Inmediatamente veo que myadd2() no funciona con matrices de cadenas, pero esta propiedad está oculta en el código de myadd().

No puedo enfatizar lo suficiente la importancia de escribir código fácil de leer. Leer el código de otras personas es una parte esencial de la programación. Es instructivo y le permite adoptar las soluciones que otros han encontrado o implementado. Si eres nuevo en la programación, es posible que aún no te des cuenta de que después de unos meses, leer tu propio código es como leer el código de otra persona. Incluso si nunca le da su código a nadie más, es esencial que escriba un código fácil de leer para poder leerlo en una fecha posterior.

Las declaraciones explícitas también hacen que algunos mensajes de error sean más fáciles de rastrear. En los ejemplos 4 y 5, paso una matriz de cadena a myadd() y myadd2(), respectivamente.

Ejemplo 4: Pasando una matriz de cadena a myadd()



Ejemplo 5: Pasando una matriz de cadena a myadd2()



El mensaje de error en el ejemplo 4 indica que en algún lugar de myadd(), un operador o una función no pudieron realizar algo en dos objetos porque sus tipos no eran compatibles. No se deje engañar por la simplicidad de myadd(). Rastrear una falta de coincidencia de tipos en el código real puede ser difícil.

Por el contrario, el mensaje de error en el ejemplo 5 dice que la matriz C que pasamos a myadd2() no es una matriz real ni compleja como requiere el argumento de myadd2(). Al mirar el código y el mensaje de error, inmediatamente me informa que el problema es que pasé una matriz de cadena a una función que requiere una matriz numérica.

Las declaraciones explícitas son tan recomendables que Mata tiene una configuración que lo requiere, como se ilustra a continuación.

Ejemplo 6: Encendiendo matastrict



Establecer matastrict en on hace que el compilador Mata requiera que las variables de retorno y locales se declaren explícitamente. Por defecto, matastrict está desactivado, en cuyo caso las variables locales y de retorno pueden declararse implícitamente.

Cuando matastrict está activado, no es necesario que los argumentos se declaren explícitamente porque algunos argumentos contienen resultados cuyos tipos de entrada y salida pueden diferir. Considere makereal() definido y usado en el ejemplo 7.

Ejemplo 7: Cambiar un tipo de argumentos




La declaración de makereal() especifica que makereal() no devuelve nada porque void viene antes del nombre de la función. A pesar de que matastrict está activado, no declaré qué tipo de cosa debe ser A. Las dos líneas ejecutables de makereal() aclaran que A debe ser una cadena como elemento de entrada y que A será real como elemento de salida, lo que luego ilustraré.

Utilizo la función de que los argumentos pueden declararse implícitamente para que mi código sea más fácil de leer. Muchas de las funciones de Mata que escribo reemplazan los argumentos con resultados. Declaro explícitamente argumentos que son entradas, y declaro implícitamente argumentos que contienen salidas. Considere sumproduct2().


 


sumproduct2() no devuelve nada porque void viene antes del nombre de la función. El primer argumento X es una matriz real, el segundo argumento Y es una matriz real, el tercer argumento S se declara implícitamente y el cuarto argumento P se declara implícitamente. Mi convención de codificación de que las entradas se declaran explícitamente y que las salidas se declaran implícitamente de inmediato me informa que X y Y son entradas pero que S y P son salidas. Que X y Y son entradas y que S y P son salidas se ilustra en el ejemplo 8.

Ejemplo 8: Declarando explícitamente entradas, pero no salidas



Hecho y sin hacer

Mostré cómo escribir una función en Mata y discutí las declaraciones con cierto detalle. Escriba help m2_declarations para muchos más detalles.

En mi próxima publicación usaré las funciones de Mata para realizar los cálculos para un comando de estimación simple.

¡Gracias por leernos! 

Drukker, David. (22 de diciembre de 2015). Programming an estimation command in Stata: Mata functions. (Trad. Ángel Cruz). The Stata Blog. Not Elsewhere Classified. Recuperado de https://blog.stata.com/2015/12/22/programming-an-estimation-command-in-stata-mata-functions/

No hay comentarios.:

Publicar un comentario