문제

주어진 배열의 n 주파수 쌍:

[ (w0, f0), (w1, f1), ..., (wn-1, fn-1) ]

w 이어 f 정수 frequencey,과의 합계 주파수 ∑f = m,

내가 사용하려는 의사 난수를 발생기(pRNG)선택 pwj0, wj1, ..., wjp-1 러 확률을 선택하는 단어에 비례하는 주파수:

P(w = wjk) = P(i = jk) = f / m

(참고로,이것은 선택으로 교체,그래서 동일한 말씀 되는 모든 시간을 선택).

함께 왔어 세 알고리즘은 지금까지:

  1. 의 배열을 만들기 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.

  2. 단계의 입력 배열을 통해 한 번 컴퓨팅

    m = ∑h≤ifh = mi-1 + f
    후 컴퓨팅 m, 사용 pRNG 를 생성하는 번호 xk 범위 0...m-1k0...p-1 선택 wwjk (아마도 대체의 현재 값 wjk 경우) xk < f.
    O(n + np) 작동합니다.

  3. 컴퓨팅 m 으로는 알고리즘에서 2,그리고 생성하는 다음과 같은 편에서는 n 단어-주파수-부분 합계 트리플:
    [ (w0, f0, m0), (w1, f1, m1), ..., (wn-1, fn-1, mn-1) ]
    그리고,각각에서 k 0...p-1, 사용 pRNG 를 생성하는 번호 xk 범위 0...m-1 다음 검색에 배열의 세 배을 찾기 i s.t. m-f ≤ xk < m, 선택 wwjk.
    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 평균의 주파수.

주어진 이러한 쌍 wwi' 우리는 작업으로 바꿀 수 있습니 의사 단어 w' 의 주파수 f' = r (나타내는 w 확률 f/rwi' 확률 1 - f/r 다)및 새로운 단어 w'i' 의 주파수 조정 f'i' = fi' - (r - f) 각각합니다.평균 주파수의 모든 단어는 여전히 r 며,규칙에서 이전 단락이 계속 적용됩니다.이후 의사 단어는 주파수 r 의 두 단어를 주파수≠r,우리가 알고 있는 경우에 우리는 반복 이 과정에서,우리는 우리가 결코 의사 단어의 의사 단어를,그리고 이러한 반복이 끝나야 합니다 시퀀스의 n 사는 단어는 원하는 파티션입니다.

건설 이 파티션에서 O(n) 시간

  • 목록을 통해 이동의 말을 한 번 구성하는 두 개의 목록:
    • 하나의 낱말로 주파수≤r
    • 하나의 낱말로 주파수>r
  • 다음 끌어에서 단어의 첫 번째 목록
    • 는 경우의 주파수=r,그 후로 그것을 만들기 위해 요소 중 하나 파티션
    • 그렇지 않으면,당기 단어서 다른 목록을 사용하고,그것을 작성하는 두 개의 단어는 파티션입니다.다음을 넣어 두 번째 단어로 다시거나 또는 두 번째 목록에 따라 조정된 주파수이다.

이것은 실제로는 여전히 작동하는 경우 파티션의 수 q > n (당신은 그것을 증명하는 다르게).는 경우에 당신이 있는지 확인하려면 r 필수적이며,당신은 쉽게 찾을 수 있는 요인 qm s.t. q > n, 할 수 있습 pad 모든 주파수에 의해 요소의 n, 래 f' = nf, 업데이트 m' = mnr' = mq = 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;
        }
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top