¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosUna discusión comunitaria reciente script para buscar y reemplazar un valor numérico con un valor faltante en toda la tabla tuvo una muy buena entrada proporcionada por @SDF1 que fue seleccionada como la solución
names default to here(1);
dt=current data table();
For( i = 1, i <= N Rows( dt ), i++,
For( l = 1, l <= N Cols( dt ), l++,
If( Column( l )[i] == 999,
Column( l )[i] = .
)
)
);
Cuando vi la solución, me vino a la cabeza una vieja enseñanza que decía aproximadamente: "No recorras una tabla de datos.El bucle es lento. Utilice las capacidades integradas de JMP."
Entonces comencé a modificar @SDF1 código.
Determiné que mi estándar alternativo de "Obtener filas donde ()" sería más rápido.Después de todo, permite que todas las filas encontradas se establezcan con una declaración de asignación, después de que Get Rows Where() "muy rápido" haya encontrado las filas.
Otra solución que he visto. empujado Lo recomendado por la comunidad es la instalación Recode en JMP.
Entonces:
Hipótesis: Las funciones JMP integradas de Obtener filas dónde y Recodificar serán más rápidas que recorrer una tabla de datos completa.
Seleccioné la tabla de datos Capacidad de semiconductores como una tabla de buen tamaño, 132 columnas y 1455 filas.
Escribí un pequeño script que establece 10 valores aleatorios en cada columna en 999.
names default to here(1);
dt=current data table();
for(i=5,i<=ncols(dt),i++,
if(col stddev(ascolumn(dt,i))!=0,
for(k=1,k<=10,k++,
column(dt,i)[randominteger(1,1455)]=999;
)
));
Names Default To Here( 1 );
dt = Current Data Table();
start = HP Time();
For( i = 5, i <= N Cols( dt ), i++,
dt << Recode Column(
As Column( dt, i ),
{If( _rcNow == 999, ., _rcNow )},
Target Column( As Column( dt, i ) )
)
);
show(hptime()-start)
Este es el valor original que se cambiará en la discusión mencionada anteriormente.Los scripts deben cambiar el 999 a faltante (.).
Método:
- Inicie JMP 16.
- Leer en la tabla de datos de capacidad de semiconductores
- Ejecute el script para establecer los 999 valores en cada columna
- Repita los 2 pasos anteriores para cada uno de los 3 métodos y recodifica el tiempo hasta el milisegundo.
- Repita los pasos anteriores para JMP15
Aquí está el script para Recode.
Names Default To Here( 1 );
dt = Current Data Table();
start = HP Time();
For( i = 5, i <= N Cols( dt ), i++,
dt << Recode Column(
As Column( dt, i ),
{If( _rcNow == 999, ., _rcNow )},
Target Column( As Column( dt, i ) )
)
);
show(hptime()-start)
El código para Obtener filas donde
names default to here(1);
dt=current data table();
start=hptime();
for(i=5,i<= ncols(dt),i++,
column(dt,i)[dt<<GET rows="" where=""></GET>
Y aquí están los sorprendentes resultados.

El For Loop gana sin lugar a dudas.Y según los resultados, Obtener filas dónde debe usarse con moderación.
Comentarios y correcciones son bienvenidos......
Combinación y limpieza de datosIngeniería de Calidad y ProcesosRe: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datos
@jthi escribió:
Quizás profundicé demasiado en esto (pero al menos tuve una idea de cómo hacer este tipo de pruebas más adelante si es necesario).
Escribí una especie de script de prueba con diferentes expresiones para probar diferentes formas de reemplazar el 999 que falta.
....
acabo de usar @jthi guión de:
https://community.jmp.com/t5/Discussions/Should-you-Loop-through-a-data-table-or-use-Recode-or-use-Get/mp/381766/highlight/true#M63232
para reproducir el rendimiento de los diferentes enfoques en un sistema con Jmp (16.2 y) 17.1.
Destaqué algunos enfoques (incl. loc ) que hoy en día tienen que estar dentro iniciar/finalizar actualización de datos *)
para deshacerse de un aumento severo de tiempo con una fracción porcentual creciente de 999.
Las diferencias por factor 2 podrían deberse a las diferentes computadoras.
¿Quién tiene un sistema con Jmp 15 y 17 para una comparación directa?
*) aunque el subconjunto se abrió "invisible".

Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datos@hogi escribió:
...
Si un usuario sabe si el problema, un muy barato La solución es agregar un evaluar()
barato con respecto a la complejidad del código JSL frente a la penalización de tiempo.
Pero para mesas más largas Evaluación(i) pierde significativamente contra Sustituir(...,NombreExpr(Como columna()))) .
Entonces: sigue siendo bastante rápido (en comparación con la versión original
, pero no tan rápido como hubiera esperado.
¿Por qué? ¿Cuál es la diferencia fundamental?
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosHm, ¿quizás sea posible cambiar JSL a un modo fácil de usar (que evalúa previamente las variables si esto conduce a un mejor rendimiento)?
desear: obtener filas donde: problema de velocidad
Si un usuario es consciente del problema, es muy barato La solución es agregar un Evaluación():
start = HP Time();<BR />for(i=5,i<= ncols(dt),i++,<BR />dt << get rows where( As Column( dt, Eval(i) ) == 999 );<BR />);<BR />Show( (HP Time() - start) / 1000000 );start = HP Time();
i = 5;
dt << get rows where( As Column( dt, Eval(i) ) == 999 );
Show( (HP Time() - start) / 1000000 );
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosHola @ron_horne , el problema está en el obtener filas donde , por lo que la velocidad debe ser/es independiente de dichas configuraciones.
Por otro lado, hace una gran diferencia si el índice de la columna es explícito o si es una variable (incluso si la variable tiene un valor asignado).
Esto no estaba claro para mí: ¡qué buena me pareció esta conversación!
No sé cuántos códigos jsl podrían ser más rápidos en un factor de ~ N (filas de la tabla de datos)...
¿Se puede solucionar el problema con lo que sucede en segundo plano en JSL?
¿O hay algo fundamental en la arquitectura JSL que especifica que tal comportamiento está previsto y no se puede cambiar?
Si es así: un mensaje de advertencia podría ayudar a los programadores a no quedar atrapados por este problema...
Names Default To Here( 1 );
dt = Open( "$SAMPLE_DATA/Semiconductor Capability.jmp" );
For( k = 1, k <= 4, k++,
dt << Concatenate( dt, dt, dt, Append to first table )
);
nuke = Function( {},
For( k = 1, k <= 10, k++,
Column( dt, 5 )[Random Integer( 1, 1455 )] = 999
)
);
//dt << show window(0);
//dt<< Begin Data Update();
nuke();
start = HP Time();
i = 5;
dt << get rows where( As Column( dt, i ) == 999 );
Show( (HP Time() - start) / 1000000 );
nuke();
start = HP Time();
dt << get rows where( As Column( dt, 5 ) == 999 );
Show( (HP Time() - start) / 1000000 );
//dt << End Data Update();
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosgracias @txnelson
¿Podría estimar el efecto del uso de tablas invisibles y privadas en los diferentes métodos? deben ser la forma más rápida de modificar cualquier guión para mejorar el rendimiento.
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosVaya, que truco tan maravilloso 
Temía que los problemas con Código de valor faltante comenzará tan pronto como lo intentes:
Col Maximum(:NPN3)
[Como sabemos que excluido las filas tienen que ser excluido en agregación Col a mano (o mejor: por Agrupar por argumento).]
Pero la sorpresa: Columna respeto de las agregaciones Códigos de valor faltantes 
Ser exigente: el pregunta OP de la publicación original era bastante implícito:
Y a partir de los resultados, el Obtener filas donde debe usarse con moderación.
Comentarios y correcciones son bienvenidos......
traducido - con una sensación de inquietud en el estómago - como: "¿¡¿porque en la tierra?!?"
Gracias a @ataqueerrático por resolver el rompecabezas 
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datos¡Ha sido una discusión muy divertida e informativa! Respuestas brillantes. Realmente no estoy calificado para agregar nada de valor aquí, así que voy a recurrir al "trampa".
La pregunta del OP era sobre reemplazar los valores de 999 en los datos con los faltantes porque a los 999 les faltan códigos de valor y no queremos que se incluyan en los cálculos. No está en absoluto en el espíritu de esta interesante línea de preguntas, pero mi contribución es que explotar la propiedad de la columna del código de valor faltante es más rápido que reemplazar los datos y logra lo mismo para *la mayoría* de los propósitos 
start = HP Time();
For( i = 5, i <= N Cols( dt ), i++,
Column(dt,i) << Set Property( "Missing Value Codes", {999} )
);
Show( HP Time() - start);
~ 0,007 segundos en mi mac m1.
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosAh, no lo sabía:
:nombre() actúa como Como columna() ?
No tan claro en el índice de Scripting 
Entonces, con Sustituto y Como columna() en lugar de Eval(Analizar(Eval Insertar(Cita JSL(nombre("^nombres[i]^") es:
start=hptime();
for(i=5,i<= ncols(dt),i++,
Eval(Substitute(Expr(column(dt,i)[dt<<GET rows="" where=""></GET>
Y después este sorprendente hallazgo Casi me sorprende que el obtener filas donde También es rápido si la comparación de números se reemplaza por una comparación de caracteres 
start=hptime();
for(i=5,i<= ncols(dt),i++,
Eval(Substitute(Expr(column(dt,i)[dt<<GET rows="" where=""></GET>
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosSi entiendo @brady_brady . Sin embargo, se podría hacer esto:
NamesDefaultToHere(1);
// Make an example table with some rogue '999' values
nr = 10; // Number of rows
nc = 10; // Number of columns
p = 0.1; // Fraction of rogue values
val = 999; // Rogue value
m = J(nr, nc, RandomInteger(1, 10));
m = Shape(m, nr*nc, 1);
m[RandomIndex(nr*nc, Floor(nr*nc*p))] = val;
m = Shape(m, nr, nc);
dt = AsTable(m);
dt << setName("Rogue Values");
Wait(3);
// Set rogue values to '.'
mask = J(nr*nc, 1, 1);
mask[Loc(dt[0,0] == val)] = .;
mask = Shape(mask, nr, nc);
dt[0,0] = mask :*</img> dt[0,0];
Pero dudo mucho que esto sea más rápido de lo que ya tienes, sobre todo por la multiplicación de elementos.
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosAquí la comparación está un poco mal: la funcionalidad "Obtener filas dónde" evaluará su expresión en cada fila, por lo que debe minimizar cualquier búsqueda superflua antes de ejecutar el bucle; en particular, su iterador es externo y Tendrá que caminar un poco para encontrarlo en cada fila.Además, evaluará la función AsColumn en cada fila, buscando tanto 'dt' como 'i' cada vez.Esto es _muy_ caro.La forma correcta de hacerlo sería la siguiente:
names default to here(1);
dt=current data table();
start=hptime();
names = dt << Get Column Names( "string" );
for(i=5,i<= ncols(dt),i++,
Eval( Parse( Eval InserT( JSL Quote(
column(dt,i)[dt<<GET rows="" where=""></GET>
Notarás que esto se ejecuta del orden de 3000 veces más rápido, lo que debería hacerlo comparable, si no mejor, que los otros métodos que tienes.
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosSí... el obstáculo es que, si bien se puede acceder a las matrices con un único índice (lo que supone un diseño de fila principal), no se puede acceder a las tablas de datos. Por lo tanto, lamentablemente no existe ningún análogo a
metro[loc(m, 9999)] = .
donde m es una matriz pxq, en el mundo de las tablas de datos... de ahí las líneas que preceden y siguen a ésta en el código anterior. Si bien el código sigue siendo rápido, sería REALMENTE rápido si el acceso de índice único estuviera disponible para las tablas.
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosPara el ' gastos generales al crear una matriz. Sospecho que subíndice de tabla de datos podría ayudar.@Craige_Hales sabría.
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosAquí hay una manera de evitar los bucles, aunque hay una sobrecarga al crear una matriz y volver a asignarla a la tabla después. Este enfoque funciona rápidamente con estos datos, aproximadamente igual que loc_2d, pero a medida que la tabla se vuelve enorme, esperaría que su rendimiento relativo se vea afectado, pero no lo he verificado.
expr_mat = expr(
m = dt[0, 5 :: N Col( dt )];
m[Loc( m, 999 )] = .;
dt[0, 5 :: N Col( dt )] = m;
);
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosQuizás fui demasiado profundo en esto (pero al menos tengo alguna idea de cómo hacer este tipo de pruebas más adelante si es necesario).
Escribí una especie de script de prueba con diferentes expresiones para probar diferentes formas de reemplazar el 999 que falta. Probé con dos conjuntos de datos (Semiconductor Capability.jmp y Probe.jmp) y cambié la cantidad de valores faltantes en las columnas.
Loc() es el más rápido a la hora de reemplazar valores (no es de extrañar). Missing Value Codes() es "siempre" rápido, pero tiene casos de uso un poco más limitados en comparación con Loc() y es un poco más complicado de usar si hubiera varios valores para reemplazar.

El más rápido terminó siendo loc_2d (no me molesté en cambiar los nombres de las variables de esto: Usando Loc con una matriz 2D ). Todavía tengo que hacer un bucle para establecer los valores (al menos que yo sepa), por lo que lo más probable es que la razón por la que esto sea más rápido que solo Loc() es que omitirá algunas columnas. A continuación se muestran expr_loc2d y expr_loc:
expr_loc = Expr(
for(i=5,i<= ncols(testData),i++,
column(testData,i)[Loc(testData[0,i], 999)]=.;
);
);
expr_loc_2d = Expr(
mat = testData[0,5::NCols(testData)];
nr = N Rows(mat);
nc = N Cols(mat);
blacklocs = Loc(mat, 999) - 1;
rowlocs = Floor((blacklocs) / nc ) + 1;
collocs = Mod((blacklocs), nc ) + 1 + 4;
uniqCols = Associative Array(collocs) << get keys;
For(i_2d = 1, i_2d <= N Items(uniqCols), i_2d++,
testData[rowlocs[Loc(collocs, uniqCols[i_2d])], uniqCols[i_2d]] = .;
);
);
También parece importante utilizar AsColumn(Column(dt, i)) como @Ryan_Gilmore dijo (ni siquiera me molesté en probar << obtener filas sin él, porque será muy lento), pero probé la recodificación con y sin Column(). También me acabo de dar cuenta de que me perdí una columna() de la recodificación, así que ejecute un par de pruebas rápidas (no adjuntas en los datos ni en el script):
Diferencia bastante grande entre estos tres:
expr_recode_ascolumn = Expr(
For(i = 5, i <= N Cols(testData), i++,
testData << Recode Column(
As Column(dt, i),
{If( _rcNow == 999, ., _rcNow)},
Target Column(As Column(testData, i))
)
);
);
expr_recode_ascolumn_column = Expr(
For(i = 5, i <= N Cols(testData), i++,
testData << Recode Column(
As Column(dt, i),
{If( _rcNow == 999, ., _rcNow)},
Target Column(As Column(Column(testData, i)))
)
);
);<BR />
expr_recode_ascolumn_column_column = Expr(
For(i = 5, i <= N Cols(testData), i++,
testData << Recode Column(
As Column(Column(dt, i)),
{If( _rcNow == 999, ., _rcNow)},
Target Column(As Column(Column(testData, i)))
)
);
);

El script de prueba y algunos datos de resultados adjuntos. Lo más probable es que el guión tenga algunos errores aquí y allá. Debería ser bastante fácil agregar nuevas expresiones si alguien quiere hacerlo. Una cosa que no probé en absoluto es usar << Inicio/Fin de actualización de datos.
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datos¡Interesante discusión! La notación matricial de la tabla de datos, que creo que apareció por primera vez en JMP 13, es bastante eficiente para la asignación.
Para este problema en particular, es casi 500 veces más rápido que el bucle for (0,003 frente a 1,5 segundos, computadora portátil Mac JMP 15).
start = HP Time();
For( i = 5, i <= N Cols( dt ), i++,
Try( dt[Loc( dt[0, i], 999 ), i] = . )
);
Show( HP Time() - start);
El try() es necesario para evitar un error en las columnas sin "999".
Sigue siendo necesario recorrer las columnas porque la asignación directa para toda la matriz, que por un momento pensé que sería aún más rápida, no funciona. Error: "Varios subíndices requieren subíndices únicos en cada nivel interno de acceso o evaluación...", lo que, pensándolo bien, tiene sentido.
// The left Data Table matrix syntax is OK on its own, but not for assignment.
dt[0, 5 :: N Col( dt )][Loc( dt[0, 5 :: N Col( dt )], 999 )] = .;
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosEs posible que haya sido cauteloso al usar bucles en algún momento, pero después de tomar un curso de algoritmo (que nunca terminé...) un poco menos. Solo tienes que ser eficiente con ellos, muy a menudo haces demasiados bucles (complejidad de tiempo y notación Big O). Además, utilizar bucles es mucho más fácil que intentar resolver problemas con matemáticas puras.
Con JMP normalmente opto por las opciones seguras que he aprendido en algún momento, ya que la velocidad rara vez es un problema. Pero cuando el tiempo es un problema (una aplicación tardó más de 6 minutos en abrirse en el trabajo), comenzaré a buscar formas de hacerlo más rápido (logré que se iniciara en menos de 2 minutos). En este caso logré hacerlo más rápido usando Loc() con diferentes combinaciones de otras funciones (eliminar fila, establecer estado de fila).
Además de Loc(), usar Summarize() parece ser "mucho" más rápido en comparación con mi opción favorita desde hace mucho tiempo para obtener valores únicos en la columna (matriz asociativa() << obtener claves). Cuando el recuento de filas aumenta, la matriz asociativa() << obtener claves se vuelve cada vez más lenta y Summarize() no parece sufrir el mismo problema, al menos no tan rápido. Así que intenté comenzar a usar Summarize() más (nunca sé qué tan altas llegan a ser las tablas de datos).
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosAsí que nos saltamos AsColumn() con (vamos más por una corazonada y no he probado que esto reemplace todos los valores correctos):
start=hptime();
for(i=5,i<= ncols(dt),i++,
column(dt,i)[Loc(dt[0,i], 999)]=.;
if(mod(i,10)==0,show(i));
);
show(hptime()-start);
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosEstoy de acuerdo en que Loc() es el mejor método.
Para mí, la desaceleración parece deberse a As Column. Veo una diferencia significativa entre,
start = HP Time();
For( i = 5, i <= N Cols( dt ), i++,
As Column( column(dt, i) );
);
Show( HP Time() - start );
y
start = HP Time();
For( i = 5, i <= N Cols( dt ), i++,
As Column( dt, i );
);
Show( HP Time() - start );
Cambiar la sintaxis de columna como en el código de @txnelson Pregunta original, el bucle For sigue siendo el más rápido pero los demás son más comparables.
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosHola @txnelson ,
Comparación muy interesante y tampoco los resultados que esperaba. Recuerdo cuando comencé a aprender programación en la universidad y también me enseñaron algo similar: tener cuidado con los bucles porque son lentos.
Seguramente, con algunos cálculos y en algunos programas, he encontrado que los bucles For son muy lentos, más lentos que las alternativas. Sin embargo, al no ser un gran programador, tiendo a recurrir a lo que sé hacer, lo cual no siempre es rápido o elegante. A veces, para mí, la lógica de un bucle me permite escribir un código funcional para hacer lo que quiero, lo que me permite pasar a los siguientes pasos.
Me parece interesante que las opciones For Loop y Recode sean ligeramente más lentas para JMP 16 versus 15, pero Get Rows donde mejoró al reducir el tiempo casi a la mitad, eso es un cambio sustancial.
¡Gracias!,
DS
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosTal vez @Craige_Hales podría tenernos una solución aún más rápida. Se me ocurrió la idea de utilizar cálculos Matrix (especialmente Loc()) de las publicaciones/blog de su comunidad.
He creado una herramienta que funciona más rápido y que abre un conjunto de datos y luego elimina los datos antiguos (según la selección del usuario). Originalmente usaba << Seleccionar dónde y Eliminar filas. Lo reemplacé con algo de magia Loc() y también se volvió mucho más rápido. Últimamente me gusta mucho Loc().
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datos@jthi ,
Su código basado en matriz resultó ser el más rápido.
0,299795 segundos.....
Re: ¿Debería recorrer una tabla de datos, usar Recodificar o usar Obtener filas? Dónde cambiar los valores en una tabla de datosHe estado optimizando algunos scripts antiguos que tenemos. Algunas de las cosas que tuve que cambiar estaban relacionadas con la obtención de filas. He comenzado a usar cada vez más operaciones matriciales (principalmente Loc()) si necesito tener un código JSL rápido.
Por ejemplo, podría cambiar las filas de obtención a las siguientes (no probé si reemplaza los valores correctos o todos ellos):
start=hptime();
for(i=5,i<= ncols(dt),i++,
column(dt,i)[Loc(ascolumn(dt,i) << get as matrix, 999)]=.;
if(mod(i,10)==0,show(i));
);
show(hptime()-start);
También existe la opción de utilizar las propiedades de columna Etiquetas de valor y Códigos de valor faltante que podrían funcionar en algunos casos. Me gusta usarlos cuando sea posible, porque así no cambiarás los datos.