Question de débutant sur la génération de tables de données (extraction) à partir de données brutes de sondeSalut à tous, c'est mon premier message dans cette communauté. J'ai récemment changé de travail et je ferai de nombreux tests au banc et analyses de données. J'ai un peu utilisé JMP, mais rien d'avancé du tout.
À l'heure actuelle, mon test génère toujours un gros fichier CSV et les données de mesure sont enterrées avec des informations inintéressantes (telles que la configuration du test, les conditions, etc.). J'aimerais obtenir de l'aide pour extraire les informations utiles à l'aide du script JMP. et à partir de là, commencez mon apprentissage avancé des scripts.
J'explique ma tâche dans la capture d'écran ci-jointe. L'angle supérieur droit est un exemple de point de données de balayage IV (pour mesurer R) pour vous donner une idée de ce à quoi ressemble mon gigantesque CVS (il contient des centaines de structures de ce type). "Informations inintéressées sur plusieurs lignes" représente les lignes inutiles que je ne souhaite pas importer. En plus de copier et coller la partie des données I/V/R, j'aime également extraire l'identifiant du lot de tranches, l'identifiant de la tranche, l'index du réticule (ou disons le champ pas à pas) et le numéro de sous-site à partir de certaines chaînes. La case en haut à droite affiche la sortie JMP souhaitée.
En lecture facultative, il y a quelques anecdotes dans les deux cases du bas. En bas à gauche se trouvent mes commentaires généraux sur la structure des données, et en bas à droite explique la signification des chaînes où je dois extraire certaines informations.
J'espère que la capture d'écran vous fournit suffisamment d'informations pour ma question. J'avais l'habitude de faire ce travail en utilisant la macro Excel VBA : analyser les chaînes de signature de recherche, puis importer sélectivement certains caractères/chaînes/lignes à proximité de cet emplacement, puis continuer la recherche jusqu'à la fin du fichier de données brutes. Je me demande si le script JMP ferait la même chose ?
Automatisation et scriptsRe : Question de débutant sur la génération (extraction) de tables de données à partir de données brutes de sondeAucune capture d'écran. Serait-il possible de joindre un petit ensemble de données anonymisé ou un fichier .csv ?
Re : Question de débutant sur la génération (extraction) de tables de données à partir de données brutes de sondeComme d'autres l'ont dit, cela peut dépendre fortement de votre format de données réel. Vous trouverez ci-dessous un exemple utilisant la copie de données collée depuis Excel vers un fichier texte.
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");
Il utilise des expressions régulières pour rechercher des lignes spécifiques, puis les analyse. Pour les données, il trouve l'index de ligne à l'endroit où il commence, puis l'analyse en laissant JMP simplement l'ouvrir (en fonction des données réelles, cela peut nécessiter des étapes supplémentaires).

Re : Question de débutant sur la génération (extraction) de tables de données à partir de données brutes de sondeSalut pmroz, merci pour votre réponse rapide. J'ai oublié la pièce jointe lors de ma première soumission, mais en moins d'une minute, j'ai modifié le message et joint la capture d'écran. Vous pouvez vérifier à nouveau.
Également à votre demande, je télécharge l'Excel ici. J'ai supprimé la plupart des informations inutiles pour rendre le fichier propre, mais vous pouvez copier et coller la case en haut à gauche comme exemple de "données brutes".
Re : Question de débutant sur la génération (extraction) de tables de données à partir de données brutes de sondeLe format que vous affichez ne devrait pas être un gros problème à lire. Les lignes d'informations inintéressantes me préoccupent car ce qui s'y trouve peut interférer avec la lecture des données. Mon autre préoccupation est de savoir comment faire en sorte que JMP reconnaisse la ligne contenant le nom du projet. Est-ce que ça commence toujours par Proj ?
Fournir un fichier réel serait très utile.
Ré: Question de débutant sur la génération (extraction) de tables de données à partir de données de sonde brutes- J'ai oublié le sous-site, désolé. Je l'ai ajouté au script.
- Le but du forum de discussion est d'aider les utilisateurs de JMP à résoudre les problèmes qu'ils rencontrent lors de l'exécution de JMP. Il ne s'agit pas d'un service d'écriture de script gratuit. La raison pour laquelle j'écris des scripts pour les membres de la communauté est de les aider à apprendre à utiliser JSL. J'espère que les destinataires des scripts que je fournis prendront le temps d'apprendre d'eux, afin qu'ils puissent résoudre leur problème global.
- J'ai modifié les colonnes dynamiques (propriétés des colonnes de portion) pour qu'elles soient numériques
- Le script ajoute désormais chaque table créée ensemble
- Concernant la compression du code... pourquoi ? Si le but de la compression est de le rendre plus rapide, je peux accepter cela. Mais si la compression d'un morceau de code le rend plus difficile à lire par la prochaine personne qui doit le regarder, alors le code n'est pas un bon code. Par conséquent, ma réponse à votre question de savoir si le code pourrait être compressé dans un format plus concis, ma réponse est que je suis sûr que c'est possible.
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 );
Ré: Question de débutant sur la génération (extraction) de tables de données à partir de données de sonde brutesPoursuivant mon idée précédente en séparant le fichier texte en sections, puis en analysant ces sections (cet enregistrement couvre partiellement ce sujet Scripters Club 2024 : Session 2 - Préparation des données entrantes non structurées pour l'analyse ).
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);

Ré: Question de débutant sur la génération (extraction) de tables de données à partir de données de sonde brutesVoici un script qui lit les 3 données de projet trouvées dans votre exemple de fichier CSV et crée 3 tables de données distinctes.
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]
)
)
);
Ré: Question de débutant sur la génération (extraction) de tables de données à partir de données de sonde brutesSalut txnelson , bien dit. Je m'excuse pour ma paresse. Je sais que je pourrais trouver la réponse moi-même si j'y consacre du temps (et cela me fait du bien à long terme), mais je me suis senti obligé d'obtenir la bonne réponse dès que possible.
Je reviendrai et j'aiderai les nouveaux venus comme vous l'avez fait lorsque j'aurai acquis de l'expérience. Je pense qu'il s'agit d'une véritable communauté d'utilisateurs où tout le monde s'entraide. Chaque réponse est personnalisée en fonction des besoins individuels. JMP devrait vraiment motiver les utilisateurs actifs ici. J'espère que votre réponse dans ce fil de discussion profitera également aux autres utilisateurs ingénieurs.
Ré: Question de débutant sur la génération (extraction) de tables de données à partir de données de sonde brutesSalut txnelson , ça marche ! J'aurai littéralement besoin de ce script pour mon rapport de la semaine prochaine. Merci !!!~~~
En attendant, pourriez-vous apporter quelques améliorations si ce n'est pas trop compliqué ?
1. Les informations du sous-site (colonne) sont manquantes.
//Pour aider les futurs observateurs, une plaquette comporte plusieurs réticules (alias champ pas à pas ou matrice) ; chaque réticule possède son propre indice unique (index X, index Y) ; chaque réticule possède de nombreux dispositifs appelés « sous-site » (alias sous-matrice). La mesure est effectuée par sous-site-réticule-plaquette.

2. Exportez tous les DP dans une seule table JMP
//Sans trop réfléchir, j'ai appliqué votre script à mon fichier brut complet (des centaines de DP...), vous pouvez imaginer ce qui s'est passé : je me suis battu avec de nombreuses fenêtres JMP qui apparaissaient sans cesse, et j'ai finalement abandonné en me tournant vers le gestionnaire de tâches...
3. Modifiez les propriétés de la colonne de la partie du tableau de données de caractère à numérique.
4. Est-il possible de compresser le codage dans un format plus concis ?
//Le code actuel est très intuitif, parfait pour moi en tant que débutant. Mais, à l'avenir, un code plus court pourrait être plus convivial. Veuillez l'oublier s'il est compliqué ou n'est plus convivial pour le premier utilisateur.
Ré: Question de débutant sur la génération (extraction) de tables de données à partir de données de sonde brutesSalut jthi , merci beaucoup ! Je vais certainement consacrer du temps à en apprendre davantage sur cette fonction regex plus tard.
J'espère que ce fil de discussion me donnera non seulement les réponses dont j'ai besoin (vraiment apprécié), mais servira également de modèle de départ pour des tâches JMP d'analyse et d'extraction similaires. Je conserverai tous les scripts pour mes futurs travaux !
Juste pour contribuer davantage à ce sujet, le problème le plus probable lorsque j'utilise de tels scripts est la cohérence du format de l'ID de tâche . Faites très attention à la façon dont vous construisez l'ID de tâche et ne le modifiez pas arbitrairement, ce qui fausserait la programmation si vous ne le respectez pas. Pour donner deux exemples, le format standard de mon ID de tâche est : Nom du projet_ID du lot_ID de la plaquette_ID personnel Remarque : index X index Y
Mais, comme il s'agit d'un test sur banc et que j'ai nommé manuellement tous les tests, il y a eu des cas où j'ai moi-même violé la règle et je n'ai PAS EXACTEMENT suivi le style ci-dessus :
1. j'ai manqué le "_" entre l'identifiant du lot et l'identifiant de la plaquette, par exemple, au lieu de "753367.1_W11", j'ai tapé "753367.1W11" dans certains cas ;
2. j'ai ajouté deux notes personnelles au lieu d'une : par exemple, lorsque je fais un nouveau test après la première exécution, au lieu d'utiliser "_2nd_", j'ai utilisé "_1st_redo_". Étant donné que j'utilise "_" comme séparateur de section d'informations, cela poserait des problèmes à cet endroit ainsi qu'à tout ce qui suit cette section, car le comptage se dérègle.
Merci encore à jthi et txnelson de m'avoir aidé à faire mon premier pas sur le script JMP avancé !
Ré: Question de débutant sur la génération (extraction) de tables de données à partir de données de sonde brutesEn fonction de votre application, vous pourrez peut-être rendre l'analyseur plus robuste en recherchant des modèles répétitifs au lieu de vous fier à des modèles regex correspondant à des lignes spécifiques. Par exemple, il semble que le nom de votre projet se trouve entre les lignes MetaData

En fonction des hypothèses que vous pouvez faire, vous pouvez l'extraire en vous basant sur ces métadonnées et ces lignes « vides » au lieu de vous fier à « la ligne commence par Proj » ou « la ligne correspond à ce modèle d'expression régulière ».
Ré : Question de débutant sur la génération (extraction) de tables de données à partir de données de sonde brutesSalut Jthi,
J'obtiens cette erreur lors de l'exécution de ce script. Pourriez-vous m'aider ?

Ré : Question de débutant sur la génération (extraction) de tables de données à partir de données de sonde brutesPoint intéressant, jthi. J'y réfléchirai.
Notez que les informations sont intégrées à la ligne d'identifiant du travail. Le principal problème réside dans leur extraction, et non dans leur localisation. Ma leçon est de garantir la cohérence de la mention « la ligne commence par Proj ». C'est très important. Pour le confirmer, nous pourrions ajouter un script de vérification de modèle et nous assurer que les informations extraites sont conformes aux attentes. Regex est un outil intuitif pour cela.
Ré : Question de débutant sur la génération (extraction) de tables de données à partir de données de sonde brutesAvez-vous défini TEST_SECTION_END ?
Ré : Question de débutant sur la génération (extraction) de tables de données à partir de données de sonde brutesOui, j'utilise le même script que vous avez publié plus tôt.

Ré : Question de débutant sur la génération (extraction) de tables de données à partir de données de sonde brutesAh… ils ont été supprimés pour une raison quelconque dans mon script et vous devrez déterminer TEST_SECTION_END. En y regardant de plus près, cela pourrait être la même chose que EMPTY_LINE.