효율적인 알고리즘을 무작위로 선택 항목을 가진 주파수
문제
주어진 배열의 n
주파수 쌍:
[ (w0, f0), (w1, f1), ..., (wn-1, fn-1) ]
가 w나
이어 f나
정수 frequencey,과의 합계 주파수 ∑f나 = m
,
내가 사용하려는 의사 난수를 발생기(pRNG)선택 p
말 wj0, wj1, ..., wjp-1
러
확률을 선택하는 단어에 비례하는 주파수:
P(w나 = wjk) = P(i = jk) = f나 / m
(참고로,이것은 선택으로 교체,그래서 동일한 말씀 수 되는 모든 시간을 선택).
함께 왔어 세 알고리즘은 지금까지:
의 배열을 만들기
m
, 고 채우 그것은 그래서 첫번째f0
항목w0
, 다음f1
항목w1
, 고,그래서 마지막fp-1
항목wp-1
.[ w0, ..., w0, w1,..., w1, ..., wp-1, ..., wp-1 ]
다음 사용하 pRNG 선택p
수 범위에서0...m-1
, 보고 단어에 저장되는 그 지수입니다.
이O(n + m + p)
작업,멋지지 않아,이후m
할 수 있습이 훨씬 더 큰 n.단계의 입력 배열을 통해 한 번 컴퓨팅
m나 = ∑h≤ifh = mi-1 + f나
후 컴퓨팅m나
, 사용 pRNG 를 생성하는 번호xk
범위0...m나-1
각k
에0...p-1
선택w나
대wjk
(아마도 대체의 현재 값wjk
경우)xk < f나
.
이O(n + np)
작동합니다.- 컴퓨팅
m나
으로는 알고리즘에서 2,그리고 생성하는 다음과 같은 편에서는 n 단어-주파수-부분 합계 트리플:[ (w0, f0, m0), (w1, f1, m1), ..., (wn-1, fn-1, mn-1) ]
그리고,각각에서 k0...p-1
, 사용 pRNG 를 생성하는 번호xk
범위0...m-1
다음 검색에 배열의 세 배을 찾기i
s.t.m나-f나 ≤ xk < m나
, 선택w나
대wjk
.
이O(n + p log n)
작동합니다.
나의 질문은:거기에 더 많은 효율적인 알고리즘을 사용할 수 있는 이를 위해,또는 이러한 그?
해결책 3
확인,다른 알고리즘: 별칭 방법 (또한 언급된 에서 이 응답).기본적으로 파티션을 생성의 확률이 공간 같은 것:
- 가
n
파티션,모든 동일한 폭r
s.t.nr = m
. - 각 파티션에는 두 단어가 포함되어에서 어떤 비율(저장된 파티션).
- 를 위해 각각의 단어
w나
,f나 = ∑파티션 t s.t w나 ∈t r × ratio(t,w나)
때문에 모든 파티션의 크기를 선택하는 파티션을 수행할 수 있습에서 지속적인 작업(선택에서 인덱스 0...n-1
에서 무작위),그리고 파티션의 비율을 사용하여 다음을 수행할 수 있습니다를 선택하는 단어에서 사용되는 지속적인 작업(을 비교 pRNGed 수와 비율 사이에 두 개의 단어이다).그래서 즉 p
선택을 수행 할 수 있습에 O(p)
작업 부여,같은 파티션입니다.
그 이유는 그런 분이 존재하는 존재어 w나
s.t. f나 < r
, 는 경우에만이 존재한 말씀 wi'
s.t. fi' > r
, 이후,r 평균의 주파수.
주어진 이러한 쌍 w나
고 wi'
우리는 작업으로 바꿀 수 있습니 의사 단어 w'나
의 주파수 f'나 = r
(나타내는 w나
확률 f나/r
고 wi'
확률 1 - f나/r
다)및 새로운 단어 w'i'
의 주파수 조정 f'i' = fi' - (r - f나)
각각합니다.평균 주파수의 모든 단어는 여전히 r 며,규칙에서 이전 단락이 계속 적용됩니다.이후 의사 단어는 주파수 r 의 두 단어를 주파수≠r,우리가 알고 있는 경우에 우리는 반복 이 과정에서,우리는 우리가 결코 의사 단어의 의사 단어를,그리고 이러한 반복이 끝나야 합니다 시퀀스의 n 사는 단어는 원하는 파티션입니다.
건설 이 파티션에서 O(n)
시간
- 목록을 통해 이동의 말을 한 번 구성하는 두 개의 목록:
- 하나의 낱말로 주파수≤r
- 하나의 낱말로 주파수>r
- 다음 끌어에서 단어의 첫 번째 목록
- 는 경우의 주파수=r,그 후로 그것을 만들기 위해 요소 중 하나 파티션
- 그렇지 않으면,당기 단어서 다른 목록을 사용하고,그것을 작성하는 두 개의 단어는 파티션입니다.다음을 넣어 두 번째 단어로 다시거나 또는 두 번째 목록에 따라 조정된 주파수이다.
이것은 실제로는 여전히 작동하는 경우 파티션의 수 q > n
(당신은 그것을 증명하는 다르게).는 경우에 당신이 있는지 확인하려면 r 필수적이며,당신은 쉽게 찾을 수 있는 요인 q
의 m
s.t. q > n
, 할 수 있습 pad 모든 주파수에 의해 요소의 n
, 래 f'나 = nf나
, 업데이트 m' = mn
트 r' = m
면 q = n
.
어떤 경우에,이 알고리즘만 O(n + p)
일,내가 생각하는 최적입니다.
루비에서는:
def weighted_sample_with_replacement(input, p)
n = input.size
m = input.inject(0) { |sum,(word,freq)| sum + freq }
# find the words with frequency lesser and greater than average
lessers, greaters = input.map do |word,freq|
# pad the frequency so we can keep it integral
# when subdivided
[ word, freq*n ]
end.partition do |word,adj_freq|
adj_freq <= m
end
partitions = Array.new(n) do
word, adj_freq = lessers.shift
other_word = if adj_freq < m
# use part of another word's frequency to pad
# out the partition
other_word, other_adj_freq = greaters.shift
other_adj_freq -= (m - adj_freq)
(other_adj_freq <= m ? lessers : greaters) << [ other_word, other_adj_freq ]
other_word
end
[ word, other_word , adj_freq ]
end
(0...p).map do
# pick a partition at random
word, other_word, adj_freq = partitions[ rand(n) ]
# select the first word in the partition with appropriate
# probability
if rand(m) < adj_freq
word
else
other_word
end
end
end
다른 팁
이것은 유전자/진화 알고리즘의 선택 과정에 주로 사용되는 룰렛 휠 선택처럼 들립니다.
대상 배열을 생성 한 다음 선택해야 할 확률을 결정하는 단어를 통해 루프하고 임의의 숫자에 따라 배열의 단어를 교체 할 수 있습니다.
첫 번째 단어의 경우 확률은 f입니다0/중0 (여기서 mN= f0+..+fN), 즉 100%, 따라서 대상 어레이의 모든 위치는 w로 채워집니다.0.
다음 단어의 경우 확률이 떨어지고 마지막 단어에 도달하면 대상 배열이 주파수로 choading 무작위로 선택된 단어로 채워집니다.
C#의 코드 예제 :
public class WordFrequency {
public string Word { get; private set; }
public int Frequency { get; private set; }
public WordFrequency(string word, int frequency) {
Word = word;
Frequency = frequency;
}
}
WordFrequency[] words = new WordFrequency[] {
new WordFrequency("Hero", 80),
new WordFrequency("Monkey", 4),
new WordFrequency("Shoe", 13),
new WordFrequency("Highway", 3),
};
int p = 7;
string[] result = new string[p];
int sum = 0;
Random rnd = new Random();
foreach (WordFrequency wf in words) {
sum += wf.Frequency;
for (int i = 0; i < p; i++) {
if (rnd.Next(sum) < wf.Frequency) {
result[i] = wf.Word;
}
}
}