Actualización a MMS_0.6
Transformaciones
El uso de las transformaciones (@MMS.Transformation
) de MMS_0.5 en los proyectos ha sido muy variopinto
dada la flexibilidad que ofrecían a los usuarios. Sin embargo, su diseño original
no estaba pensado para ello y esto conlleva algunas dificultades sobre todo
de cara a la persistencia. En MMS_0.6 las transformaciones se modifican y asumen un
papel más definido y estricto, destinado a las transformaciones invertibles propias
de la linealización de los modelos.
A continuación describimos cómo ha de modificarse la programación para conseguir los mismos resultados:
Transformación del Output
La transformación del output no suele presentar la flexibilidad en las transformaciones que comentábamos y se limita a la familia de transformaciones BoxCox. Éstas están implementadas en MMS_0.6.
Código en MMS_0.5
@MMS.Transformation _.transformation = BoxCox(0,0);
Código en MMS_0.6
Construcción de la transformación:
// Modo 1 MMS::@Transformation _.transformation.1 = MMS::@Transformation.BoxCox::Default(0,0); // Modo 2 MMS::@Transformation _.transformation.2 = MMS::@Transformation::Family("BoxCox", [[0,0]]); // Nombre de la transformación Text _.transformation.2::GetName(?); //> "BoxCox_0.0"
Alternativa en los argumentos de una MVariable:
// Modo 1 ó 2 NameBlock [_.output|_.input] = [[ ... MMS::@Transformation _.transformation = ... ... ]] // Modo 3 (por nombre) NameBlock [_.output|_.input] = [[ ... Text _.transformationLabel = "BoxCox_0.0"; ... ]]
Transformación del Input
La transformación del input es algo más delicada ya que en sus transformaciones se usaban funciones de distinto tipos que no sólo transformaban los datos sino que los ampliaban o recortaban.
MMS_0.6 no acepta esto en las transformaciones de modo que para ello hay que acudir a mecanismos del módulo de variables. Quizá hay varias maneras de solucionar esta situación e incluso puede ser muy interesante considerar el uso que se ha hecho en algunos proyectos de las transformaciones para enriquecer más el módulo de variables.
A través de Variables Calculadas
A continuación proponemos una solución basada en la construcción de variables calculadas cuando se presente la necesidad de transformar una variable.
Código en MMS_0.5
El código que nos ocupa se separa en dos partes:
(i) donde se definen constructores específicos para las transformaciones del proyecto:
/////////////////////////////////////////////////////////////////////////////// @MMS.Transformation MMC_ExtendedNormalizeBoxCox(Real first, Real second, Date dat) ////////////////////////////////////////////////////////////////////////////// { @MMS.Transformation::Block(NameBlock { NameBlock args = [[ Text _.name = "MMC_ExtendedNormalizeBoxCox"<<first<<"_"<<second; Text _.grammar = "Serie"; Text _.contextExpression = " Real _.first = "<<first<<"; Real _.second = "<<second<<"; "; Text _.directExpression = If(first==0, "Serie (Serie s) { MMC_NomalizeExtendSerLastValue("+FormatDate(dat)+", Log(s + _.second)) }", "Serie (Serie s) { MMC_NomalizeExtendSerLastValue("+FormatDate(dat)+", ((s + _.second)**_.first - 1)/_.first ) }" ); Text _.inverseExpression = If(first==0, "Serie (Serie t) { MMC_NomalizeExtendSerLastValue("+FormatDate(dat)+", (Exp(t) - _.second) ) }", "Serie (Serie t) { MMC_NomalizeExtendSerLastValue("+FormatDate(dat)+", ((_.first * t + 1)**(1/_.first) - _.second) )}" ) ]] }) }; PutDescription(" Aplica una transformación logarítmica a la serie, la normaliza a la fecha dat y la extiende en previsión con el última dato", MMC_ExtendedNormalizeBoxCox );
(ii) y donde se utilizan las transformaciones:
Text variableName = ...; Real model::CreateBaseExpTermOmega([[ ... Text _.variableName = variableName ; @MMS.Transformation _.transformation = transformation; // donde: // transformation = MMC_ExtendedNormalizeBoxCox(0, 0, modelBegin) ... ]]);
Código en MMS_0.6
Como alternativa a
(i) los constructores específicos proponemos la creación de nuevas funciones:
/////////////////////////////////////////////////////////////////////////////// Serie MMC_ExtendedNormalizeBoxCox(Serie s, Real first, Real second, Date dat) ////////////////////////////////////////////////////////////////////////////// { If(first==0, MMC_NomalizeExtendSerLastValue(dat, Log(s+ second)), MMC_NomalizeExtendSerLastValue(dat, ((s + second)**first - 1)/first) ) }; PutDescription(" Aplica una transformación logarítmica a la serie s, la normaliza a la fecha dat y la extiende en previsión con el último dato", MMC_ExtendedNormalizeBoxCox );
(ii) mientras que en la construcción de los términos explicativos (en MMS_0.6 no se pasa por la creación de un término base) se ha de construir "en tiempo de definición" una nueva variable cuando sea necesario, es decir cuando la transformación no sea la identidad:
Text variableName = ...; MMS::@Variable vc = model::GetDataSet(?)::CreateVariable([[ ... Text _.name = variableName<<"_Transformed"; Text _.type = ...; Text _.expression = transformationExpression; // donde: // transformationExpression = "MMC_ExtendedNormalizeBoxCox(%1, 0, 0, <modelBegin>)" // %i hace referencia a la i-ésima dependencia Set _.dependences = [[ variableName ]] ]]); Anything submodel::CreateExpTerm_TransferFunction([[ ... NameBlock _.input = [[ Text _.name = <name>; Text _.variableIdentifier = variableName<<"_Transformed" ]]; ... ]])
En ausencia de transformación sería simplemente:
Text variableName = ...; Anything submodel::CreateExpTerm_TransferFunction([[ ... NameBlock _.input = [[ Text _.name = <name>; Text _.variableIdentifier = variableName ]]; ... ]])