Я создаю каталог журналов в / usr / local / hadoop и предоставляю разрешение моей учетной записи hadoop.
/usr/local/hadoop$ sudo mkdir logs
/usr/local/hadoop$ sudo chown -R hadoop logs
Хорошо, я нашел другой алгоритм: метод псевдонима (также упоминается в этом ответе ). По сути, он создает такое разделение вероятностного пространства, что:
n
разделов, все одинаковой ширины r
st nr = m
. w i
, f i = ∑ разделы t st w i ∈ t r × ratio (t, w i )
Поскольку все разделы имеют одинаковый размер, выбор разделение может выполняться в постоянной работе (выберите случайным образом индекс из 0 ... n-1
), а затем можно использовать коэффициент раздела, чтобы выбрать, какое слово будет использоваться в постоянной работе (сравните значение pRNGed число с соотношением между двумя словами). Таким образом, это означает, что выбор p
может быть выполнен в O (p)
работе с таким разделом.
Причина, по которой такое разделение существует, состоит в том, что существует слово w i
st f i
w i '
st f i' > r
, поскольку r - это среднее значение частот.
Для такой пары w i
и w i '
мы можем заменить их псевдословом w' i
частоты f ' i = r
(что представляет w i
с вероятностью f i / r
и w i '
с вероятностью 1 - f i / r
) и новое слово w' i '
настроенной частоты f' i ' = f i' - (r - f i )
соответственно. Средняя частота всех слов по-прежнему будет r, и по-прежнему действует правило из предыдущего абзаца.
Это действительно работает, если количество разделов q> n
(вам просто нужно доказать это по-другому). Если вы хотите убедиться, что r является целым, и вы не можете легко найти множитель q
из m
st q> n
, вы можете заполнить все частоты в n
, поэтому f ' i = nf i
, что обновляет 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
This sounds like roulette wheel selection, mainly used for the selection process in genetic/evolutionary algorithms.
You could create the target array, then loop through the words determining the probability that it should be picked, and replace the words in the array according to a random number.
For the first word the probability would be f0/m0 (where mn=f0+..+fn), i.e. 100%, so all positions in the target array would be filled with w0.
For the following words the probability falls, and when you reach the last word the target array is filled with randomly picked words accoding to the frequency.
Example code in 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;
}
}
}