Предсказание популярности статьи еще до ее написания

Всем привет! Захотелось мне запилить приложение, которое бы предсказывало популярность статьи на Либератуме еще до ее написания. Ведь было бы круто не писать статьи, которые в будущем не станут популярными и не привлекут читателя. И писать статьи, которые привлекут читателя? Как вам такой план?

Web-приложение, классификатор текстов на Либератуме

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

Действует НБК просто: на вход подается текст (в данном случае заголовок статьи) и класс документа (в данном случае shit или cool). «Обучая» классификатор, мы строим таблицу вероятностей встречи ключевого слова с учетом того, к какому классу относится документ. После того, как таблица будет построена, на вход классификатора мы будем подавать произвольные заголовки (и вы сами сможете в этом поучаствовать), а на выходе получим класс документа: shit или cool.

Единственный серьезный вопрос: на каких данных обучать классификатор? Для этого я экспортировал заголовки статей с Либератума за 10 лет. Около 11 тыс. штук.

Экспорт CSV данных

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

Число просмотров и комментариев каждой статьи на Либератуме

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

Вот общий график популярности постов:

Популярность постов

Красная линия — медиана, синяя — среднее арифметическое.

А вот гистограмма:

Гистограмма популярности статей на сайте, Либератум

Что считать границей популярных постов и лажовых? Я даже пытался вводить больше классов и использовать классификатор K-Means. Вот такое разбиение было предложено:

K-Means классификатор для оценки популярности статей на Либератуме

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

А лучший результат показало деление по среднему арифметическому.

Медианное значение и среднее арифметическое

2550 просмотров на статью. Ниже этого значения — shit, больше или равно — cool.

Теперь обучим классификатор. НБК имеет очень простую формулу и запилить классификатор можно самому. Делать этого я конечно же не стану. Возьму готовый.

Обучение:


const fs = require('fs')
const papa = require('papaparse')
const bayes = require('bayes')
const _ = require('lodash')

var classifier = bayes()

var train = (resolve, reject) => {
let f = fs.readFileSync('../data/liberpop.csv', 'utf8')
papa.parse(f, {
delimiter: ',',
complete: (result) => {
_.each(result.data, (i) => {
if (i[2] != null) {
classifier.learn(i[2].toLowerCase(), i[4])
}
})
}
})
resolve(1)
}

(new Promise(train)).then(() => {
fs.writeFile('../data/probabilities.json', classifier.toJson(), () => {
console.log('Results saved to probabilities.json')
})
})

Библиотека PapaParse помогла распарсить CSV, а библиотека Bayes предоставила байесовский наивный классификатор. Результат обучения (JSON, ~800 Kb) сохранен в probabilities.json. Вуаля! Теперь можно подгружать probabilities.json в браузер к клиенту и юзер сможет вычислять популярность статей еще до их написания. Последний штрих (client side):


var bayes = require('bayes')
var axios = require('axios')

const PROBABILITIES_FILE = 'https://nobleman.xyz/tools/editor/wanga/js/probabilities.json'

var classifier

document.addEventListener('DOMContentLoaded', () => {
axios.get(PROBABILITIES_FILE).then((res) => {
classifier = bayes.fromJson(JSON.stringify(res.data))
var title = document.getElementById('title')
var results = document.getElementById('results')
title.addEventListener('keydown', (e) => {
if (e.keyCode == 13) {
var t = title.value
let c = classifier.categorize(t.toLowerCase())
title.value = ''
results.innerHTML = '' + t + '' + c + '' + results.innerHTML;
}
})
}).catch((err) => {
console.log('Axios error: ' + err)
})
})

В фоне подгружается probabilities.json, подключается к классификатору, всё это дело вешается на окно ввода. Готово. Можно пользоваться.

Web-приложение, классификатор текстов на Либератуме

Ссылка на рабочее web-приложение: https://nobleman.xyz/tools/editor/wanga/

Наивный байесовский классификатор

НБК удобно использовать для фильтрации спама, определения тональности высказываний, много для чего. Из Википедии:

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

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

Подробности: How to predict article popularity using Naive Bayes Classifier and NodeJS

Оценка: 
5
Средняя: 4.3 (6 оценки)

Комментарии

Предсказание популярности статьи еще до ее написания — shit

Помогите переформулировать заголовок, чтобы стало cool. :)

Оценка: 
Средняя: 3.7 (10 оценки)

и ремесло поставил я подножием искусству;
Я сделался ремесленник перстам
Придал послушную, сухую беглость
И верность уху, звуки умертвив
Я музыку разъял, как труп >
Поверив алгеброй гармонию

Смысл: проверить разумом, точным расчётом то, что выражено чувствами. Говорится обычно иронически или критически по отношению к человеку, который пытается проверить точными расчётами то, что относится к области чувств

спасибо классикам )

Оценка: 
Средняя: 3.8 (5 оценки)

администрация сайта: будьте прокляты!

Оценка: 
Средняя: 3.7 (3 оценки)
comrade аватар

Вы со знаками препинания в проклятиях поаккуратнее! Поставили двоеточие вместо запятой, и проклятие не в ту сторону пошло...
(-;

Оценка: 
Средняя: 4.5 (8 оценки)

Ваш камент — говно.

[table Title | Assessment
администрация сайта: будьте прокляты! | shit]

Оценка: 
Средняя: 2.7 (6 оценки)

чак норрис досчитал до бесконечности, дважды - cool

а программе уже привито чувство страха))

Оценка: 
Средняя: 4.3 (3 оценки)

Помогите переформулировать заголовок, чтобы стало cool. :)

предсказываем оригинальность заголовка статьи - cool

Оценка: 
Средняя: 4.3 (3 оценки)

Если это выглядит как утка, плавает как утка и крякает как утка, то, вероятно, это утка (какая разница, что это на самом деле) - cool
If it looks like a duck, swims like a duck and quacks like a duck, then it probably is a duck (who cares what it really is) - shit

она понимает аглицкий?

Оценка: 
Средняя: 3.8 (4 оценки)

Только те иностранные слова, которые уже включались в заголовки. Ubuntu "поймет", а, например, tits нет.

Оценка: 
Средняя: 3.4 (7 оценки)

Приделал к читалке новостей. Теперь непрочитанные новости сортируются по классу интересности на основе предыдущих решений (просматривал или нет).

Оценка: 
Средняя: 5 (2 оценки)

сентябрь на дворе, допилен ли ваш "Локал Гугл"?
"чертовски эффективный" post-popularity-prediction?

Оценка: 
Средняя: 3.8 (4 оценки)

Не приложение, а программа. И JavaScript это позор.

Оценка: 
Средняя: 4.7 (3 оценки)

Комментировать

Filtered HTML

  • Use [fn]...[/fn] (or <fn>...</fn>) to insert automatically numbered footnotes.
  • Доступны HTML теги: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <blockquote> <strike> <code> <h2> <h3> <h4> <h5> <del> <img>
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Строки и параграфы переносятся автоматически.

Plain text

  • HTML-теги не обрабатываются и показываются как обычный текст
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Строки и параграфы переносятся автоматически.