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

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

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

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

Что считать границей популярных постов и лажовых? Я даже пытался вводить больше классов и использовать классификатор 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-приложение: https://nobleman.xyz/tools/editor/wanga/