Principiante que intenta escribir un script / ¿Cómo iterar dentro de la función de fórmula?Hola, soy un principiante en la escritura de scripts en cualquier lenguaje. Actualmente estoy deambulando por lo que pensé que sería una tarea práctica simple. Estoy usando JMP18. Mi objetivo es automatizar una operación de rutina que hago con conjuntos de datos en crecimiento a lo largo del tiempo. La operación de rutina es determinar primero la escala de tiempo y luego mostrar el cambio en los datos a lo largo de esa escala de tiempo para conjuntos de datos grandes. La forma básica en que estoy abordando esto es creando nuevas columnas para completar todos los datos iniciales y usando fórmulas en más columnas para obtener diferencias. Si alguien tiene una mejor sugerencia, se lo agradecería. A continuación se muestra dónde estoy:
Básicamente, tengo un conjunto de datos y quiero lograr lo siguiente.
1) Estoy buscando tomar las columnas de fecha y hora, unirlas en una sola columna y luego encontrar el mínimo y usarlo para crear una fecha de inicio. Luego puedo restar las horas para ver la diferencia de tiempo entre los datos. Todo esto fue bastante simple con las funciones formula(). Todo aquí funciona muy bien.
2) Quiero hacer algo similar con varias de las columnas de datos, pero no puedo hacer lo que hice antes para encontrar el valor inicial. Los datos iniciales están determinados por el tiempo mínimo encontrado en lo que hice antes para cada elemento único en una tercera columna (llamada Unique_Fruit en el código a continuación). Para el bien de este foro, para cada unique_fruit, quiero crear una columna que contenga los valores iniciales de los datos para esa fruta para poder calcular rápidamente los cambios a partir de la columna de datos real.
Mi script JSL actual se muestra a continuación. Tengo una fórmula de código ficticio en la que no he descubierto qué hacer. Son los pasos en los que utilicé la función If, descubrí que los tiempos son iguales entre sí y establecí el valor solo para esas celdas. Mi idea original era intentar usar un bucle for e iterar en la fórmula, pero eso no pareció funcionar.
DataTable = Current Data Table();
New Column( "Date Number Format", Numeric, "Continuous" );
For( i = 1, i <= N Rows( DataTable ), i++,
DataTable:Date Number Format[i] = Num( DataTable:Key_Date[i] );
);
New Column( "Time Number Format", Numeric, "Continuous" );
For( i = 1, i <= N Rows( DataTable ), i++,
DataTable:Time Number Format[i] = Num( DataTable:Key_Time[i] );
);
New Column( "Current_Time", Numeric, "Continuous" );
For( i = 1, i <= N Rows( DataTable ), i++,
DataTable:Current_Time[i] = DataTable:Date Number Format[i] + DataTable:Time Number Format[i];
);
New Column( "Unique_Fruit", Character, "Nominal" );
For( i = 1, i <= N Rows( DataTable ), i++,
DataTable:Unique_Fruit[i] = DataTable:Fruit[i] || "-" || DataTable:Type[i];
);
New Column( "Starting_Date_Number_Format", Numeric, "Continuous",
Formula( Col Minimum( :Current_Time, :Unique_Fruit ) )
);
New Column( "Minutes", Numeric, "Continuous",
Formula( Date Difference( :Starting_Date_Number_Format, :Current_Time, "Minute", "fractional" ) )
);
New Column( "Days", Numeric, "Continuous",
Formula( Date Difference( :Starting_Date_Number_Format, :Current_Time, "Day", "fractional" ) )
);
New Column( "Weeks", Numeric, "Continuous",
Formula( Date Difference( :Starting_Date_Number_Format, :Current_Time, "Week", "fractional" ) )
);
New Column( "Months", Numeric, "Continuous",
Formula( Date Difference( :Starting_Date_Number_Format, :Current_Time, "Month", "fractional" ) )
);
New Column( "Initial_Taste", Numeric, "Continuous",
Formula(
If( :Current_Time == :Starting_Date_Number_Format, :Key_Taste, . )
)
);
For( i = 1, i <= N Rows( DataTable ), i++,
If( DataTable:Current_Time[i] == DataTable:Starting_Date_Number_Format[i],
DataTable:Initial_Taste[i] = DataTable:Key_Taste[i];
);
);
New Column( "Delta_Taste", Numeric, "Continuous",
Formula( :Key_Taste - :Initial_Taste )
);
New Column( "%_Change_Taste", Numeric, "Continuous",
Formula( ( :Delta_Taste / :Initial_Taste ) * 100 + 100 )
);</CODE></P><BR /></LINGO-BODY><LINGO-LABS id="lingo-labs-844919" slang="en-US" mode="CREATE"><LINGO-LABEL>Automatización y scripting</LINGO-LABEL></LINGO-LABS><LINGO-SUB id="lingo-sub-844929" slang="en-US" mode="CREATE">Re: Principiante que intenta escribir un script / ¿Cómo iterar dentro de la función de fórmula?</LINGO-SUB><LINGO-BODY id="lingo-body-844929" slang="en-US" mode="CREATE"><P>¿Puedes proporcionar un ejemplo de conjunto de datos + columna con la respuesta correcta? Lo más probable es que puedas obtener los valores iniciales usando algo como esto, pero debes modificar la comparación ya que esta obtiene el primer valor para cada categoría.</P>
<BR />
<PRE><CODE class=" language-jsl">Col Cumulative Sum(If(Row() == Col Min(Row(), :age), :height, .), :age)
donde :age es unique_fruit y :height es la columna de valores. También puedes utilizar Lag() y variables.
También hay algunos cambios que haría en tu script para hacerlo un poco más robusto.
- Comience su script con Nombres predeterminados aquí (1);
- Como tienes referencia a una tabla de datos, úsala.
- DataTable << Nueva Columna(...
- También consideraría cambiar DataTable a dt o algo similar, ya que JMP tiene una función llamada Datatable()
- Al recorrer una tabla de datos, utilice For Each Row en lugar de For, ya que es su caso de uso especial.
- Cuando desea tener nuevas columnas en la tabla JMP sin tener fórmulas, tiene algunas opciones:
- Usar la combinación Nueva columna + Fórmula + ejecutar fórmulas + eliminar fórmula
- Crea una nueva columna y recorre la tabla de datos (como lo estás haciendo)
- Luego hay un método un poco delicado de usar << Aplicar fórmula, pero yo me quedaría con esos primeros (normalmente uso el primero)
Re: Principiante que intenta escribir un script / ¿Cómo iterar dentro de la función de fórmula?Bienvenido a la Comunidad.
Estoy de acuerdo con Jarmo, una tabla de datos de muestra.
También te sugiero que proporciones un ejemplo simulado de cuáles son los resultados esperados.
Re: Principiante que intenta escribir un script / ¿Cómo iterar dentro de la función de fórmula?Gracias por la sugerencia. Estoy intentando crear un conjunto de datos simulado y lo que hago actualmente de forma manual. Para establecer los valores iniciales, miro cada elemento único y solicito los datos de esa celda y completo toda la columna para luego poder pasar a la siguiente parte del cálculo. Intentaré actualizar el resto del script con tus sugerencias también, pero creo que el problema principal aún no está resuelto para mí (o aún no lo he entendido).
Re: Principiante que intenta escribir un script / ¿Cómo iterar dentro de la función de fórmula?Hola @bub , echa un vistazo a https://marketplace.jmp.com/appdetails/Normalization+GUI
Facilita la tarea de normalizar datos por un valor inicial (restar o dividir) - por grupo.
Re: Principiante que intenta escribir un script / ¿Cómo iterar dentro de la función de fórmula?No se resolvió porque, por lo general, lleva más tiempo crear datos de simulación que responder la pregunta correcta . Deberías poder utilizar algo como esto para los valores iniciales.
Col Min(If(:Date Number Format == Col Min(:Date Number Format, :Unique_Fruit), :Key_Taste, .), :Unique_Fruit)
Esta no es la única forma de construirlos, pero algo como esto funciona con bastante frecuencia.
Re: Principiante que intenta escribir un script / ¿Cómo iterar dentro de la función de fórmula?Muchas gracias. Solo para aclarar, no estaba tratando de culpar a tu primera respuesta, sino que estaba tratando de implementarla en algunas iteraciones y pensé que todavía me faltaba algo. Debería haber seguido porque probablemente hubiera terminado en la respuesta que mostraste aquí (eventualmente), pero como dije antes, soy nuevo en la creación de scripts para estas cosas, así que es un proceso lento.
Por curiosidad, ¿por qué tiene el "." en el else?
Re: Principiante que intenta escribir un script / ¿Cómo iterar dentro de la función de fórmula?El valor faltante está ahí para intentar "forzar" a Col Min a tener solo una opción para elegir, ya que ignorará los valores faltantes.
Puedes dividir este tipo de fórmulas en varias partes para intentar comprenderlas mejor (a veces aún pueden ser muy crípticas).
//col1
Col Min(:Date Number Format, :Unique_Fruit)
//col2
:Date Number Format == :col1
//col3
If(:col2, :Key_Taste, .)
//col4
Col Min(:col3, :Unique_Fruit)

Re: Principiante que intenta escribir un script / ¿Cómo iterar dentro de la función de fórmula?En el futuro, tareas como ésta serán súper fáciles:
https://community.jmp.com/t5/JMP-Wish-List/Group-by-sooo-useful-how-about-Interpolate/idc-p/828679/highlight/true#M6896
Junto con Col Interpolate, se agregarán muchas funciones (y funcionalidades) nuevas a las agregaciones Col:)
Re: Principiante que intenta escribir un script / ¿Cómo iterar dentro de la función de fórmula?Hola, se me ocurrió una idea adicional mientras estaba jugando con esto. Si quisiera hacer algo más parecido a lo que originalmente pensé que tenía que hacer cuando publiqué esto, ¿cómo se hace? Lo que estoy haciendo es escribir una variable que almacena una lista y luego intentar que el código itere a través de esa lista para completar la fórmula. En lugar de completar la fórmula, la variable permanece dentro de la fórmula en lugar de actualizarse a uno de los valores de la lista. ¿Es algo que se puede hacer dentro de la función de fórmula?
Re: Principiante que intenta escribir un script / ¿Cómo iterar dentro de la función de fórmula?Gracias por la explicación. Estoy experimentando con ella mientras continúo con este pequeño proyecto para mí y viendo hasta dónde puedo llegar.
Re: Principiante que intenta escribir un script / ¿Cómo iterar dentro de la función de fórmula?Puedes obtener una lista de valores/recopilar una lista de valores dentro de una fórmula, pero debes tener cuidado con la forma en que actualizas los valores (usar As Constant o If(Row() == 1,...) puede ayudar). También es posible que desees evitar los bucles dentro de las fórmulas, ya que se activan con bastante frecuencia.
Podrías usar Lag() pero esto requeriría que tus datos estén ordenados (se puede hacer sin ordenar, pero puede complicarse rápidamente) pero generalmente la idea es algo como esto
If(Row() == 1,
init_taste = :Key_Taste
);
If(:Unique_Fruit != Lag(:Unique_Fruit),
init_taste = :Key_Taste;
);
init_taste;
Tenga en cuenta que ordené los datos por formato de número de fecha y fruta única.