효율적인 이동 평균 알고리즘<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />안녕하세요,
이전에 여기에 게시한 사람들 덕분에 몇 가지 유용한 답변을 찾았습니다!
오실로스코프에서 가져온 여러 개의 큰 데이터 세트(각각 2천만 포인트!)가 있습니다. 이동 평균을 계산하고 싶습니다. 하지만 제가 고안한 알고리즘은 매우 느립니다. 내 수식에 대한 코드는 다음과 같습니다.
"
If(Row() < 100, Empty(), 합계(i = Row() - 99, Row(), :Current[i,Empty()]) / 100)
"

평균 창의 너비(이 경우 100개 샘플)가 커지면(예: 500, 1000 또는 50000 이상) 계산 시간이 불합리해집니다. 누군가 이동 평균을 수행하는 더 빠른 방법이 있습니까?
감사해요!
덴마크 사람
Re: 효율적인 이동 평균 알고리즘나는 일반적으로 테이블을 모두 피할 수 있다면 더 빠릅니다. 이것은 내 컴퓨터에서 더 빠르게 실행됩니다. 내 번호도 Jeffs와 다르다는 것을 알 수 있습니다. 그것은 단순히 끝에 있는 숫자를 미러링한 다음 중앙에서 (마지막 x 포인트가 아니라) x 포인트를 이동하기 때문입니다. 또한 누락된 값의 가중치가 있으므로 누락된 값이 있어도 문제가 되지 않습니다. 적어도 나는 그렇게 생각한다. 끝에 열이 필요하지 않으면 더 빠릅니다. 그리고 기본적으로 결합된 인덱스 행렬이기 때문에 매우 빠릅니다.
Names Default to here(1);
dt = open("$SAMPLE_DATA\Big Class.jmp");
st1 = HPtime();
mat = :height << Get Values;
//number of rows you want to average
x= 5;
//+- gap
z = (x-1)/2;
//get the rows
rows = 1::nrows(mat);
//mirror the rows on the front and back
mirrored = ((z+1)::2)||rows||((ncol(rows)-1)::(ncol(rows)-z));
big_mat = [];
for(i=0, i<=x-1, i++,
//this is cutting up the longer mirrored vector into x vectors of the same length as the original
big_mat ||= mat[mirrored[rows+i]];
);
//now we can just take a VSum of the transpose /x to get our average
Squasher = !ismissing(big_mat); //everywhere there's a non-missing, make 1
Squasher = VSum(Squasher`); //count real numbers, this is to not weight non-missings
A = Vsum(big_mat`)/x;
New Column("Moving Average", Set Values(A)); //If you don't need this column
//and you're just doing matrix operations this is actually about half the total time
en1 = HPTime()-st1;
// Data Table method
st2 = HPTime();
dt<< New Column("moving sum(x)", formula(If(Row()<=:Moving Avg Window,
If( Row() == 1,
:height,
Lag( :Name( "moving sum(x)" ), 1 ) + :height
),
(Lag( :Name( "moving sum(x)" ), 1 ) + :height) -
Lag( :height, :Moving Avg Window )
)));
dt<< New Column("Moving Avg", Formula(
If(Row()>=:Moving Avg Window,
:Name( "moving sum(x)" ) / :Moving Avg Window,
.
)));
en2 = HPTime()-st2;
show(en1, en2);Re: 효율적인 이동 평균 알고리즘훌륭한 솔루션입니다. 데이터 열의 누락된 값(이 예에서는 "현재")은 첫 번째 누락 데이터가 발생한 행에서 아래의 모든 행까지 계산된 데이터 열에 빈 값을 생성합니다. 알고 있어야 할 작은 문제입니다.Re: 효율적인 이동 평균 알고리즘고마워, 제프. 합산 방법보다 훨씬 빠르게 실행됩니다!
Re: 효율적인 이동 평균 알고리즘여기서 몇 가지 전략을 제시할 수 있습니다.
둘 다 현재 사용 중인 Summation() 연산자보다 더 효율적이라고 생각합니다. 하지만 가장 효율적이라고 할 수는 없습니다.
1) 행렬에서 Sum() 함수를 사용합니다.
If(Row()<:Moving Avg Window,
.,
Sum( :Current[Index( Row() - (:Moving Avg Window - 1), Row() )] ) / :Moving Avg Window
)

이것은 매트릭스 연산의 속도를 이용합니다. 의 첨자 현재의 이 수식의 열은 이동 평균 창의 시작부터 현재 행 번호까지의 행 번호 행렬입니다. 이 방식으로 열을 첨자화하면 JMP는 행렬을 반환하고 Sum 함수는 행렬에 비해 상대적으로 효율적입니다.
훨씬 더 빠른 방법은 두 열에 대해 이 이동 평균을 계산하는 것입니다. 첫 번째 열은 단순히 다음 값을 추가하여 이동 합계를 유지합니다. 현재의 한 행에서 이전 행의 롤링 합계 값으로 변경한 다음 창 시작 부분의 행에서 Current 값을 뺍니다.
이동 합계 공식은 다음과 같습니다.
If(Row()<=:Moving Avg Window,
If( Row() == 1,
:Current,
Lag( :Name( "moving sum(x)" ), 1 ) + :Current
),
(Lag( :Name( "moving sum(x)" ), 1 ) + :Current) -
Lag( :Current, :Moving Avg Window )
)

그런 다음 나누는 열을 갖는 것이 쉽습니다. 이동 합계 의해 이동 평균 창 .
If(Row()>=:Moving Avg Window,
:Name( "moving sum(x)" ) / :Moving Avg Window,
.
)

이 두 가지 방법을 모두 보여주는 데이터 테이블을 첨부하고 있습니다. 데이터 테이블에는 이동 평균 창 이다 데이터 테이블 변수 .
이 데이터 테이블에서 두 번째 방법의 효율성을 보려면 다음을 수행할 수 있습니다. 평가를 억제하다 의 의 이동 평균(x) 먼저 열.
-제프