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


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.