Лабораторная работа №2. Оценка релевантности документов с помощью BM25
Full API
Дано
Коллекция из десяти текстов сказок на английском языке,
хранящаяся в папке assets
.
В рамках данной лабораторной работы мы будем оценивать релевантность документов
с помощью метрики BM25
.
BM25
- это вероятностная модель оценки релевантности,
используемая в информационном поиске и ранжировании документов.
При выполнении поискового запроса наша цель — найти документы,
которые наиболее точно соответствуют этому запросу.
BM25
позволяет вычислить степень релевантности каждого документа,
что дает возможность их отранжировать и выделить те, которые бы максимально
соответствовали нашим ожиданиям.
Что надо сделать
Шаг 0. Начать работу над лабораторной (вместе с преподавателем на практике)
Создайте форк репозитория.
Установите необходимые инструменты для работы.
Измените файлы
main.py
иstart.py
.Закоммитьте изменения и создайте Pull request.
Important
В файле start.py
вы должны написать код, сортирующий
данные сказки по релевантности запросу.
Для этого реализуйте функции в модуле main.py
и импортируйте их в
start.py
. Весь код, выполняющий лабораторную работу, должен быть
выполнен в функции main
в файле start.py
:
def main() -> None:
pass
Вызов функции в файле start.py
:
if __name__ == '__main__':
main()
В рамках данной лабораторной работы нельзя использовать модули collections, itertools, а также сторонние модули.
Обратите внимание, что желаемую оценку необходимо указать в файле
settings.json
в поле target_score
. Возможные значения: 0, 4, 6, 8, 10.
Чем большее значение выставлено, тем больше тестов будет запущено.
Шаг 1. Токенизировать текст
Вам дана коллекция из 10 документов,
которые уже прочитаны из файлов и хранятся в виде списка, где каждый документ представлен как одна строка,
в переменной documents
.
Для того, чтобы разбить текст на токены,
реализуйте функцию lab_2_retrieval_w_bm25.main.tokenize()
.
Рассмотрим работу этой и следующих функций на примере начальных предложений трёх детских историй, которые впоследствии мы хотим рекомендовать по запросам пользователей.
Оригинальный текст: "There was a boy, who was a wizard. He used his wand to do spells.
He was studying in a magic school. His best friend was a wizard too."
Результат токенизации: ['there', 'was', 'a', 'boy', 'who', 'was', 'a', 'wizard', 'he', 'used', 'his',
'wand', 'to', 'do', 'spells', 'he', 'was', 'studying', 'in', 'a', 'magic', 'school',
'his', 'best', 'friend', 'was', 'a', 'wizard', 'too']
Оригинальный текст: "Steven was a boy who loved pets. He had a cat, two dogs and three parrots.
Every morning he did not want to go to school, because he had to leave his pets at home."
Результат токенизации: ['steven', 'was', 'a', 'boy', 'who', 'loved', 'pets', 'he', 'had', 'a', 'cat', 'two',
'dogs', 'and', 'three', 'parrots', 'every', 'morning', 'he', 'did', 'not', 'want', 'to',
'go', 'to', 'school', 'because', 'he', 'had', 'to', 'leave', 'his', 'pets', 'at', 'home']
Оригинальный текст: "A dragon and a princess had a picnic date at the top of the hill.
They rarely leaved the tower, but the summer weather was just perfect for the hill picnic."
Результат токенизации: ['a', 'dragon', 'and', 'a', 'princess', 'had', 'a', 'picnic', 'date', 'at', 'the',
'top', 'of', 'the', 'hill', 'they', 'rarely', 'leaved', 'the', 'tower', 'but', 'the',
'summer', 'weather', 'was', 'just', 'perfect', 'for', 'the', 'hill', 'picnic']
Таким образом, после выполнения этого шага каждый документ должен представлять собой список токенов.
Шаг 2. Удалить стоп-слова
Important
Выполнение Шагов 1-2 соответствует 4 баллам.
Стоп-слова
- это лексические единицы, которые не несут
значимой информации. В рамках данной лабораторной работы в качестве
стоп-слов нужно использовать следующий англоязычный перечень, предложенный
в библиотеке для обработки естественного языка - NLTK.
Стоп-слова находятся в файле stopwords.txt
в папке assets
и уже импортированы в start.py
для дальнейшей работы в виде списка.
Чтобы удалить стоп-слова из токенизированного текста,
реализуйте функцию
lab_2_retrieval_w_bm25.main.remove_stopwords()
,
Удалив стоп-слова из наших трёх документов, мы получим следующие списки. Они значительно меньше, так как в них остались только самые значимые слова.
['boy', 'wizard', 'used', 'wand', 'spells', 'studying', 'magic', 'school', 'best', 'friend', 'wizard']
['steven', 'boy', 'loved', 'pets', 'cat', 'two', 'dogs', 'three', 'parrots', 'every', 'morning', 'want', 'go', 'school', 'leave', 'pets', 'home']
['dragon', 'princess', 'picnic', 'date', 'top', 'hill', 'rarely', 'leaved', 'tower', 'summer', 'weather', 'perfect', 'hill', 'picnic']
Продемонстрируйте удаление стоп-слов из текстов на
английском языке в файле start.py
. Список текстов на английском языке
сохранен в переменную documents
.
Шаг 3. Получить список уникальных слов
В дальнейшем для осуществления оценки релевантности документов поисковому запросу, необходимо будет использовать уникальные слова, встречающиеся в коллекции текстов.
Для того чтобы создать список уникальных слов из всех документов,
реализуйте функцию
lab_2_retrieval_w_bm25.main.build_vocabulary()
.
Из трёх документов детских историй после выкидывания стоп-слов, например,
мы можем получить список следующих уникальных токенов:
['school', 'tower', 'go', 'used', 'magic', 'perfect', 'cat', 'dogs', 'best', 'top', 'studying',
'pets', 'leave', 'parrots', 'morning', 'hill', 'loved', 'picnic', 'rarely', 'boy', 'every',
'weather', 'steven', 'two', 'three', 'spells', 'wizard', 'home', 'leaved', 'date', 'friend',
'dragon', 'sad', 'princess', 'wand', 'summer']
Шаг 4. Посчитать Term Frequency
В рамках данной лабораторной работы в качестве базового способа оценки
релевантности текста поисковому запросу будет использован TF-IDF
(Term frequency–inverse document frequency).
TF-IDF
- это статистический показатель оценки важности слова в контексте документа,
являющегося частью коллекции документов или корпуса. Например:
Высокий
TF
и высокийIDF
: слово часто встречается в определенном документе, но редко в корпусе. В таком случае слово является важным в контексте определенного документа и значимым для его понимания;Высокий
TF
, но низкийIDF
: слово часто встречается как в определенном документе, так и во всем корпусе. В таком случае слово, вероятно, не обладает уникальностью, имеет более общую семантику и не значимо в контексте определенного документа;Низкий
TF
, но высокийIDF
: слово редко встречается как в определенном документе, так и во всем корпусе. В таком случае слово, вероятно, представляет собой термин или редко встречающееся понятие;Низкий
TF
и низкийIDF
: слово редко встречается в определенном документе, но часто в корпусе. В таком случае слово не является важным для определенного документа и, вероятно, является общеупотребительным.
Метрика TF-IDF
имеет две составные части и рассчитывается по формуле
\(TF\_IDF = TF \cdot IDF\), где:
TF
- частота слова в конкретном документе;IDF
- обратная частота документа.
Значение первой составной части метрики - TF (Term Frequency)
-
рассчитывается по формуле
\(TF = \frac{n_t}{|D|}\), где:
\(n_t\) - количество вхождений токена \(t\) в документ;
\(|D|\) - длина документа.
Для того чтобы посчитать частоту слова в документе,
реализуйте функцию lab_2_retrieval_w_bm25.main.calculate_tf()
.
Таким образом, каждый документ из коллекции будет иметь свой словарь с TF
значениями для каждого уникального слова.
Для трёх историй частотные словари будут выглядеть так:
{'school': 0.09, 'hill': 0.0, 'perfect': 0.0, 'want': 0.0, 'boy': 0.09, 'best': 0.09, 'top': 0.0, 'three': 0.0, 'parrots': 0.0, 'wand': 0.09, 'summer': 0.0, 'tower': 0.0, 'cat': 0.0, 'dragon': 0.0, 'date': 0.0, 'morning': 0.0, 'used': 0.09, 'wizard': 0.18, 'rarely': 0.0, 'every': 0.0, 'home': 0.0, 'studying': 0.09, 'friend': 0.09, 'picnic': 0.0, 'steven': 0.0, 'loved': 0.0, 'weather': 0.0, 'pets': 0.0, 'go': 0.0, 'two': 0.0, 'spells': 0.09, 'leaved': 0.0, 'leave': 0.0, 'dogs': 0.0, 'magic': 0.09, 'princess': 0.0}
{'school': 0.059, 'hill': 0.0, 'perfect': 0.0, 'want': 0.059, 'boy': 0.059, 'best': 0.0, 'top': 0.0, 'three': 0.059, 'parrots': 0.059, 'wand': 0.0, 'summer': 0.0, 'tower': 0.0, 'cat': 0.059, 'dragon': 0.0, 'date': 0.0, 'morning': 0.059, 'used': 0.0, 'wizard': 0.0, 'rarely': 0.0, 'every': 0.059, 'home': 0.059, 'studying': 0.0, 'friend': 0.0, 'picnic': 0.0, 'steven': 0.059, 'loved': 0.059, 'weather': 0.0, 'pets': 0.118, 'go': 0.059, 'two': 0.059, 'spells': 0.0, 'leaved': 0.0, 'leave': 0.059, 'dogs': 0.059, 'magic': 0.0, 'princess': 0.0}
{'school': 0.0, 'hill': 0.143, 'perfect': 0.07, 'want': 0.0, 'boy': 0.0, 'best': 0.0, 'top': 0.07, 'three': 0.0, 'parrots': 0.0, 'wand': 0.0, 'summer': 0.07, 'tower': 0.07, 'cat': 0.0, 'dragon': 0.07, 'date': 0.07, 'morning': 0.0, 'used': 0.0, 'wizard': 0.0, 'rarely': 0.07, 'every': 0.0, 'home': 0.0, 'studying': 0.0, 'friend': 0.0, 'picnic': 0.143, 'steven': 0.0, 'loved': 0.0, 'weather': 0.07, 'pets': 0.0, 'go': 0.0, 'two': 0.0, 'spells': 0.0, 'leaved': 0.07, 'leave': 0.0, 'dogs': 0.0, 'magic': 0.0, 'princess': 0.07}
Как видно, они содержат все уникальные токены, но отличные от нуля значения только у тех токенов, которые были в конкретном тексте.
Шаг 5. Посчитать Inverse Document Frequency
Второй составной частью метрики TF-IDF
является Inverse Term Frequency (IDF)
- обратная частота документа. В рамках данной лабораторной работы мы будем использовать
вариант этой метрики со сглаживанием.
Значение IDF
рассчитывается по формуле
\(IDF = ln(\frac{N - \sum^{m}_{j=1}n_j + 0.5}{\sum^{m}_{j=1}n_j + 0.5})\), где:
\(N\) - количество документов;
\(\sum^{m}_{j=1}n_j\) - количество документов, в которых содержится интересующее слово.
Для того чтобы посчитать обратную частоту документа,
реализуйте функцию lab_2_retrieval_w_bm25.main.calculate_idf()
.
Таким образом, у всей коллекции документов будет общий словарь с IDF
значениями для каждого уникального слова.
Note
Для подсчета логарифма необходимо использовать метод log
из модуля math
(https://docs.python.org/3/library/math.html).
IDF
-словарь для детских историй после вычисления будет выглядеть так:
{'parrots': 0.51, 'school': -0.51, 'want': 0.51, 'princess': 0.51, 'wand': 0.51, 'loved': 0.51, 'leaved': 0.51, 'studying': 0.51, 'dragon': 0.51, 'friend': 0.51, 'leave': 0.51, 'cat': 0.51, 'pets': 0.51, 'two': 0.51, 'steven': 0.51, 'spells': 0.51, 'date': 0.51, 'boy': -0.51, 'tower': 0.51, 'picnic': 0.51, 'go': 0.51, 'best': 0.51, 'three': 0.51, 'every': 0.51, 'home': 0.51, 'dogs': 0.51, 'morning': 0.51, 'top': 0.51, 'weather': 0.51, 'perfect': 0.51, 'summer': 0.51, 'rarely': 0.51, 'magic': 0.51, 'wizard': 0.51, 'used': 0.51, 'hill': 0.51}
Шаг 6. Посчитать TF-IDF
Important
Выполнение Шагов 1-6 соответствует 6 баллам.
Для того, чтобы для каждого уникального слова в коллекции документов
получить значение метрики TF-IDF
, реализуйте функцию
lab_2_retrieval_w_bm25.main.calculate_tf_idf()
.
Напоминаем, метрика TF-IDF
имеет следующую формулу:
\(TF\_IDF = TF \cdot IDF\).
После вычисления TF-IDF
для текстов про мальчика-волшебника,
Стивена и пикник должны получиться следующие словари:
{'loved': 0.0, 'studying': 0.046, 'every': 0.0, 'top': 0.0, 'wizard': 0.09, 'want': 0.0, 'weather': 0.0, 'tower': 0.0, 'summer': 0.0, 'dogs': 0.0, 'cat': 0.0, 'best': 0.046, 'two': 0.0, 'wand': 0.046, 'friend': 0.046, 'leaved': 0.0, 'boy': -0.046, 'home': 0.0, 'princess': 0.0, 'dragon': 0.0, 'three': 0.0, 'go': 0.0, 'leave': 0.0, 'date': 0.0, 'school': -0.046, 'magic': 0.046, 'rarely': 0.0, 'parrots': 0.0, 'morning': 0.0, 'perfect': 0.0, 'pets': 0.0, 'spells': 0.046, 'hill': 0.0, 'steven': 0.0, 'picnic': 0.0, 'used': 0.046}
{'loved': 0.03, 'studying': 0.0, 'every': 0.03, 'top': 0.0, 'wizard': 0.0, 'want': 0.03, 'weather': 0.0, 'tower': 0.0, 'summer': 0.0, 'dogs': 0.03, 'cat': 0.03, 'best': 0.0, 'two': 0.03, 'wand': 0.0, 'friend': 0.0, 'leaved': 0.0, 'boy': -0.03, 'home': 0.03, 'princess': 0.0, 'dragon': 0.0, 'three': 0.03, 'go': 0.03, 'leave': 0.03, 'date': 0.0, 'school': -0.03, 'magic': 0.0, 'rarely': 0.0, 'parrots': 0.03, 'morning': 0.03, 'perfect': 0.0, 'pets': 0.06, 'spells': 0.0, 'hill': 0.0, 'steven': 0.03, 'picnic': 0.0, 'used': 0.0}
{'loved': 0.0, 'studying': 0.0, 'every': 0.0, 'top': 0.036, 'wizard': 0.0, 'want': 0.0, 'weather': 0.036, 'tower': 0.036, 'summer': 0.036, 'dogs': 0.0, 'cat': 0.0, 'best': 0.0, 'two': 0.0, 'wand': 0.0, 'friend': 0.0, 'leaved': 0.036, 'boy': -0.0, 'home': 0.0, 'princess': 0.036, 'dragon': 0.036, 'three': 0.0, 'go': 0.0, 'leave': 0.0, 'date': 0.036, 'school': -0.0, 'magic': 0.0, 'rarely': 0.036, 'parrots': 0.0, 'morning': 0.0, 'perfect': 0.036, 'pets': 0.0, 'spells': 0.0, 'hill': 0.073, 'steven': 0.0, 'picnic': 0.073, 'used': 0.0}
Продемонстрируйте подсчет метрики TF-IDF
для всех уникальных слов в коллекции текстов,
хранящейся в переменной documents
в файле start.py
. В результате у вас должен
получиться список из 10 словарей со значениями TF-IDF
для каждого текста в коллекции.
Шаг 7. Посчитать BM25
Целью данной лабораторной работы является оценка релевантности документов с помощью
метрики BM25
(Best Matching 25).
BM25
- это вероятностная модель оценки релевантности,
используемая в информационном поиске и ранжировании документов.
Осуществляя поисковый запрос, мы хотим найти документы, которые бы наиболее соответствовали ему.
Чем выше показатель релевантности документа,
тем больше вероятность того, что документ содержит корректный ответ на наш запрос.
Метрика BM25
является продолжением классической модели TF-IDF
и учитывает не только частоту слова,
но и длину документа, что позволяет более точно оценивать значимость слова в контексте документа.
Метрика BM25
так же, как и TF-IDF
имеет две составные части и рассчитывается по формуле
\(BM25(q, D) = \sum_{i=1}^{n} IDF(q_i) \cdot \frac{n_t \cdot (k_1 + 1)}{n_t + k_1 \cdot (1 - b + b \cdot \frac{|D|}{avgdl})}\), где:
\(n_t\) - количество вхождений токена \(t\) в документ \(D\);
\(|D|\) - длина документа;
\(avgdl\) - средняя длина документа в коллекции;
\(k_1\) и \(b\) - параметры, регулирующие влияние частоты слова и длины документа. Параметр \(k_1\) может изменяться в пределах [1.2, 2.0], параметр \(b\) может изменяться в пределах [0, 1].
Как вы можете видеть, при подсчете BM25
используется IDF
,
которую мы получили в ходе подсчета метрики TF-IDF
для каждого слова.
Для того чтобы рассчитать метрику BM25
для заданного документа относительно всей коллекции,
реализуйте функцию lab_2_retrieval_w_bm25.main.calculate_bm25()
.
После подсчёта BM25
для каждого из текстов коллекции должны получиться словари.
Детские истории имеют следующие:
{'wizard': 0.784, 'go': 0.0, 'weather': 0.0, 'morning': 0.0, 'rarely': 0.0, 'best': 0.565, 'date': 0.0, 'perfect': 0.0, 'used': 0.565, 'wand': 0.565, 'boy': -0.565, 'cat': 0.0, 'spells': 0.565, 'studying': 0.565, 'home': 0.0, 'dogs': 0.0, 'leave': 0.0, 'hill': 0.0, 'princess': 0.0, 'steven': 0.0, 'friend': 0.565, 'picnic': 0.0, 'three': 0.0, 'loved': 0.0, 'want': 0.0, 'parrots': 0.0, 'tower': 0.0, 'leaved': 0.0, 'dragon': 0.0, 'two': 0.0, 'summer': 0.0, 'school': -0.565, 'magic': 0.565, 'every': 0.0, 'pets': 0.0, 'top': 0.0}
{'wizard': 0.0, 'go': 0.466, 'weather': 0.0, 'morning': 0.466, 'rarely': 0.0, 'best': 0.0, 'date': 0.0, 'perfect': 0.0, 'used': 0.0, 'wand': 0.0, 'boy': -0.466, 'cat': 0.466, 'spells': 0.0, 'studying': 0.0, 'home': 0.466, 'dogs': 0.466, 'leave': 0.466, 'hill': 0.0, 'princess': 0.0, 'steven': 0.466, 'friend': 0.0, 'picnic': 0.0, 'three': 0.466, 'loved': 0.466, 'want': 0.466, 'parrots': 0.466, 'tower': 0.0, 'leaved': 0.0, 'dragon': 0.0, 'two': 0.466, 'summer': 0.0, 'school': -0.466, 'magic': 0.0, 'every': 0.466, 'pets': 0.683, 'top': 0.0}
{'wizard': 0.0, 'go': 0.0, 'weather': 0.51, 'morning': 0.0, 'rarely': 0.51, 'best': 0.0, 'date': 0.51, 'perfect': 0.51, 'used': 0.0, 'wand': 0.0, 'boy': -0.0, 'cat': 0.0, 'spells': 0.0, 'studying': 0.0, 'home': 0.0, 'dogs': 0.0, 'leave': 0.0, 'hill': 0.73, 'princess': 0.51, 'steven': 0.0, 'friend': 0.0, 'picnic': 0.73, 'three': 0.0, 'loved': 0.0, 'want': 0.0, 'parrots': 0.0, 'tower': 0.51, 'leaved': 0.51, 'dragon': 0.51, 'two': 0.0, 'summer': 0.51, 'school': -0.0, 'magic': 0.0, 'every': 0.0, 'pets': 0.0, 'top': 0.51}
Продемонстрируйте подсчет метрики BM25
для всех уникальных слов в коллекции текстов,
хранящейся в переменной documents
в файле start.py
. В результате у вас должен
получиться список из 10 словарей со значениями BM25
для каждого текста в коллекции.
Используйте значения k1 = 1.5
и b = 0.75
в качестве параметров для алгоритма BM25
.
Шаг 8. Отранжировать документы по определенному поисковому запросу
Important
Выполнение Шагов 1-8 соответствует 8 баллам.
В результате использования метрик оценки релевантности документов какому-либо поисковому запросу, мы хотим получить список рангов соответствия документов запросу. Для этого для каждого слова в поисковом запросе необходимо получить метрику релевантности в контексте рассматриваемого документа. Затем метрики необходимо суммировать, а документы нужно отсортировать по убыванию суммарных оценок.
Для того, чтобы отранжировать документы по убыванию релевантности
(то есть по убыванию значений метрики), реализуйте функцию
lab_2_retrieval_w_bm25.main.rank_documents()
.
Так, например, у нас есть три документа: [0, 1, 2] — текст про мальчика-волшебника, текст про Стивена и его питомцев и текст про пикник принцессы и дракона.
Пусть пользователь направил запрос нашей базе детских историй:
""A story about a wizard boy in a tower!"
с желанием получить какую-нибудь книжку, соответствующую его предпочтениям в литературе.
Реализация функции lab_2_retrieval_w_bm25.main.rank_documents()
должна уметь
получить запрос query
и осуществить его предобработку с помощью функций
lab_2_retrieval_w_bm25.main.tokenize()
и lab_2_retrieval_w_bm25.main.remove_stopwords()
.
Получив токены запроса, функция должна обратиться к коллекции словарей метрики (TF-IDF
или BM25
, в зависимости от того, что подаётся функции на вход) и посчитать суммарное
значение метрики для токенов запроса в конкретном документе коллекции. Затем тексты должны
быть отсортированы по этим значениям.
Тогда для запроса пользователя у нас может получиться два списка значений:
TF-IDF
: [(0, 0.0464), (2, 0.0365), (1, -0.0300)]BM25
: [(2, 0.5108), (0, 0.2184), (1, -0.4659)]
Как видно, в зависимости от способа определения (метрики) первая (нулевая по индексу)
или третья (индекс [2]) истории обе могут наиболее подходить запросу
"A story about a wizard boy in a tower!"
Но обе метрики показывают, что история про Стивена и его питомцев не подойдёт пользователю.
Отранжируйте тексты из коллекции документов для запроса 'Which fairy tale has Fairy Queen?'
с использованием метрик TF-IDF
и BM25
в файле start.py
и сравните результат.
Используйте значения k1 = 1.5
и b = 0.75
в качестве параметров для алгоритма BM25
.
Шаг 9. Посчитать оптимизированный BM25
При работе с большой коллекцией текстов подсчет метрики BM25
для запроса
может быть вычислительно неэффективным. Для того, чтобы решить данную проблему, можно
воспользоваться оптимизированной версией алгоритма BM25
.
Ее ключевая особенность
состоит в том, что вместо того, чтобы подсчитывать BM25
для каждого слова в запросе,
мы можем пропускать те слова, чье значение метрики IDF
меньше определенного порога alpha
.
Данная модификация позволяет значительно увеличить скорость работы алгоритма.
Модифицированная метрика BM25
рассчитывается по формуле
\(BM25(q, D) = \sum_{i=1}^{n} IDF(q_i) \cdot \frac{n_t \cdot (k_1 + 1)}{n_t + k_1 \cdot (1 - b + b \cdot \frac{|D|}{avgdl})}\), где:
\(n_t\) - количество вхождений токена \(t\) в документ \(D\);
\(|D|\) - длина документа;
\(avgdl\) - средняя длина документа в коллекции;
\(k_1\) и \(b\) - параметры, регулирующие влияние частоты слова и длины документа. Параметр \(k_1\) может изменяться в пределах [1.2, 2.0], параметр \(b\) может изменяться в пределах [0, 1].
Для того, чтобы посчитать значение оптимизированной метрики BM25
, реализуйте
функцию lab_2_retrieval_w_bm25.main.calculate_bm25_with_cutoff()
.
Значения BM25
с модификацией слегка отличаются от значений обычной метрики, что можно
увидеть и среди значений для наших детских историй.
{'top': 0.0, 'two': 0.0, 'leave': 0.0, 'rarely': 0.0, 'spells': 0.565, 'weather': 0.0, 'wizard': 0.784, 'want': 0.0, 'dragon': 0.0, 'magic': 0.565, 'perfect': 0.0, 'dogs': 0.0, 'three': 0.0, 'go': 0.0, 'best': 0.565, 'summer': 0.0, 'parrots': 0.0, 'picnic': 0.0, 'princess': 0.0, 'morning': 0.0, 'every': 0.0, 'hill': 0.0, 'date': 0.0, 'wand': 0.565, 'friend': 0.565, 'leaved': 0.0, 'studying': 0.565, 'tower': 0.0, 'home': 0.0, 'cat': 0.0, 'loved': 0.0, 'steven': 0.0, 'pets': 0.0, 'used': 0.565}
{'top': 0.0, 'two': 0.466, 'leave': 0.466, 'rarely': 0.0, 'spells': 0.0, 'weather': 0.0, 'wizard': 0.0, 'want': 0.466, 'dragon': 0.0, 'magic': 0.0, 'perfect': 0.0, 'dogs': 0.466, 'three': 0.466, 'go': 0.466, 'best': 0.0, 'summer': 0.0, 'parrots': 0.466, 'picnic': 0.0, 'princess': 0.0, 'morning': 0.466, 'every': 0.466, 'hill': 0.0, 'date': 0.0, 'wand': 0.0, 'friend': 0.0, 'leaved': 0.0, 'studying': 0.0, 'tower': 0.0, 'home': 0.466, 'cat': 0.466, 'loved': 0.466, 'steven': 0.466, 'pets': 0.683, 'used': 0.0}
{'top': 0.511, 'two': 0.0, 'leave': 0.0, 'rarely': 0.511, 'spells': 0.0, 'weather': 0.511, 'wizard': 0.0, 'want': 0.0, 'dragon': 0.511, 'magic': 0.0, 'perfect': 0.511, 'dogs': 0.0, 'three': 0.0, 'go': 0.0, 'best': 0.0, 'summer': 0.511, 'parrots': 0.0, 'picnic': 0.73, 'princess': 0.511, 'morning': 0.0, 'every': 0.0, 'hill': 0.73, 'date': 0.511, 'wand': 0.0, 'friend': 0.0, 'leaved': 0.511, 'studying': 0.0, 'tower': 0.511, 'home': 0.0, 'cat': 0.0, 'loved': 0.0, 'steven': 0.0, 'pets': 0.0, 'used': 0.0}
Можно заметить, что в новых словарях меньше токенов. Поищите, какие отсутствуют, и подумайте, почему.
Если отранжировать значения оптимизированной метрики BM25
для всё того же запроса
"A story about a wizard boy in a tower!"
, то мы получим [(0, 0.7837), (2, 0.5108), (1, 0.0)]
— история про волшебника подходит больше всего.
В файле start.py
рассчитайте значение оптимизированной метрики BM25
для каждого
уникального слова в коллекции. В качестве параметров используйте значения alpha = 0.2
,
k1 = 1.5
и b = 0.75
Шаг 10. Сохранить значения метрик
При использовании больших коллекций текстов каждый раз подсчитывать значения метрик может быть не только неудобно, но и вычислительно затратно, поэтому необходимо научиться сохранять их.
Для того, чтобы сохранить полученные значения метрик в json
файл, реализуйте
функцию lab_2_retrieval_w_bm25.main.save_index()
.
Note
Для сохранения данных в json
файл вам может потребоваться метод dump, который в качестве аргументов принимает Python объект, который вы хотите сохранить в json
, файловый объект, в который будут сохранены данные, и отступ - целое число, определяющее количество пробелов для отступа.
Пример корректного сохранения
вы можете найти в папке tests/assets/saved_metrics_example.json
.
В файле start.py
продемонстрируйте сохранение в файл assets/metrics.json
метрик, полученных с использованием
эффективного алгоритма BM25
для всех текстов в коллекции.
Шаг 11. Загрузить значения метрик
На предыдущем шаге мы уже научились сохранять полученные для каждого слова значения метрики в файл, однако важно также научиться корректно загружать их из него.
Для того, чтобы загрузить полученные значения метрик, реализуйте
функцию lab_2_retrieval_w_bm25.main.load_index()
.
Note
Для загрузки данных из json
файла вам может потребоваться метод load, который в качестве аргумента принимает объект json
файла, из которого считываются данные.
В файле start.py
продемонстрируйте загрузку из файла метрик, полученных с
использованием эффективного алгоритма BM25
. Далее, используя загруженные значения,
отранжируйте документы по запросу 'Which fairy tale has Fairy Queen?'
.
Шаг 12. Посчитать ранговую корреляцию Спирмена
Important
Выполнение Шагов 1-12 соответствует 10 баллам.
Ранее мы уже отранжировали документы по убыванию релевантности
с использованием показателей TF-IDF
и BM25
и вручную сравнивали между собой
полученные результаты.
Однако вместо того, чтобы вручную сравнивать списки рангов, можно воспользоваться
ранговой корреляцией Спирмена
(Тест ранговой корреляции Спирмена).
Коэффициент ранговой корреляции Спирмена
- это показатель, позволяющий оценить,
насколько сильно два набора данных связаны между собой.
Этот коэффициент измеряет степень монотонной зависимости между
ранжированными переменными и варьируется от -1 до 1:
Значения близкие к 1 указывают на сильную положительную корреляцию;
Значения близкие к -1 указывают на сильную отрицательную корреляцию;
Значения близкие к 0 указывают на отсутствие корреляции.
Коэффициент ранговой корреляции Спирмена
рассчитывается по формуле
\(Spearman's = 1 - \frac{6\sum d^2_i}{n(n^2 - 1)}\), где:
\(d^2_i\) - разность рангов для \(i\)-го элемента;
\(n\) - количество наблюдений;
Для того чтобы рассчитать ранговую корреляцию Спирмена между полученным
списков рангов и “золотым стандартом”,
реализуйте функцию lab_2_retrieval_w_bm25.main.calculate_spearman()
.
В итоге для коллекции из трёх детских историй при рассчитывании рангов для TF-IDF
,
обычного BM25
и эффективного BM25
, получаются следующие документы в порядке
уменьшения релевантности:
TF-IDF
: [0, 2, 1]BM25
: [2, 0, 1]BM25 CUTOFF
: [0, 2, 1]
Коэффициент ранговой корреляции показывает, что пары TF-IDF
и BM25
, BM25
и BM25 CUTOFF
имеют среднюю положительную корреляцию 0.5, в то время как пара
TF-IDF
и BM25 CUTOFF
имеет коэффициент Спирмена равный 1, так как они идентичны.
В файле start.py
отранжируйте тексты из коллекции документов для запроса
'Which fairy tale has Fairy Queen?'
с использованием эффективного алгоритма BM25
, которому в качестве порога передается
значение аргумента alpha = 0.2
, а также параметры k1 = 1.5
и b = 0.75
.
Далее в start.py
продемонстрируйте подсчет ранговой корреляции Спирмена
между рангами, полученными с использованием TF-IDF
, BM25
и оптимизированного BM25
и золотым стандартом.
Золотой стандарт представляет собой список из 10 рангов, полученных в результате вызова функции
lab_2_retrieval_w_bm25.main.rank_documents()
на значениях, полученных с использованием
оптимизированной метрики BM25
(lab_2_retrieval_w_bm25.main.calculate_bm25_with_cutoff()
).
При корректном выполнении лабораторной работы золотой стандарт должен быть следующим:
[1, 7, 5, 0, 9, 2, 3, 4, 6, 8]
.