Cómo crear una columna de promedio con JSL basada en columnas aleatoriasQuiero crear una lista de columnas basándome en ciertos criterios de selección. Los nombres de las columnas no se conocerán de antemano. Luego, usaré esa lista para crear una columna de fórmula que calcule la media (o desviación estándar o número) de esas columnas.
Script de ejemplo sencillo que toma todas las columnas numéricas:
dt = Open( "$SAMPLE_DATA/Cars.jmp" );
ColList = {};
For(i=1, i<=NCols(), i++,
If(Column(i)<
<GETDATATYPE></GETDATATYPE>
<BR /> <BR /> <P>Observe que ColList es una lista válida de columnas. Al insertarla en la fórmula de la primera columna, la vista previa en el editor de fórmulas muestra una evaluación correcta, pero la columna permanece vacía. Aparentemente, necesitamos insertar escalares, listas o matrices en la función Mean() (aunque la vista previa funcionará de todos modos).</P> <P><SPAN class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><span class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><img src="https://us.v-cdn.net/6038925/uploads/images/115064i3C11FFA7C1D866DE/pauldeen_0-1788272598908.png" role="button" title="pauldeen_0-1788272598908.png" alt="pauldeen_0-1788272598908.png" /></span><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN></P> <P>La segunda columna de fórmula agrega un AsColumn() alrededor de la referencia de columna... lo cual es un poco contraintuitivo ya que ya es una columna. Pero ahora crea una lista, escalar o matriz, y la fórmula mean() funcionará.</P> <P>Me parece que lo estoy complicando demasiado. ¿Existe una forma más sencilla de generar una columna de resumen de forma procedimental?</P>
Re: Cómo crear una columna de promedio con JSL basada en columnas aleatoriasNormalmente, en casos sencillos como este, uso Sustituir para reemplazar la lista con alguna otra expresión.
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Cars.jmp");
collist = dt << Get Column Names("Numeric", "String");
colrefs = Transform Each({colname}, collist,
Name Expr(As Column(dt, colname))
);
mexpr = Substitute(colrefs, Expr(List), Expr(Mean));
Eval(EvalExpr(
dt << New Column("AVG", Numeric, Continuous, Formula(
Expr(Name Expr(mexpr))
));
));
Write();
Re: Cómo crear una columna de promedio con JSL basada en columnas aleatoriasGracias, pero esta sigue siendo una solución avanzada para un problema sencillo. Me interesa saber si alguien encuentra una forma más simple de agregar referencias de columna a una fórmula de columna.
Re: Cómo crear una columna de promedio con JSL basada en columnas aleatoriasSupongamos que tenemos una columna llamada "TEST" en la tabla dt. Hay diferencias entre el "básico"
- Columna(dt, "PRUEBA")
- ComoColumna(dt, "PRUEBA")
- "PRUEBA"
- Nombre Expr(Como Columna(dt, "PRUEBA"))
Ver más...
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Cars.jmp");
Row() = 0; // default row value
col = "Size";
Show(col);
Show(Column(dt, col));
Show(AsColumn(dt, col));
Show(Name Expr(AsColumn(dt, col)));
Show(dt:col);
Show(AsName(col));
Write("\!N\!N");
Row() = 1;
Show(Column(dt, col)[Row()]);
Show(AsColumn(dt, col));
Show(Name Expr(AsColumn(dt, col)));
Show(dt:col);
Show(AsName(col));
¿Qué tipo de solución busca? No se añaden referencias de columna a las fórmulas a menos que se utilicen corchetes [] o [Row()] con la referencia. Si las columnas se obtienen como referencias (o cadenas de texto), generalmente deberá convertirlas en "accesos a columnas" para poder utilizarlas en las fórmulas.
Re: Cómo crear una columna de promedio con JSL basada en columnas aleatoriasEnvié un informe de error a JMP.
El problema radica en que la fórmula de columna no acepta argumentos del tipo Column("nombre"), sino que estos deben ir precedidos de una expresión As Column(). Al usar el editor de fórmulas visual, se arrastran columnas a los campos de argumentos, por lo que JSL debería reflejar el mismo comportamiento. Añadir esta funcionalidad a JSL simplificaría enormemente la creación de fórmulas de columna.
Aparentemente, la ventana de vista previa del editor de fórmulas sí interpreta esto correctamente, ya que muestra una vista previa.
Re: Cómo crear una columna de promedio con JSL basada en columnas aleatoriasColumn() y AsColumn()/:colname no son lo mismo y no deben usarse de manera similar.
En mi opinión, el problema reside en el editor de fórmulas y en cómo las muestra al crearlas con JSL. Omite fórmulas incorrectas (como en este caso) y no muestra mensajes de error cuando debería.
jthi_1-1788881236165.pngjthi_1-1788881236165.pngjthi_1-1788881236165.png
jthi_2-1788881243139.pngjthi_2-1788881243139.pngjthi_2-1788881243139.png
jthi_4-1788881274171.pngjthi_4-1788881274171.pngjthi_4-1788881274171.png
En este caso, debería mostrarse en las propiedades de la columna.
jthi_7-1788882167381.pngjthi_7-1788882167381.pngjthi_7-1788882167381.png
y esto en el editor de fórmulas
jthi_6-1788882151203.pngjthi_6-1788882151203.pngjthi_6-1788882151203.png
Y si intentas aplicarlo, aparece un error como este.
jthi_5-1788882131736.pngjthi_5-1788882131736.pngjthi_5-1788882131736.png
Si lo corriges a Column()[] se mostrará correctamente y devolverá resultados correctos.
jthi_0-1788880964367.pngjthi_0-1788880964367.pngjthi_0-1788880964367.png
Pero corresponde a los desarrolladores de JMP decidir cómo creen que debería comportarse esto.
Re: Cómo crear una columna de promedio con JSL basada en columnas aleatoriasJarmo plantea puntos importantes y ofrece una solución alternativa: usar Column("nombre")[]. Como bien dice Jarmo, usar Column("nombre")[] no se ve tan bien en el Editor de fórmulas. Mi solución a continuación no aborda esa opción, pero explica por qué resulta confusa para muchos usuarios. Repite gran parte de lo que Jarmo ya publicó, pero como ya lo tenía escrito...
En realidad, lo que muestra el script original no es un error. Se trata del comportamiento esperado, y evidencia una confusión común entre los usuarios respecto a la referencia a columnas y el funcionamiento de la evaluación de fórmulas de columna.
La clave de la confusión reside en comprender la diferencia entre la sintaxis `Column("nombre")` y la sintaxis `:nombre`. Ambas son formas válidas de referirse a columnas en ciertas circunstancias, pero lo que devuelven es diferente. Específicamente, `Column("nombre")` devuelve una referencia a un objeto de columna, mientras que `:nombre` devuelve el valor de la columna `nombre` en la fila actual. Por cierto, `:nombre` es la forma operacional de la función `As Column("nombre")`. En otras palabras, son exactamente lo mismo.
Considere el siguiente script de ejemplo para ilustrarlo. Este script presupone que tiene la tabla de datos Cars.jmp abierta y activa en su sesión de JMP.
Names Default To Here(1);
dt = Open( "$SAMPLE_DATA/Cars.jmp" );
// sending messages to a column; either syntax works
Column(dt, "Year") << Set Property("Range Check", LELE(87, 97));
dt:Head IC << Set Property("Spec Limits", {LSL( 150 ), Show Limits( 1 )});
// Return values
// returns a column object reference shown as Column( "Year" ) in log
Column(dt, "Year"); // returns Column( "Year" )
// returns value in Year column on the current row.
// Since current row is 0 (the default invalid row number), returns missing (.)
:Year; // returns .
// Set the current row to the first row
Row() = 1;
:Year; // returns 87
Teniendo en cuenta esta información, resulta evidente que JMP no puede calcular la media de un conjunto de referencias de columna. Por ello, la fórmula de la primera columna no se evalúa correctamente. La función Mean() necesita valores, que se proporcionan en la fórmula de la segunda columna. Al evaluar las fórmulas de columna, la tabla de datos asigna el valor 1 a la fila actual y, a continuación, evalúa la expresión almacenada en la propiedad Formula. El valor resultante se coloca en la celda de la columna correspondiente en la fila actual. Posteriormente, la fila actual se actualiza con el siguiente valor y el proceso se repite. Estos pasos se repiten hasta que la fórmula se evalúa para la última fila. Por consiguiente, la sintaxis de la fórmula de columna debe permitir la evaluación de cada fila de la tabla de datos.
En mi opinión, hay un resultado inesperado en tu script de ejemplo. La sintaxis `As Column(Column("name"))` se evalúa igual que `As Column("name")`. Esperaba que generara un error, pero JMP la acepta e interpreta la intención correctamente. Esa es la ventaja (a veces) de un lenguaje de scripting sobre un lenguaje de programación formal. Sin embargo, no recomendaría usar esta sintaxis, ya que podría fallar en el futuro.
Creo que la mejor manera de lograr el objetivo, según el script de ejemplo, es descartar el primer enfoque en la fórmula de columna y usar el segundo. El cambio adicional consiste en definir ColList como una lista de nombres de columna en lugar de referencias de columna. Aquí hay una versión modificada del script de ejemplo original que debería ser robusta.
dt = Open( "$SAMPLE_DATA/Cars.jmp" );
ColList = {};
For( i = 1, i <= N Cols(), i++,
If( Column( i ) << GetDataType == "Numeric",
Insert Into( ColList, <FONT color="#FF6600"><STRONG>Column( i ) << Get Name</STRONG></FONT> )
)
);
MeanExpr2 = Name Expr( Mean() );
For( i = 1, i <= N Items( ColList ), i++,
Insert Into( MeanExpr2, Name Expr( As Column( ColList[i] ) ) )
);
Eval( Eval Expr( dt << New Column( "Average of numerics 2", Formula( Expr( Name Expr( MeanExpr2 ) ) ) ) ) );
Re: Cómo crear una columna de promedio con JSL basada en columnas aleatoriasSi bien desde un punto de vista teórico y mecánico probablemente tengas toda la razón, la interfaz de usuario no se comporta así. Selecciono columnas de la tabla y las arrastro al operador mean() para que calcule. Sin embargo, al programar, no puedo seleccionar columnas, sino que tengo que seleccionar objetos de cadena (que corresponden a los nombres de las columnas) y luego indicarle a JSL que los interprete como referencias a las columnas, las cuales puedo insertar en el operador mean(). ¿No sería sencillo modificar los operadores JSL para que traten Column("Name") como objetos de columna indexados a la fila? Esto sería mucho más intuitivo y reflejaría el comportamiento de la interfaz de usuario y, por lo tanto, la forma de pensar del usuario. Como bien señalaste, existe mucha confusión entre los usuarios al respecto.
Y en relación con lo que comenta Jarmo: los mensajes de error en el editor de fórmulas necesitan mejoras en cuanto a claridad y coherencia. Cabe destacar que la vista previa muestra una evaluación correcta, pero la fórmula no se evalúa al usar la sintaxis Column("Name").