Выберите случайный элемент на основе вероятностей

javascript #reactjs

#javascript #reactjs

Вопрос:

Я создаю простое веб-приложение, которое поможет мне в изучении словарного запаса.

У вас есть массив слов (каждое слово является объектом — термином определение). Прямо сейчас я случайным образом выбираю слово, оно покажет мне определение, и я должен написать термин. Всякий раз, когда я отправляю термин, он покажет мне, был ли я прав или нет, а затем случайным образом выбирает другое слово.

Проблема в том, что, возможно, я буду получать некоторые слова очень часто, хотя я их очень хорошо знаю, в то время как другие (с которыми у меня могут возникнуть проблемы) будут отображаться не часто.

Я хотел бы выбрать слово из массива слов, чтобы слова, которые я знаю, не отображались так часто, в то время как слова, которые я еще не сделал, или я отвечал неправильно, будут отображаться с более высокой частотой. (Но я все равно хотел бы сохранить какую-то случайность)

Я использую эту функцию для получения случайного индекса слова в массиве слов:

 const newIndex = () =>{
   return [...Array(words.length).keys()].sort(() => 0.5 - Math.random())[0]
}
 

К сожалению, я не могу придумать, как это реализовать, есть идеи?

Комментарии:

1. Здесь уже есть сотни подобных вопросов.

2. Вы можете удалить правильные слова из своего списка. Делайте это до тех пор, пока все слова не будут правильными, тогда вы можете начать все сначала с начального списка. Вы также можете подсчитать, сколько пришло слово, если оно превышает определенное количество, а затем удалить его из списка.

3. Я могу ответить на ваш вопрос напрямую, когда вернусь к компьютеру, но довольно простым подходом может быть сохранение словаря вашей оценки (pct правильно) и посещений (количество просмотров) каждого слова, затем вычислите относительный вес каждого слова (много способов сделать это) — нормализоватьобщее количество весов всех слов равно 1. выборка из равномерного распределения и выбор соответствующего слова, то есть: слова A. B и C с весами 20%, 50% и 30% соответственно будут выбраны в следующих диапазонах: A = 0-20, B = 20-70, C = 70-100

4. По сути, я предлагаю A / B тестирование, где «успех» определяется как неправильное определение слова, поэтому бандит пытается использовать вашу некорректность. Существует несколько библиотек js, которые упрощают A / B тестирование, aptonic.github.io/ab.js может быть, это будет плодотворно

Ответ №1:

Поскольку вы спрашиваете о. an idea of how to implement it

  1. ассоциируйте вероятности с вашими словами
  2. выберите const value = Math.random() * sumOfProbabilities
  3. В цикле проверьте, меньше ли значение вероятности n-го слова, если да, верните его, если нет, уменьшите значение на вероятность текущего проверяемого слова и перейдите к следующему.

Боковое примечание:

 const newIndex = () =>{
   return [...Array(words.length).keys()].sort(() => 0.5 - Math.random())[0]
}
 

это имеет сложность O(nlogn) для задачи, которая может быть достигнута O(n) .

Ответ №2:

Следующая функция принимает длину вашего массива, коэффициент, на который взвешенные индексы должны отображаться больше, чем не взвешенные, и массив всех индексов, которые должны быть взвешены.

 const newWeightedRandomIndex = (length, weightedIndexes, factor) => {
    let indexArray = [...Array(length).keys()]

    //multiply the apearance of all weightedIndexes by the factor
    weightedIndexes
        .sort()
        .reverse()
        .forEach((index) => {
            let indexMultiplied = []

            for (let i = 0; i < factor; i  ) {
                indexMultiplied.push(index)
            }

            indexArray = [
                ...indexArray.slice(0, index),
                ...indexMultiplied,
                ...indexArray.slice(index   1, indexArray.length),
            ]
        })

    //get a random element of the now weighted array
    return indexArray[Math.floor(Math.random() * indexArray.length)]
}
 

Таким образом, входные newWeightedRandomIndex(4, [2,3], 3) данные будут генерировать случайный индекс для массива длиной 4, где индексы 2 и 3 в 3 раза выше, чем вероятность появления всех других индексов.

Для вашего использования вы могли бы назвать это так:

 let allWords = [
    { word: "Word 1", correct: false },
    { word: "Word 2", correct: false },
    { word: "Word 3", correct: true },
    { word: "Word 4", correct: false },
]

let indexesOfWordsNotAnsweredOrWrong = allWords
    .map((e, index) => ({ ...e, index })) //attach index to each
    .filter((e) => !e.correct) //filter out correct
    .map((e) => e.index) //map to only index

newWeightedRandomIndex(allWords.length, indexesOfWordsNotAnsweredOrWrong , 3)
 

Таким образом, вероятность генерации индекса каждого слова с правильным:false будет в 3 раза выше.