실행중인 중앙값을 계산하는 알고리즘?


18

작은 창 크기에서는 n log n정렬이 작동 할 수 있습니다. 이것을 달성하기위한 더 나은 알고리즘이 있습니까?


1
이것이 스택 오버플로로 옮겨진 첫 번째 후보라고 생각합니다.

아마도, SO에 대한 더 많은 설명이 필요할 것입니다.
워키 토키

2
대부분의 프로그래머는 "중앙값"을 알고 있습니다. (정렬 (배열)) [길이 / 2]는 잊어 버린 사람들에게 큰 힌트입니다. 또한 각각의 새로운 지점에 대해 가장 기본적으로 배열의 절반에서 이등분 / 삽입 만하면됩니다.
Paul

1
다시 오픈에서 토론 다음 meta.stats.stackexchange.com/questions/276/...
롭 Hyndman

2
주석보다 더 사소한 것은 아니지만 3의 중앙값에 대한 코드는 a + b + c-max (a, b, c)-min (a, b. c)입니다. 관계가 있어도 잘 작동합니다. 다른 사람의 코드 (왜이 경우 중간을 얻기 위해 더하고 빼는 것입니까 ???)에서 그것에 대해 생각하고 나면 다른 사람들과 동일한 반응을 보일 수 있습니다. max () 및 min ()은 종종 초고속 함수로 구현됩니다. 슬프게도 일반적으로 그러한 트릭은 없습니다.
Nick Cox

답변:



7

다음 은 하나의 가능한 알고리즘을 설명하는 기사입니다. 소스 코드가 포함되어 있고 상당히 심각한 응용 프로그램 (레이저 간섭계를 기반으로 한 중력파 감지)을 잘 테스트 할 수 있습니다.


1
링크가 깨졌으며 제목이나 저자 정보가 없으면 참조한 내용을 찾기가 어렵습니다.
Kristopher Johnson


6

근사치를 용납하려는 경우 다른 방법이 있습니다. 예를 들어 한 근사값은 순위가 실제 중앙값에서 (사용자 지정) 거리 내에있는 값입니다. 예를 들어, 중앙값은 (정규화 된) 순위가 0.5이며, 오류 항을 10 %로 지정하면 순위가 0.45와 0.55 사이 인 답이 필요합니다.

그러한 대답이 적절하면 데이터 창을 슬라이딩하는 데 사용할 수있는 많은 솔루션이 있습니다. 기본 아이디어는 특정 크기 (대략 1 / 오류 항)의 데이터 샘플을 유지하고이 샘플의 중앙값을 계산하는 것입니다. 입력의 특성에 관계없이 높은 확률로 결과 중앙값이 위에서 언급 한 속성을 만족함을 알 수 있습니다.

따라서 주요 질문은 특정 크기의 데이터에 대한 실행 샘플을 유지하는 방법이며, 저수지 샘플링이라는 기술을 포함하여 많은 접근 방식이 있습니다. 예를 들어이 백서 : http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.24.7136


4

길이가 k 인 데이터 창을 정렬 된 이중 링크 목록으로 유지하는 경우 이진 검색 (창으로 이동 할 때 각 새 요소를 삽입) 및 포인터의 원형 배열 (즉, 삭제해야 함), 창의 각 시프트에는 하나의 요소를 삽입하기위한 O (log (k)) 노력, 창 밖으로 이동 된 요소를 삭제하기위한 O (1) 노력 및 찾기위한 O (1) 노력 만 필요 중앙값 (한 요소가 목록에 삽입되거나 삭제 될 때마다 O (1) 시간에 중앙값에 대한 포인터를 업데이트 할 수 있기 때문에) 따라서 길이 N의 배열을 처리하기위한 총 노력은 O ((nk) log (k)) <= O (n log (k))입니다. 이것은 지금까지 제안 된 다른 방법보다 낫고 근사치가 아니며 정확합니다.


1
정렬 된 이중 연결 목록에서 이진 검색을 제안하는 방법에 대해 자세히 설명해 주시겠습니까?
NPE

하나의 '링크'를 사용하면 목록을 정렬 된 순서로 탐색 할 수 있습니다. 다른 하나는 요소가 나타나는 순서대로 순회 할 수 있습니다. 그러나 @ aix 질문과 같이 포인터로 어떻게 할 것인지는 확실하지 않습니다.
shabbychef

2
@aix 나는 당신의 친밀감이 맞다고 생각합니다. 정렬 된 이중 링크 목록뿐만 아니라 색인 가능한 건너 뛰기 목록이 필요합니다. 아이디어는 한 요소의 삽입, 한 요소의 삭제 및 예상 O (log (n)) 시간 (또는 더 나은)에서 중간 값을 찾을 수있는 데이터 구조를 갖는 것입니다.
whuber

3

당신이 언급했듯이 정렬은 O(n·log n)길이의 창에 대한 것 n입니다. 이 이동을 수행하면 l=vectorlength총 비용 이 추가 O(l·n·log n)됩니다.

이것을 푸시하는 가장 간단한 방법은 한 창에서 다음 창으로 이동할 때 메모리에 마지막 n 개의 요소를 순서대로 나열하는 것입니다. 정렬 된 목록에서 하나의 요소를 제거 / 삽입하면 둘 다의 O(n)비용이 발생 O(l·n)합니다.

의사 코드 :

l = length(input)
aidvector = sort(input(1:n))
output(i) = aid(n/2)
for i = n+1:l
    remove input(i-n) from aidvector
    sort aid(n) into aidvector
    output(i) = aid(n/2)


2

실제 중앙값 대신 추정값으로 살 수있는 경우, Remedian Algorithm (PDF) 은 스토리지 요구 사항이 낮고 정확도가 정의 된 원 패스입니다.

기본 b에 대한 교정은 단일 관측치 만 남을 때까지 b 개의 관측치 그룹의 중간 값을 계산 한 다음이 중간 값의 중간 값을 계산하여 진행됩니다. 이 방법은 단지 크기가 b 인 k 개의 배열 만 필요합니다 (n = b ^ k) ...


0

임베디드 응용 프로그램 에서이 RunningStats C ++ 라이브러리 를 사용했습니다. 내가 찾은 가장 간단한 실행 통계 라이브러리입니다.

링크에서 :

이 코드는 데이터를 한 번에 표준 편차를 계산하기위한 Knuth 및 Welford 방법의 확장입니다. 비슷한 인터페이스를 사용하여 왜도 및 첨도를 계산합니다. 데이터를 한 번만 통과하면되는 알고리즘은 수치 적으로 안정적이고 정확합니다.


해당 페이지에 중간 값에 대한 정보가 있습니까?
musiphil
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.