Подтвердить что ты не робот

Какие проверенные алгоритмы для предлагать похожие статьи?

Довольно распространенная ситуация, я бы сделал ставку. У вас есть блог или новостной сайт, и у вас есть много статей или значков, или как вы их называете, и вы хотите, чтобы внизу каждого предлагали другие, которые, как представляется, связаны друг с другом.

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

Как вы можете найти возможные документы?

Меня скорее интересует фактический алгоритм, а не готовые решения, хотя я бы с удовольствием посмотрел на что-то, реализованное в ruby ​​или python, или полагался на mysql или pgsql.

изменить: текущий ответ довольно хорош, но я хотел бы видеть больше. Возможно, какой-то действительно простой пример кода для одной или двух.

4b9b3361

Ответ 1

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

Самый простой подход называется мешок слов. Каждый документ сводится к разреженному вектору пар {word: wordcount}, и вы можете бросить классификатор NaiveBayes (или некоторый другой) в наборе векторов, который представляет ваш набор документов, или вычислить оценки подобия между каждым мешком и каждым другим пакетом ( это называется классификацией k-ближайшего соседа). KNN работает быстро, но требует хранения O (n ^ 2) для матрицы баллов; однако для блога n не очень велико. Для чего-то размер большой газеты, KNN быстро становится непрактичным, поэтому алгоритм классификации "на лету" иногда лучше. В этом случае вы можете рассмотреть механизм векторной поддержки рангов. SVM опрятно, потому что они не ограничивают вас линейными мерами сходства и все еще довольно быстры.

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

Если сходство с сумкой слов недостаточно, вы можете абстрагировать его до уровня сходства с суммарным количеством N-граммов, где вы создаете вектор, представляющий документ, основанный на парах или тройках слов. (Вы можете использовать 4-кортежи или даже более крупные кортежи, но на практике это мало помогает). Это имеет недостаток в создании гораздо больших векторов, и, соответственно, классификация займет больше работы, но матчи, которые вы получите, будут намного ближе синтаксически. OTOH, вам, вероятно, не нужно это для семантического сходства; это лучше для таких вещей, как обнаружение плагиата. Chunking, или сокращение документа до облегченных деревьев синтаксического анализа, также можно использовать (существуют алгоритмы классификации для деревьев), но это больше полезно для таких вещей, как проблема авторства ( "с учетом документа неизвестного происхождения, который его написал?" ).

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

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

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

Ответ 2

Это типичный случай "Классификация документов" , который изучается в каждом классе машинного обучения. Если вам нравятся статистические данные, математика и информатика, я рекомендую вам взглянуть на неконтролируемые методы, такие как kmeans ++, Байесовские методы и LDA. В частности, байесовские методы довольно хорошие в том, что вы ищете, их единственная проблема идет медленно (но если вы не запустите очень большой сайт, это не должно вас сильно беспокоить).

На более практичном и менее теоретическом подходе я рекомендую вам посмотреть this и этот другой отличный пример кода.

Ответ 3

Вы должны прочитать книгу "Программирование коллективного интеллекта: создание приложений Smart Web 2.0" (ISBN 0596529325)!

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

См. Анализ кластеров/Кластерная разбивка на разделы.

Очень простой (но теоретический и медленный) метод для поиска прямых сходств:

Preprocess:

  • Сохраняйте список плоских слов в каждой статье (не удаляйте повторяющиеся слова).
  • "Перекрестно присоединяйся" к статьям: подсчитайте количество слов в статье A, которые соответствуют тем же словам в статье B. Теперь у вас есть матрица int word_matches[narticles][narticles] (вы не должны хранить ее подобным образом, сходство A- > B такое же как B- > A, поэтому разреженная матрица сохраняет почти половину пространства).
  • Нормализовать значение слова_макшей в диапазоне 0..1! (найдите максимальное количество, затем разделите любое количество на это) - вы должны хранить там поплавки, а не ints;)

Найти похожие статьи:

  • выберите статьи X с наивысшими совпадениями из word_matches

Ответ 4

Небольшая поисковая система векторного пространства в Ruby. Основная идея состоит в том, что два документа связаны, если они содержат одни и те же слова. Таким образом, мы учитываем появление слов в каждом документе, а затем вычисляем косинус между этими векторами (каждый член имеет фиксированный индекс, если он появляется, то есть 1 в этом индексе, если не равен нулю). Косинус будет 1.0, если два документа имеют общие термины и 0.0, если у них нет общих терминов. Вы можете напрямую перевести это значение в%.

terms = Hash.new{|h,k|h[k]=h.size}
docs = DATA.collect { |line| 
  name = line.match(/^\d+/)
  words = line.downcase.scan(/[a-z]+/)
  vector = [] 
  words.each { |word| vector[terms[word]] = 1 }
  {:name=>name,:vector=>vector}
}
current = docs.first # or any other
docs.sort_by { |doc| 
  # assume we have defined cosine on arrays
  doc[:vector].cosine(current[:vector]) 
}
related = docs[1..5].collect{|doc|doc[:name]}

puts related

__END__
0 Human machine interface for Lab ABC computer applications
1 A survey of user opinion of computer system response time
2 The EPS user interface management system
3 System and human system engineering testing of EPS
4 Relation of user-perceived response time to error measurement
5 The generation of random, binary, unordered trees
6 The intersection graph of paths in trees
7 Graph minors IV: Widths of trees and well-quasi-ordering
8 Graph minors: A survey

определение Array#cosine остается как упражнение для читателя (должно иметь дело с значениями nil и разными длинами, но для этого мы получили Array#zip правильно?)

BTW, документы примера взяты из бумаги SVD Deerwester etal:)

Ответ 5

Некоторое время назад я реализовал что-то похожее. Возможно, эта идея устарела, но я надеюсь, что она может помочь.

Я запустил веб-сайт ASP 3.0 для программирования общих задач и начал с этого принципа: у пользователя есть сомнения и он останется на веб-сайте, пока он/она может найти интересный контент по этому вопросу.

Когда пользователь пришел, я начал объект ASP 3.0 Session и записал всю навигацию пользователя, как связанный список. В событии Session.OnEnd я беру первую ссылку, ища следующую ссылку и увеличивая столбец счетчика, например:

<Article Title="Cookie problem A">
    <NextPage Title="Cookie problem B" Count="5" />
    <NextPage Title="Cookie problem C" Count="2" />
</Article>

Итак, чтобы проверить связанные статьи, мне просто нужно было отобразить вершины n NextPage сущностей, упорядоченных по столбцу счетчика.