行から単語を列名として抽出し、対応する数値を値として列に抽出します。「障害」という名前の列があり、さまざまなデバイスから抽出された障害コードが含まれています。 特定の日の障害コードの 1 つを以下に示します。
「インバータ インバータ 20 が制限値を下回る: 0.96 キロワット/インバータ (1.63 キロワットの 58.9 %)、2019 年 11 月 30 日午前 7:30:00 (太陽 az: 123.4 el: 3.7) 継続時間: 4.00 時間 インバータ インバータ 23 が制限値を下回る: 0.95キロワット/インバーター (1.63 キロワットの 57.9 %)、2019 年 11 月 30 日午前 7 時 30 分: 00 (sun az: 123.4 el: 3.7) 継続時間: 3.50 時間
目標は、分析を実行して、故障したインバータを日付ごとに表にし、その累積的なパフォーマンスと期間を集計することです。後で他の値を使用して障害を診断します。
次の形式で詳細を抽出する必要があります ----列名:値
インバーター:20台
限界以下(kW/インバータ) : 0.96
最大値の%: 58.9%
日付 2019 年 11 月 30 日
時間 : 午前7時30分00秒
サンアズ : 123.4
標高:3.7
所要時間 (時間) : 4
2 番目のインバータにも障害コードがある場合 (上記の障害コードの 2 行目を参照)
インバーター:23台
限界以下(kW/インバータ) : 0.95
最大値の%: 57.9%
日付 2019 年 11 月 30 日
時間 : 午前7時30分00秒
サンアズ : 123.4
標高:3.7
所要時間 (時間) : 3.50
場合によっては、1 行で同様のコードを与える可能性のあるインバーターが (70 個中) 5 個または 10 個存在する場合があります。
これを行う方法を教えていただけますか。 JSL経由のみですか?それとも数式を使えばいいのでしょうか? いずれにせよ、助けが必要です。
高度な統計モデリング自動化とスクリプト作成消費者および市場調査マスカスタマイゼーション品質およびプロセスエンジニアリングRe: 行から単語を列名として抽出し、対応する数値を値として列に抽出するこんにちは、SunnyR さん
これが古い投稿であることは承知していますが、この問題は興味深いと思い、私があなたと似たような状況で時々使用するアイデアを共有したいと思いました。 データが適切に構造化されており、複雑すぎない場合、これは非常に強力 (そしてシンプル) です。
注: この特定のソリューションでは、現在ログが単一のデータ列 (テーブル内の唯一のデータ列) に存在していることを前提としています。 おっしゃるとおり、行ごとに異なる数のインバーター ログが含まれる場合があります。
「時間」という単語は各インバーターのログの最後にのみ出現することに気付きました。そのため、この方法でログ記録を分割し、データを積み重ねることができます。 それが完了したら、数字を維持するためにテキストを分割します。 すべてのログに同じテキストと測定値があり、常に同じ順序であることが重要です。そのため、テキストを分割すると、これらが列に整列されます。
すべての列を数値に変換します。これにより、数値以外のデータ、つまり欠落したデータが明らかになります。 数値以外のデータを削除し、列の名前を変更すれば完了です。
これがどのように機能するかを確認できるように、テーブル スクリプトを含む表を添付しました。
Names Default To Here( 1 );
dt = :log << get data table; // for use within a table script. otherwise, use dt = current data table();
// can break up the logs at "hours". Replace with ~ or some other unused character to delimit.
For( i = 1, i <= N Row( dt ), i++,
dt:log[i] = Substitute( dt:log[i], "hours", "~" )
);
//split the logs using this delimiter
dt << Text to Columns( delimiters( "~" ), columns( :log ) );
// some logs had more inverters than others, so the stack my have empty data in some rows. Delete them.
dt2 = dt << stack( columns( (dt << get column names)[2 :: N Col( dt )] ) );
dt2 << delete rows(dt2 << get rows where (:data == ""));
//using parens and spaces as delimiters, break up each log
dt2 << text to columns( delimiters( " ()" ), columns( :data ) );
//deal with date and time. They're always in the same columns, making this easier
dt2 << New Column( "date", formula( Informat( :data 14 ) ) );
dt2 << New Column( "time", formula( Informat( :data 15 || " " || :data 16 ) ) );
dt2:date << Delete Formula;
dt2:time << Delete Formula;
dt2 << delete columns( {"data 14", "data 15"} ); //else these persist later, as they are numeric
//Remove non-numeric columns by changing all columns to numeric and removing those containing only missing data.
//Proceed "backward" as deletions change indices.
For( i = N Col( dt2 ), i >= 1, i--,
Column( dt2, i ) << set data type( numeric );
If( N Row( Loc( dt2:i << get values ) ) == 0, dt2 << delete columns( i ) );
);
//rename columns and reformat date and time.
colNames = Words( "Inverter,Below Limit(kw/inverter),% of max,Max,Sun Az,Elevation,Duration", "," );
For( i = 1, i <= N Items( colNames ), i++, Column( dt2, i ) << set name( colNames[i] ) );
dt2:date << Format( "m/d/y" );
dt2:time << Format( "h:m:s" );Re: 行から単語を列名として抽出し、対応する数値を値として列に抽出するすばらしい! 私の要求を達成するためにこの長いコードを辛抱強く書いていただきありがとうございます。 これを私が持っている他のアラート コードに実装しようとしています。本当にありがとう。これにより、長い間私は救われました。
Re: 行から単語を列名として抽出し、対応する数値を値として列に抽出する暇な時間があったので、Covid-19 がまだ流行しているので他にやることはあまりないので、データの読み込みを始めるのに適した JSL を少し書きました。
Names Default To Here( 1 );
dt = Open(
"Path to the data file",
columns( New Column( "c000001", Character, "Nominal" ) ),
Import Settings(
End Of Line( CRLF, CR, LF ),
End Of Field( CSV( 0 ) ),
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 ),
Data Starts( 1 ),
Lines To Read( "All" ),
Year Rule( "20xx" )
)
);
// Create the new output data table
dtLong = New Table( "Long Data",
New Column( "Label", character ),
New Column( "Value", character ),
New Column( "Line" ),
New Column( "Instance" )
);
// A function that returns the next word in the line and
// then removes the word from the front of the target line
getWord = Function( {},
theWord = Trim( Word( 1, target, " " ) );
target = Trim( Substr( target, Length( theWord ) + 1 ) );
theWord;
);
// Loop through all rows in the input data table
For( i = 1, i <= N Rows( dt ), i++,
instance = 0;
target = Column( dt, 1 )[i];
While( Word( 1, target, " " ) != "",
dtLong << add rows( 1 );
dtLong:line[N Rows( dtLong )] = i;
theWord = getWord();
Match( theWord,
"inverter",
instance++;
dtLong:Instance[N Rows( dtLong )] = instance;
dtLong:Label[N Rows( dtLong )] = theWord;
theWord = getWord();
theWord = getword();
dtLong:value[N Rows( dtLong )] = theWord;,
"below",
dtLong:Instance[N Rows( dtLong )] = instance;
dtLong:Label[N Rows( dtLong )] = theWord || " limit (KW/Inverter)";
theWord = getWord();
theWord = getWord();
dtLong:value[N Rows( dtLong )] = theWord;
// Get the % of Max
dtLong << Add Rows( 1 );
dtLong:line[N Rows( dtLong )] = i;
dtLong:Instance[N Rows( dtLong )] = instance;
theWord = getWord();
theWord = getWord();
dtLong:Label[N Rows( dtLong )] = "% of Max";
dtLong:value[N Rows( dtLong )] = Substr( theWord, 2 );
// Skip forward to the Date
For( k = 1, k <= 5, k++,
theWord = getWord()
);
// Get the Date
dtLong << add rows( 1 );
theWord = getWord();
dtLong:Instance[N Rows( dtLong )] = instance;
dtLong:line[N Rows( dtLong )] = i;
dtLong:Label[N Rows( dtLong )] = "Date";
dtLong:value[N Rows( dtLong )] = theWord;
// Get the Time
dtLong << add rows( 1 );
theWord = getWord();
dtLong:Instance[N Rows( dtLong )] = instance;
dtLong:line[N Rows( dtLong )] = i;
dtLong:Label[N Rows( dtLong )] = "Time";
dtLong:value[N Rows( dtLong )] = theWord || getWord();
// Get the Sun Az
dtLong << add rows( 1 );
theWord = getWord();
dtLong:Instance[N Rows( dtLong )] = instance;
dtLong:line[N Rows( dtLong )] = i;
dtLong:Label[N Rows( dtLong )] = Substr( theWord, 2 ) || " " || getWord();
dtLong:value[N Rows( dtLong )] = getWord();
// Get the Elevation
dtLong << add rows( 1 );
theWord = getWord();
dtLong:Instance[N Rows( dtLong )] = instance;
dtLong:line[N Rows( dtLong )] = i;
dtLong:Label[N Rows( dtLong )] = "Elevation";
dtLong:value[N Rows( dtLong )] = Word( -1, getWord(), ")" );,
"Duration:",
dtLong:Instance[N Rows( dtLong )] = instance;
dtLong:Label[N Rows( dtLong )] = theWord || " (hrs)";
dtLong:value[N Rows( dtLong )] = getWord();
theWord = getWord();
)
;
);
);Re: 行から単語を列名として抽出し、対応する数値を値として列に抽出するジム
提案ありがとう。 試してみます。 私はスクリプト作成が初めてなので、例を見て理解していきます。
Re: 行から単語を列名として抽出し、対応する数値を値として列に抽出する私もこのようなデータを扱う必要が何度もありました。私が取るべきだと思うアプローチは、入力ファイルからすべてのデータを JMP データ テーブルに読み込み、完全な各行が 1 つの列に読み込まれることです。最終的には、1 列のデータ テーブルが作成され、行数は入力データ テーブルの行数と同じになります。
次に、Label、Value、Line の 3 つの列を持つ新しいテーブルを作成します。次に、1 つの列の各行の内容をスキャンする JSL を使用して、新しいテーブルに新しい行を作成し、ラベル (つまり、インバーター、制限未満 (KW/インバーター) など)、値 (つまり 20) を設定します。 、0.96 など) と Line (現在の行番号になります....Row())。また、ライン上の 1 番目のインバータ、または 2 番目のインバータなどに基づく追加の出力列も必要になる場合があります。
これは、区切り文字として「:」をスキャンする Word() 関数と While() 関数を組み合わせて使用することで実行できます。奇数番号のワードはラベル、偶数番号のワードは値になります。
この新しいテーブルを作成したら、Tables=>Split を使用して、インバータごとに 1 行に簡単に移動できます。
Re: 行から単語を列名として抽出し、対応する数値を値として列に抽出するデイブ、
はい、障害のあるインバーターが 1 つまたは 2 つだけであれば可能ですが、たとえば、1 つの日付に対して 1 行に 23 の障害コードがある場合は、非常に多くの列を個別に作成し、それぞれの数式を作成する必要があります。インバーター23台。 私があなたの解決策を理解しているかどうか、明確にしていただけますか。また、抽出後の分析の目的を要約する行を追加しました。
Re: 行から単語を列名として抽出し、対応する数値を値として列に抽出する数式エディタを使用すると、かなりの作業を進めることができるはずです。WORD 関数を見てください。