Hola, tengo el siguiente desafío con el que tengo problemas para crear secuencias de comandos.
Mi tabla de datos iniciales se ve a continuación. Me gustaría multiplicar Xi hacia atrás a partir de col2 = 0 como criterio y colocar los nuevos valores en una nueva columna.
col1 col2
X1 0
x2 y2
x3 y3
…
xn yn
XX1 0
XX2 yy2
….
XXn yyn
….
….
Mi tabla de datos finales se vería así:
col1 col2 col3
X1 0 Xn*Xn-1*……X3*X2*X1
X2 y2 Xn*Xn-1*…..X3*X2
X3 y3 Xn*Xn-1*….*X3
…
Xn yn Xn
XX1 0 XXn*XXn-1*…..XX2*XX1
XX2 aa2 XXn*XXn-1*…..XX2
….
XXn yyn XXn
….
….
¿Puede alguien por favor ayudar? ¡Muy apreciado!
Los cálculos que desea son muy fáciles de hacer si se invierten los datos, así que aquí hay un pequeño script que calculará los valores usando esa idea.
names default to here(1);
// create the sample table
dt = New Table( "example",
Add Rows( 10 ),
New Column( "col1",
Numeric,
"Continuous",
Format( "Best", 12 ),
Set Values( [1, 2, 3, 2, 4, 5, 6, 7, 8, 9] ),
Set Display Width( 48 )
),
New Column( "col2",
Character( 1 ),
"Nominal",
Set Values( {"x", "x", "x", "y", "y", "y", "y", "z", "z", "z"} ),
Set Display Width( 45 )
)
);
// JSL to create the column you want
// create a new column to preserve the order of the data
dt << new column("origRow", formula(row()));
dt:origRow << delete formula;
// Reverse the order of the data
dt << sort(by(:origRow), order(descending), replace table(1));
// create the new column
dt << new column( "col3", formula(
If( Row() == 1, x = :col1 );
If( Lag( :col2 ) != :col2,
x = :col1,
x = x * :col1
);
x;
));
// Since the formula is dependent on the order of the data, the formula needs
// to be removed and the values set to static values
dt:col3 << delete formula;
// reorder the data table back to the original order and delete the origRow column
dt << sort(by(:origRow), order(ascending), replace table(1));
dt << delete columns(:origRow);
Y aquí hay una pieza de JSL que creará la nueva columna sin ordenar
Names Default To Here( 1 );
// create the sample table
dt = New Table( "example",
Add Rows( 10 ),
New Column( "col1",
Numeric,
"Continuous",
Format( "Best", 12 ),
Set Values( [1, 2, 3, 2, 4, 5, 6, 7, 8, 9] ),
Set Display Width( 48 )
),
New Column( "col2",
Character( 1 ),
"Nominal",
Set Values( {"x", "x", "x", "y", "y", "y", "y", "z", "z", "z"} ),
Set Display Width( 45 )
)
);
// create the new column
dt << New Column( "col3b" );
:col3b[N Rows( dt )] = :col1[N Rows( dt )];
For( i = N Rows( dt ) - 1, i >= 1, i--,
If( :col2[i + 1] != :col2[i],
:col3b[i] = :col1[i],
:col3b[i] = :col3b[i + 1] * :col1[i]
)
);
Hola Jim @txnelson
Eso realmente funcionó en una tabla más pequeña (es decir, varios miles de filas). Gracias.
El 'nuevo' problema que tengo es que mi tabla de datos es muy grande. Cuando incrusté la fórmula en la nueva columna y hice clic en 'aplicar', el programa se colgó y tuve que matar a jmp para salir.
Mientras paso el cursor sobre la fórmula, aquí está el mensaje de advertencia sobre la 'tabla de datos actual'.
"La tabla de datos actuales () tiene efectos secundarios y, por lo general, no es apropiado para usarse dentro de una fórmula. Si es necesario, puede usar expr o eval para evitar la ejecución en fórmulas..."
Mis habilidades de scripting son muy limitadas. ¡Gracias por su ayuda adicional en este tema!
Saludos,
Tinghui
@txnelson escribió:
Aquí está la nueva fórmula... es el mismo método que la fórmula anterior, pero solo hay que encontrar el punto inicial y final para cada uno de los grupos.
If( Row() == 1,
curCol = :col2;
end = Max( Current Data Table() << get rows where( :col2 == curCol ) );
x = :col1;
,
:col2 != curCol;
curCol = :col2;
end = Max( Current Data Table() << get rows where( :col2 == curCol ) );
x = :col1;
);
For( i = Row() + 1, i <= end, i++,
x = x * :col1[i]
);
x;
Aquí está la nueva fórmula... es el mismo método que la fórmula anterior, pero solo hay que encontrar el punto inicial y final para cada uno de los grupos.
If( Row() == 1,
curCol = :col2;
end = Max( Current Data Table() << get rows where( :col2 == curCol ) );
x = :col1;
,
:col2 != curCol;
curCol = :col2;
end = Max( Current Data Table() << get rows where( :col2 == curCol ) );
x = :col1;
);
For( i = Row() + 1, i <= end, i++,
x = x * :col1[i]
);
x;

Hola Jim @txnelson
Gracias por su respuesta.
No, los nombres de mis columnas no cambian. Permanecen como col1, col2 como se indica.Me gustaría agregar una nueva columna (col3) que haga la multiplicación hacia atrás por un mismo valor dado en col2. Estoy demostrando mi necesidad en la siguiente tabla.¿Podrias ayudarme por favor?
col1 col2 col3
1 x 6 (es decir, 1 x 2 x 3)
2 x 6 (es decir, 2 x 3)
3 x 3 (es decir, 3)
2 y 240 (es decir, 2x4x5x6)
4 y 120 (es decir, 4 x 5 x6)
5 y 30 (es decir, 5x6)
6 y 6 (es decir, 6)
7 z 504 (es decir, 7x8x9)
8 z 72 (es decir, 8x9)
9 z 9
¡Gracias!
Eliminé mi publicación porque me perdí la variable de agrupación. Mi enfoque no funcionaría en este escenario.
No entiendo tus 3 conjuntos de columnas.Parece como si estuviera cambiando los nombres de las columnas en medio de una tabla de datos, lo que no funcionará en JMP.¿Este formato de tabla proviene de una hoja de cálculo de Excel?
Aquí hay una fórmula simple que hará lo que quieras para una tabla de datos que se parece a

Adjunto la tabla de datos.
La fórmula utilizada es:
x = :col2[Row()];
If( Row() < N Rows( Current Data Table() ),
For( i = Row() + 1, i <= N Rows( Current Data Table() ), i++,
x = x * :col2[i]
)
);
x;
Esta misma idea se puede usar si hay varios lugares en una tabla de datos que necesitan reiniciar la multiplicación.La identificación de cuándo reiniciar y cuándo finalizar solo tendría que resolverse