Pregunta de novato sobre la generación (extracción) de tablas de datos a partir de datos de sonda sin procesarHola a todos, esta es mi primera publicación en esta comunidad. Recientemente cambié de trabajo y haré muchas pruebas de banco y análisis de datos. Usé JMP un poco, pero nada avanzó en absoluto.
En este momento, mi prueba siempre genera un archivo CSV grande y los datos de medición están enterrados junto con información que no interesa (como la configuración de la prueba, las condiciones, etc.). Me gustaría obtener ayuda para extraer información útil usando el script JMP. y desde aquí, comenzar mi aprendizaje avanzado de guiones.
Explico mi tarea en la captura de pantalla adjunta. La parte superior derecha es un ejemplo de un único punto de datos de barrido IV (para medir R) para darle una idea de cómo se ve mi CVS gigantesco (contiene cientos de estructuras de este tipo). La "información no interesada de varias filas" representa esas filas inútiles que no quiero importar. Además de copiar y pegar la parte de datos I/V/R, también me gusta extraer la identificación del lote de oblea, la identificación de la oblea, el índice de retícula (o digamos campo paso a paso) y el número de subsitio de algunas cadenas. El cuadro superior derecho muestra la salida JMP deseada.
Como lectura opcional, hay algunas curiosidades en los dos cuadros inferiores. En la parte inferior izquierda están mis comentarios generales sobre la estructura de datos y en la parte inferior derecha se explican los significados de las cadenas de las que necesito extraer cierta información.
Espero que la captura de pantalla le proporcione suficiente información para mi pregunta. Solía hacer ese trabajo usando Excel VBA Macro: escanear cadenas de firmas de búsqueda, luego importar selectivamente cierto carácter/cadena/fila cerca de esa ubicación, y luego continuar la búsqueda hasta el final del archivo de datos sin procesar. Me pregunto si el script JMP haría lo mismo.
Automatización y secuencias de comandosRe: Pregunta de novato sobre la generación (extracción) de tablas de datos a partir de datos de sonda sin procesarSin captura de pantalla. ¿Sería posible adjuntar un conjunto de datos pequeño y anónimo o un archivo .csv?
Re: Pregunta de novato sobre la generación (extracción) de tablas de datos a partir de datos de sonda sin procesarHola pmroz, gracias por la pronta respuesta. Olvidé el archivo adjunto cuando lo envié por primera vez, pero luego de 1 minuto edité la publicación y adjunté la captura de pantalla. Puedes comprobarlo de nuevo.
También según su solicitud, subo el Excel aquí. Eliminé la mayor parte de la información inútil para limpiar el archivo, pero puedes copiar y pegar el cuadro superior izquierdo como ejemplo de "datos sin procesar".
Re: Pregunta de novato sobre la generación (extracción) de tablas de datos a partir de datos de sonda sin procesarComo han dicho otros, esto puede depender en gran medida del formato de datos real. A continuación se muestra un ejemplo que utiliza la copia de datos pegada desde Excel a un archivo de texto.
Names Default To Here(1);
filepath = "$DOWNLOADS/744027.txt";
txt = Load Text File(filepath);
lines = Words(txt, "\!N");
project_pattern = "^(.+)_(\d+\.\d*)(W\d{1,2})_(T\d+)_(.+):(.+)?";
subsite_pattern = "<SUBSITE>(\d+)</SUBSITE>";
datastart_pattern = "^DataName";
data_start = 0;
For Each({line, idx}, lines,
If(!IsMissing(Regex(line, project_pattern)),
matches = Regex Match(line, project_pattern);
projname = matches[2];
lotid = matches[3];
waferid = matches[4];
time = matches[5];
notes = matches[6];
reticles = Words(Trim Whitespace(matches[7]), " ");
, !IsMissing(Regex(line, subsite_pattern)),
subsite = Regex(line, subsite_pattern, "\1");
, !IsMissing(Regex(line, datastart_pattern)),
data_start = idx;
break();
);
);
data_str = Concat Items(lines[data_start::N Items(lines)], "\!N");
dt = Open(Char To Blob(data_str), "text");
dt << New Column("lot", Character, Nominal, Set Each Value(lotid));
dt << New Column("waferid", Character, Nominal, Set Each Value(waferid));
dt << New Column("x", Character, Nominal, Set Each Value(reticles[1]));
dt << New Column("y", Character, Nominal, Set Each Value(reticles[2]));
dt << New Column("subsite", Character, Nominal, Set Each Value(subsite));
dt << Move Selected Columns({:lot, :waferid, :x, :y, :subsite}, To First);
dt << Delete Columns("DataName");
Utiliza expresiones regulares para encontrar líneas específicas y luego las analiza. Para los datos, encuentra el índice de línea donde comienza y luego lo analiza dejando que JMP simplemente lo abra (dependiendo de los datos reales, esto podría requerir pasos adicionales).

Re: Pregunta de novato sobre la generación (extracción) de tablas de datos a partir de datos de sonda sin procesarEl formato que estás mostrando no debería ser un gran problema para leer. Las filas de información poco interesantes me preocupan porque lo que hay allí puede interferir con la lectura de los datos. Mi otra preocupación es cómo hacer que JMP reconozca la fila que contiene el nombre del proyecto. ¿Siempre comienza con Proj?
Sería muy útil proporcionar un archivo real.
Re: Pregunta de principiante sobre la generación (extracción) de tablas de datos a partir de datos de sondeo sin procesar- Pasé por alto el subsitio, lo siento. Lo agregué al script.
- El propósito del foro de discusión es ayudar a los usuarios de JMP con los problemas que tengan al ejecutar JMP. No es un servicio gratuito de escritura de scripts. La razón por la que escribo scripts para los miembros de la comunidad es para ayudarlos a aprender a usar JSL. Espero que los destinatarios de los scripts que proporciono se tomen el tiempo de aprender de ellos, para que puedan resolver su problema total.
- He cambiado las columnas dinámicas (propiedades de la columna de porción) para que sean numéricas
- El script ahora agrega cada tabla creada
- En cuanto a la compresión del código... ¿por qué? Si el propósito de la compresión hace que se ejecute más rápido, podría aceptarlo. Pero si comprimir un fragmento de código hace que sea más difícil de leer para el próximo humano que necesite verlo, entonces el código no es bueno. Por lo tanto, mi respuesta a su pregunta sobre si el código se puede comprimir en un formato más conciso es que estoy seguro de que se puede.
names default to here(1);
clear symbols( dtOut );
file = pick file();
dt = Open(
File,
Import Settings(
End Of Line( CRLF, CR, LF ),
End Of Field( Comma, CSV( 0 ) ),
Treat Leading Zeros as Character( 1 ),
Strip Quotes( 1 ),
Use Apostrophe as Quotation Mark( 0 ),
Use Regional Settings( 0 ),
Scan Whole File( 1 ),
Treat empty columns as numeric( 0 ),
CompressNumericColumns( 0 ),
CompressCharacterColumns( 0 ),
CompressAllowListCheck( 0 ),
Labels( 0 ),
Column Names Start( 1 ),
First Named Column( 1 ),
Data Starts( 1 ),
Lines To Read( "All" ),
Year Rule( "20xx" )
)
);
// Change column names to simplify coding
for( i=1,i<=ncols(dt), i++, column(i)<< set name( "C" || char(i)));
// Create a base output table
dtFinal = New Table( "Final" );
// Loop through the data
for(theRow = 1, theRow <= NRows(dt), theRow++,
If( dt:C1[theRow] == "SetupTitle",
memoryProjectName = "";
memoryLotName = "";
memoryWaferID = "";
memoryT0 = "";
memory1strun = "";
memoryIndexX = .;
memoryIndexY = .;
memorySubsite = .;
setupFlag = 1;
projFlag = 0;
// If this is not the first read in table, then append the table
// to the Final table, and close the current dtOut table
If( nrows(dtFinal) != 0 | isEmpty( dtOut ) == 0,
dtFinal << concatenate( dtOut, append to first table(1));
close( dtOut, nosave )
)
,
dt:C1[theRow] == "" & setupFlag == 1,
projFlag = 1;
setupFlag = 0;
,
projFlag == 1 & dt:C1[theRow] != "",
dt:C1[theRow] = trim(dt:C1[theRow]);
memoryProjectName = word(1, dt:C1[theRow], "_");
memoryLotName = word(2, dt:C1[theRow], "_W");
memoryWaferID = word(3, dt:C1[theRow], "_W");
memoryT0 = word(4, dt:C1[theRow], "_W");
memory1strun = word(5, dt:C1[theRow], "_W:");
memoryIndexX = num(word(2, dt:C1[theRow], ": "));
memoryIndexY = num(word(3, dt:C1[theRow], ": "));
memorySubsite = num(word(2, trim(dt:C1[theRow + 2 ]),"<>"));
projFlag = 0;
,
dt:C1[theRow] == "DataName",
colList = {};
col=2;
while( column(dt,col)[theRow] != "",
insert into(colList, column(dt,col)[theRow]);
col++
);
dtOut = New Table( "Lot " || memoryLotName || " WaferID " || memoryWaferID,
new column( "Project Name", character),
new column( "Lot Name", character),
new column( "WaferID", character),
new column( "Time Readout", character),
new column( "Personal Note", character),
new column( "SubSite", numeric, ordinal),
new column( "Index X", numeric, ordinal),
new column( "Index Y", numeric, ordinal)
);
for each( {colName}, colList,
dtOut << new column( eval(colName), numeric, continuous);
);
,
dt:C1[theRow] == "DataValue",
dtOut << Add Rows(1);
dtOut:Project Name[nrows(dtOut)] = memoryProjectName;
dtOut:Lot Name[nrows(dtOut)] = memoryLotName;
dtOut:WaferID[nrows(dtOut)] = memoryWaferID;
dtOut:Time Readout[nrows(dtOut)] = memoryT0;
dtOut:Personal Note[nrows(dtOut)] = memory1strun;
dtOut:SubSite[nrows(dtOut)] = memorysubsite;
dtOut:Index X[nrows(dtOut)] = memoryIndexX;
dtOut:Index Y[nrows(dtOut)] = memoryIndexY;
for each( {colName, index}, colList,
column( dtOut, colName )[nrows(dtOut)] = num(column(dt,index+1)[theRow])
)
)
);
// Close the last work file
close( dtOut, nosave );
// Uncomment the below line if you want the raw table deleted
// close( dt, nosave );
Re: Pregunta de principiante sobre la generación (extracción) de tablas de datos a partir de datos de sondeo sin procesarContinuando con mi idea anterior de separar el archivo de texto en secciones y luego analizar esas secciones (esta grabación cubre parcialmente este tema Scripters Club 2024: Sesión 2 - Preparación de datos entrantes no estructurados para el análisis ).
Names Default To Here(1);
// Test sections seem to always start with a line starting with "SetupTitle"
// and end to same UNLESS it is last section when it ends with
// line of ",,,,,,,,,,,,,,,,,,,,,,,"
TEST_SECTION_START = "SetupTitle, ";
EMPTY_LINE = ",,,,,,,,,,,,,,,,,,,,,,,";
// Section patterns for regex
PROJECT_PATTERN = "^(.+)_(\d+\.\d*)(W\d{1,2})_(T\d+)_(.+): (\d+ \d+)\,+?";
SUBSITE_PATTERN = "<SUBSITE>(\d+)</SUBSITE>";
DATASTART_PATTERN = "^DataName";
find_test_section_lines = function({lines}, {Default Local},
start_idx = 0;
end_idx = 0;
TEST_SECTION_START = TEST_SECTION_START; // JMP "feature", 00075244
TEST_SECTION_END = TEST_SECTION_END; // JMP "feature", 00075244
For Each({line, idx}, lines,
If(Starts With(line, TEST_SECTION_START),
If(start_idx == 0,
start_idx = idx;
,
end_idx = idx;
break();
);
);
);
If(start_idx != 0 & end_idx == 0,
end_idx = N Items(lines);
);
return(Eval List({start_idx, end_idx}));
);
parse_test_section = function({lines}, {Default Local},
data_start = 0;
PROJECT_PATTERN = PROJECT_PATTERN; //JMP "feature", 00075244
SUBSITE_PATTERN = SUBSITE_PATTERN; //JMP "feature", 00075244
DATASTART_PATTERN = DATASTART_PATTERN; //JMP "feature", 00075244
For Each({line, idx}, lines,
If(!IsMissing(Regex(line, PROJECT_PATTERN)),
matches = Regex Match(line, PROJECT_PATTERN);
projname = matches[2];
lotid = matches[3];
waferid = matches[4];
time = matches[5];
notes = matches[6];
reticles = Words(Trim Whitespace(matches[7]), " ");
, !IsMissing(Regex(line, SUBSITE_PATTERN)),
subsite = Regex(line, SUBSITE_PATTERN, "\1");
, !IsMissing(Regex(line, DATASTART_PATTERN)),
data_start = idx;
break();
);
);
data_str = Concat Items(lines[data_start::N Items(lines)], "\!N");
dt = Open(Char To Blob(data_str), "text", invisible);
For Each({colname}, Reverse(dt << Get Column Names("String")), // drop empty columns
If(Col Number(Column(dt, colname)) == 0,
dt << Delete Column(colname);
,
break(); // break on first "ok" column
);
);
// define order and names here
dt << New Column("project", Character, Nominal, Set Each Value(projname));
dt << New Column("lot", Character, Nominal, Set Each Value(lotid));
dt << New Column("waferid", Character, Nominal, Set Each Value(waferid));
dt << New Column("time", Character, Nominal, Set Each Value(time));
dt << New Column("notes", Character, Nominal, Set Each Value(notes));
dt << New Column("x", Character, Nominal, Set Each Value(reticles[1]));
dt << New Column("y", Character, Nominal, Set Each Value(reticles[2]));
dt << New Column("subsite", Character, Nominal, Set Each Value(subsite));
dt << Move Selected Columns({:project, :lot, :waferid, :time, :notes, :x, :y, :subsite}, To First);
dt << Delete Columns("DataName");
return(dt);
);
// Start parsing
filepath = "$DOWNLOADS/Raw data examples_3DP.csv";
txt = Load Text File(filepath);
lines = Words(txt, "\!N");
lines = Filter Each({line}, lines, line != EMPTY_LINE); // drop empty lines
{start, end} = find_test_section_lines(lines);
dt_result = Empty();
While(All(start, end),
cur_testset = Remove From(lines, start, end - 1);
dt = parse_test_section(cur_testset);
If(Is Empty(dt_result),
dt_result = dt;
,
dt_result << Concatenate(
dt,
"Append to first table"
);
Close(dt, no save);
);
{start, end} = find_test_section_lines(lines);
);
dt_result << Show Window(1);

Re: Pregunta de principiante sobre la generación (extracción) de tablas de datos a partir de datos de sondeo sin procesarAquí hay un script que lee los 3 datos del proyecto que se encuentran en el archivo CSV de muestra y crea 3 tablas de datos independientes.
names default to here(1);
file = pick file();
dt = Open(
File,
Import Settings(
End Of Line( CRLF, CR, LF ),
End Of Field( Comma, CSV( 0 ) ),
Treat Leading Zeros as Character( 1 ),
Strip Quotes( 1 ),
Use Apostrophe as Quotation Mark( 0 ),
Use Regional Settings( 0 ),
Scan Whole File( 1 ),
Treat empty columns as numeric( 0 ),
CompressNumericColumns( 0 ),
CompressCharacterColumns( 0 ),
CompressAllowListCheck( 0 ),
Labels( 0 ),
Column Names Start( 1 ),
First Named Column( 1 ),
Data Starts( 1 ),
Lines To Read( "All" ),
Year Rule( "20xx" )
)
);
// Change column names to simplify coding
for( i=1,i<=ncols(dt), i++, column(i)<< set name( "C" || char(i)));
// Loop through the data
for(theRow = 1, theRow <= NRows(dt), theRow++,
If( dt:C1[theRow] == "SetupTitle",
memoryProjectName = "";
memoryLotName = "";
memoryWaferID = "";
memoryT0 = "";
memory1strun = "";
memoryIndexX = .;
memoryIndexY = .;
setupFlag = 1;
projFlag = 0;
,
dt:C1[theRow] == "" & setupFlag == 1,
projFlag = 1;
setupFlag = 0;
,
projFlag == 1 & dt:C1[theRow] != "",
dt:C1[theRow] = trim(dt:C1[theRow]);
memoryProjectName = word(1, dt:C1[theRow], "_");
memoryLotName = word(2, dt:C1[theRow], "_W");
memoryWaferID = word(3, dt:C1[theRow], "_W");
memoryT0 = word(4, dt:C1[theRow], "_W");
memory1strun = word(5, dt:C1[theRow], "_W:");
memoryIndexX = num(word(2, dt:C1[theRow], ": "));
memoryIndexY = num(word(3, dt:C1[theRow], ": "));
projFlag = 0;
,
dt:C1[theRow] == "DataName",
colList = {};
col=2;
while( column(dt,col)[theRow] != "",
insert into(colList, column(dt,col)[theRow]);
col++
);
dtOut = New Table( "Lot " || memoryLotName || " WaferID " || memoryWaferID,
new column( "Project Name", character),
new column( "Lot Name", character),
new column( "WaferID", character),
new column( "Time Readout", character),
new column( "Personal Note", character),
new column( "Index X", numeric, ordinal),
new column( "Index Y", numeric, ordinal)
);
for each( {colName}, colList,
dtOut << new column( eval(colName), numeric, continuous);
);
,
dt:C1[theRow] == "DataValue",
dtOut << Add Rows(1);
dtOut:Project Name[nrows(dtOut)] = memoryProjectName;
dtOut:Lot Name[nrows(dtOut)] = memoryLotName;
dtOut:WaferID[nrows(dtOut)] = memoryWaferID;
dtOut:Time Readout[nrows(dtOut)] = memoryT0;
dtOut:Personal Note[nrows(dtOut)] = memory1strun;
dtOut:Index X[nrows(dtOut)] = memoryIndexX;
dtOut:Index Y[nrows(dtOut)] = memoryIndexY;
for each( {colName, index}, colList,
column( dtOut, colName )[nrows(dtOut)] = column(dt,index+1)[theRow]
)
)
);
Re: Pregunta de principiante sobre la generación (extracción) de tablas de datos a partir de datos de sondeo sin procesarHola txnelson , muy bien dicho. Disculpa mi pereza. Sé que podría averiguar la respuesta por mí mismo si le dedico tiempo (y eso me hace bien a largo plazo), pero me sentí presionado a obtener la respuesta correcta lo antes posible.
Volveré y ayudaré a los recién llegados como lo has estado haciendo cuando adquiera experiencia. Creo que esta es una verdadera comunidad de usuarios donde todos se ayudan entre sí. Cada respuesta se personaliza según las necesidades individuales. JMP realmente debería incentivar a los usuarios activos aquí. Espero que tu respuesta en este hilo también beneficie a otros usuarios ingenieros.
Re: Pregunta de principiante sobre la generación (extracción) de tablas de datos a partir de datos de sondeo sin procesarHola txnelson , ¡funciona! Literalmente necesitaré este script para mi informe de la próxima semana. ¡¡¡Gracias!!!
Mientras tanto ¿podrías hacerle algunas mejoras si no es demasiado complicado?
1. Falta la información del subsitio (columna).
//Para ayudar a los futuros observadores, una oblea tiene múltiples retículas (también conocidas como campo de pasos o matriz); cada retícula tiene su propio índice único (índice X, índice Y); cada retícula tiene numerosos dispositivos llamados "subsitio" (también conocidos como subdie). La medición se realiza por subsitio-retícula-oblea.

2. Imprima todos los DP en una única tabla JMP
//Sin pensarlo demasiado, apliqué tu script a todo mi archivo raw (cientos de DP...), puedes imaginar lo que pasó: luché con numerosas ventanas JMP que aparecían constantemente y finalmente me rendí recurriendo al administrador de tareas...
3. Cambie las propiedades de la columna de la parte de la tabla de datos de caracteres a numéricas.
4. ¿Es posible comprimir la codificación en un formato más conciso?
//El código actual es muy intuitivo, ideal para mí como principiante. Pero, en el futuro, un código más corto podría ser más fácil de usar. Olvídelo si es complicado o ya no es fácil de usar para quienes lo ven por primera vez.
Re: Pregunta de principiante sobre la generación (extracción) de tablas de datos a partir de datos de sondeo sin procesarHola jthi , ¡te lo agradezco! Seguro que más adelante dedicaré tiempo a aprender sobre esta función de expresión regular.
Espero que este hilo no solo me brinde las respuestas que necesito (realmente lo agradezco), sino que también sirva como plantilla inicial para tareas similares de escaneo y extracción de JMP. ¡Guardaré todos los scripts para mis futuros trabajos!
Solo para contribuir más con este tema, el problema más probable cuando uso estos scripts es la consistencia del formato de identificación del trabajo . Preste mucha atención a cómo construir la identificación del trabajo y no la cambie arbitrariamente, ya que distorsionaría la programación si no se sigue. Para dar dos ejemplos, mi formato estándar de identificación del trabajo es: Projname_Lot id_wafer id_personal nota: índice X índice Y
Pero, dado que se trata de una prueba de banco y nombré manualmente todas las pruebas, hubo algunos casos en los que yo mismo violé la regla y NO seguí EXACTAMENTE el estilo anterior:
1. omití el "_" entre el ID del lote y el ID de la oblea, por ejemplo, en lugar de "753367.1_W11", escribí "753367.1W11" en algunos casos;
2. Agregué dos notas personales en lugar de una: por ejemplo, cuando hago una nueva prueba después de la primera ejecución, en lugar de usar "_2nd_", usé "_1st_redo_". Dado que uso "_" como divisor de la sección de información, causaría problemas allí, además de cualquier cosa que siga a esa sección, ya que el conteo se desordena.
¡Gracias nuevamente a jthi y txnelson por ayudarme a dar mi primer paso en el scripting JMP avanzado!
Re: Pregunta de principiante sobre la generación (extracción) de tablas de datos a partir de datos de sondeo sin procesarSegún la aplicación que utilices, es posible que puedas hacer que el analizador sea más robusto buscando patrones repetidos en lugar de depender de patrones de expresiones regulares que coincidan con líneas específicas. Por ejemplo, parece que el nombre de tu proyecto está entre las líneas de metadatos.

Dependiendo de las suposiciones que pueda hacer, podría extraerlo basándose en esos MetaData y líneas "vacías" en lugar de confiar en "la línea comienza con Proj" o "la línea coincide con este patrón de expresión regular".
Re: Pregunta de principiante sobre la generación (extracción) de tablas de datos a partir de datos de sonda sin procesarHola Jthi,
Me aparece este error al ejecutar este script. ¿Podrías ayudarme?

Re: Pregunta de principiante sobre la generación (extracción) de tablas de datos a partir de datos de sonda sin procesarInteresante punto, jthi. Lo pensaré.
Tenga en cuenta que la información está incrustada en la línea de identificación del trabajo. El principal problema radica en cómo extraerla, no en cómo localizarla. Mi lección es asegurar la coherencia del texto "la línea empieza por Proj". Es muy importante. Para confirmarlo, podríamos agregar un script de verificación de patrones y asegurarnos de que la información extraída cumpla con lo esperado. Regex es una herramienta intuitiva para este propósito.
Re: Pregunta de principiante sobre la generación (extracción) de tablas de datos a partir de datos de sonda sin procesar¿Has definido TEST_SECTION_END?
Re: Pregunta de principiante sobre la generación (extracción) de tablas de datos a partir de datos de sonda sin procesarSí, estoy usando el mismo script que publicaste anteriormente.

Re: Pregunta de principiante sobre la generación (extracción) de tablas de datos a partir de datos de sonda sin procesarAh... se han eliminado por alguna razón en mi script y tendrás que determinar TEST_SECTION_END. A simple vista, podría ser lo mismo que EMPTY_LINE.