FOR() 루프를 기반으로 한 (느린) JSL 코드 최적화안녕하세요,
신뢰성 데이터 분석을 위한 코드를 작성해야 합니다.
실험이 시작되기 전에(REL_T0) 여러 지표(metric1, metric2,...metricN)가 측정된 다음 각 드롭 이벤트(DROP1, DROP2,...DROPN...) 후에 다시 측정됩니다.
내 목표는 REL_T0과 각 일련 번호 및 각 지표에 대한 드롭 이벤트 후 각 측정값 사이의 드리프트 값을 계산하는 것입니다.
내 초기 코드는 FOR() 루프(확실히 최적이 아닌 것으로 알고 있음)를 기반으로 하며 작은 데이터 세트에서는 잘 작동합니다.
그럼에도 불구하고 더 큰 데이터 세트에서 더 빠르게 실행되도록 코드를 최적화해야 합니다.
현재 10,000개의 행과 50개의 측정항목을 사용하면 프로세스를 완료하는 데 약 20분이 소요되는데 이는 너무 많은 시간입니다.
FOR() 루프를 다르게 구성하려고 시도했지만 큰 영향은 없었습니다.
JSL 독점 명령을 사용하여 훨씬 더 빠른 방법으로 이러한 간단한 계산을 수행할 수 있는 방법이 있다고 확신합니다.
여러분은 어떻게 생각하시나요?
아래 코드는 더미 테이블을 생성한 다음 초기 코드를 실행하여 계산된 드리프트가 포함된 새 열 "Δ_metricN"으로 끝납니다.
FOR() 루프 대신 JSL 명령을 사용하여 동일한 작업을 수행하여 코드를 매우 빠르게 만들고 싶습니다!
많은 감사드립니다.
설교자.
//Create dummy table
RawData = New Table( "RawData",
Add Rows( 20 ),
New Column( "serial_number", Character, set values( {"A","A","A","A","A","A","A","B","B","B","B","B","B","C","C","C","C","C","C","C"})),
New Column( "rel_event", Character, set values( {
"REL_T0","DROP1","DROP2","DROP3","DROP4","DROP5","DROP6",
"REL_T0","DROP1","DROP2","DROP3","DROP4","DROP5",
"REL_T0","DROP1","DROP2","DROP3","DROP4","DROP5", "DROP6"})),
New Column("metric1", Continuous, set values({1,2,3,5,7,10,13,2,4,5,6,8,11,1,2,4,5,5,9,12}) ),
New Column("metric2", Continuous, set values({2,3,4,7,9,14,18,2,3,4,7,9,14,2,5,7,8,9,11,13}) );
);
RawData << save( "$Desktop\RawData.jmp" );
Column(RawData, "rel_event") << Set Property( "Value ordering", {"REL_T0","DROP1","DROP2","DROP3","DROP4","DROP5","DROP6"} );
//Create handle for data table to be analyzed
RawData = Current Data Table();
ChosenDataCol = {"metric1", "metric2"};
NumDataCol = N Items( ChosenDataCol );
NumRow = N Row( RawData );
RawDataCol = RawData << get column names;
Show( NumDataCol );
Show( ChosenDataCol );
Show( RawData );
Show( NumRow );
Show( RawDataCol );
//Scan each selected data row for which Deltas must be computed
For( cpt = 1, cpt <= NumDataCol, cpt++,
//Create column to receive delta data
DeltaCol = RawData << New Column( "∆_" || Char( ChosenDataCol[cpt] ), Numeric, "Continuous" );
TargetCol = Column( RawData, ChosenDataCol[cpt] );
serial_numberlist = {}; //List of unique serial_number's within the data table of interest
Show( cpt );
Show( ChosenDataCol[cpt] );
For( i = 1, i <= NumRow, i++,
Currentserial_number = :serial_number[i];
If( Contains( serial_numberlist, Currentserial_number ) == 0,
Insert Into( serial_numberlist, Currentserial_number )
);
);//For i
Show( serial_numberList );
Numserial_number = N Items( serial_numberlist );
Show( Numserial_number );
//Scan data table for each unique serial_number
For( i = 1, i <= Numserial_number, i++,
Currentserial_number = serial_numberList[i];
Currentserial_numberrows = RawData << GetRowsWhere( :serial_number == Currentserial_number ); //matrix of rows containing current serial_number
Show( Currentserial_numberrows );
NumCurrentserial_numberrows = N Row( Currentserial_numberrows );
Show( NumCurrentserial_numberrows );
show(i);
TzeroExist = 0;
TzeroVal = 0;
//identify Time Zero value for each serial_number under consideration
For( j = 1, j <= NumCurrentserial_numberrows, j++,
CurrentRead = :rel_event[Currentserial_numberrows[j]];
Show( CurrentRead );
If( CurrentRead == "REL_T0",
TzeroVal = TargetCol[Currentserial_numberrows[j]];
Show( TzeroVal );
TzeroExist = 1;
);
); //For j
//Calculate Drift
For( j = 1, j <= NumCurrentserial_numberrows, j++,
If( TzeroExist == 1,
DeltaCol[Currentserial_numberrows[j]] = TargetCol[Currentserial_numberrows[j]] - TzeroVal
)
); //For j
);//For i
);//For cpt 고급 통계 모델링자동화 및 스크립팅Re: FOR() 루프를 기반으로 한 (느린) JSL 코드 최적화답변해 주셔서 감사합니다.
For Each Row()를 사용하는 아이디어가 마음에 듭니다. 이는 전체 스크립트를 단순화합니다.
그러나 더 많은 컨텍스트를 추가하고 스크립트를 더욱 강력하게 만들기 위해 REL_T0이 항상 일련 번호당 첫 번째 행이 아닐 수도 있습니다(데이터베이스가 항상 JMP 테이블에서 올바른 순서로 데이터를 쿼리하는 것은 아닙니다). 드리프트도 양수일 수 있습니다. 또는 부정적이므로 Col Min()이 여기에 잘 맞는지 모르겠습니다(아마도 제가 제대로 읽지 않았을 수도 있습니다).
일련 번호별로 start_row를 REL_T0 값에 직접 고정할 수 있습니까?
Re: FOR() 루프를 기반으로 한 (느린) JSL 코드 최적화예, 해당 스크립트를 약간만 변경하면 가능합니다. 올바른 행과 일치하는지 표시하기 위해 제거할 수 있는 디버그 열을 추가했습니다.
Names Default To Here(1);
dt = New Table("RawData",
Add Rows(27),
Compress File When Saved(1),
New Column("serial_number",
Character,
"Nominal",
Set Values(
{"A", "A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B", "C", "C", "C", "C", "C", "C", "C", "D", "D", "D", "D", "D", "D", "D"}
)
),
New Column("rel_event",
Character,
"Nominal",
Set Values(
{"REL_T0", "DROP1", "DROP2", "DROP3", "DROP4", "DROP5", "DROP6", "REL_T0", "DROP1", "DROP2", "DROP3", "DROP4", "DROP5", "REL_T0", "DROP1",
"DROP2", "DROP3", "DROP4", "DROP5", "DROP6", "DROP1", "DROP2", "DROP3", "REL_T0", "DROP4", "DROP5", "DROP6"}
)
),
New Column("metric1",
Numeric,
"Continuous",
Format("Best", 10),
Set Values([1, 2, 3, 5, 7, 10, 13, 2, 4, 5, 6, 8, 11, 1, 2, 4, 5, 5, 9, 12, 1, 2, 4, 5, 5, 9, 12])
),
New Column("metric2",
Numeric,
"Continuous",
Format("Best", 10),
Set Values([2, 3, 4, 7, 9, 14, 18, 2, 3, 4, 7, 9, 14, 2, 5, 7, 8, 9, 11, 13, 2, 5, 7, 8, 9, 11, 13])
)
);
debugcol = dt << New Column("REL_T0_ROW", Numeric, Continuous);
delta1col = dt << New Column("delta1", Numeric, Continuous);
delta2col = dt << New Column("delta2", Numeric, Continuous);
For Each Row(dt,
// find REL_T0 row for current serial_number
start_row = Col Min(If(:rel_event == "REL_T0", Row(), .), :serial_number);
debugcol[Row()] = start_row;
delta1col[Row()] = :metric1 - :metric1[start_row];
delta2col[Row()] = :metric2 - :metric2[start_row];
);

Re: FOR() 루프를 기반으로 한 (느린) JSL 코드 최적화정말 고마워요 Jarmo!
나는 18000개의 행과 2개의 측정항목이 있는 데이터 테이블에 이 새 버전을 사용해 보았습니다.
- 기존 방식 : ~5분
- 원하는 방법: <2분
벌써부터 엄청난 발전이군요!!!
다시 한번 감사드립니다!!
설교자
Re: FOR() 루프를 기반으로 한 (느린) JSL 코드 최적화안녕하세요 호기님
제안해 주셔서 감사합니다. Normalization 추가 기능과 관련된 게시물을 확인했습니다. 앞으로의 프로젝트에도 꼭 명심하겠습니다.
설교자
Re: FOR() 루프를 기반으로 한 (느린) JSL 코드 최적화이러한 계산을 수행하기 위해 행렬을 사용하면 추가 속도 향상을 매우 쉽게 수행할 수 있습니다. 또한 추가
dt << begin data update;
루프 전과
dt << end data update;
특히 테이블이 "지연"되므로 테이블이 보이지 않거나 비공개로 열리지 않는 경우 테이블의 시각적 개체가 업데이트됩니다.
Re: FOR() 루프를 기반으로 한 (느린) JSL 코드 최적화측정 데이터의 정규화는 데이터 분석의 일반적인 작업입니다.
정규화 GUI는 이를 위한 다양한 옵션을 제공합니다.
GUI에서 사용자는 다양한 설정을 지정할 수 있으며 AddIn은 해당 코드를 생성합니다.
생성된 수식은 Col Min, Col Max, Col Median ...과 같은 Col ... 집계를 기반으로 합니다.
다른 옵션:

이 응용 사례의 경우 "첫 번째"( ColMin(row()) 논리 기반)를 사용할 수 있습니다.
... 또는 "정규화를 위한 하위 집합 사용"을 통해 참조를 지정합니다(참조 값이 "첫 번째" 값이 아닌 경우).

Re: FOR() 루프를 기반으로 한 (느린) JSL 코드 최적화(일반적으로) 속도를 향상시키는 한 가지 방법은 루프에서 모든 출력을 제거하는 것이지만, 이 경우 루프 없이 다시 작성하는 것이 더 빠르고 데이터 테이블을 살펴볼 때 for 루프를 사용하지 않는 것이 좋습니다(각 행에 대해 작성하는 것이 더 나은 옵션입니다).
다음은 더 빠른 결과를 얻을 수 있기를 바라는 한 가지 옵션입니다(이것은 수식으로도 변환할 수 있으며 필요한 경우 여전히 상당히 빠를 것입니다). 데이터가 REL_T0가 항상 각 일련 번호의 첫 번째 행이 되도록 정렬되어 있다고 가정합니다. 그렇지 않은 경우 약간의 변경이 필요합니다.
Names Default To Here(1);
//Create dummy table
RawData = New Table("RawData",
Add Rows(20),
New Column("serial_number",
Character,
set values({"A", "A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B", "C", "C", "C", "C", "C", "C", "C"})
),
New Column("rel_event",
Character,
set values(
{"REL_T0", "DROP1", "DROP2", "DROP3", "DROP4", "DROP5", "DROP6", "REL_T0", "DROP1", "DROP2", "DROP3", "DROP4", "DROP5", "REL_T0", "DROP1",
"DROP2", "DROP3", "DROP4", "DROP5", "DROP6"}
)
),
New Column("metric1", Continuous, set values({1, 2, 3, 5, 7, 10, 13, 2, 4, 5, 6, 8, 11, 1, 2, 4, 5, 5, 9, 12})),
New Column("metric2", Continuous, set values({2, 3, 4, 7, 9, 14, 18, 2, 3, 4, 7, 9, 14, 2, 5, 7, 8, 9, 11, 13}))
);
delta1col = RawData << New Column("delta1", Numeric, Continuous);
delta2col = RawData << New Column("delta2", Numeric, Continuous);
For Each Row(RawData,
// find REL_T0 row for current serial_number
start_row = Col Min(Row(), :serial_number);
delta1col[Row()] = :metric1 - :metric1[start_row];
delta2col[Row()] = :metric2 - :metric2[start_row];
);
