Как я использовал Node.Js + Sentiment.js, чтобы понять, нравятся ли наши предложения местному сообществу.

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

Немного предыстории

Мы с напарником смотрим на аренду заброшенного здания. Если быть точным, это был местный водопой в пригороде Бристоля.

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

План состоял в том, чтобы превратить здание в два взаимодополняющих бизнеса:

  • Кафе или кафе-бар, открытые для всех
  • Частный коворкинг для фрилансеров и малого и среднего бизнеса

Пост в фейсбуке

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

Я разместил следующий пост в популярной группе Facebook.

Evening all. This is about the [REDACTED SITE NAME]. If you’re interested in the future of the site, read on!
As you know the pub closed its doors and is currently up for lease. My other half and I went and had a little look at the place, and we think it’s got huge potential for the area and the local community.
We think that with some TLC, we can give the former pub another chance at life. Sadly we don’t think *we* can run it as a pub. We know this might be disappointing because it was a popular watering hole, but we also don’t like the idea that the building is just sat there with the risk of being knocked over looming!
So what are we looking to do if not a pub?
We think that the former pub would make a good workspace & cafe. The space would be set up to attract entrepreneurs, freelancers and small businesses into the area, and it would create jobs for the local community and offer a social space.
The locals among you will also know that [REDACTED SITE NAME] has a fairly big function room as well. If this goes ahead, we would have this room used to host a range of events potentially including film screenings, classes and private meetings. Let me be clear: We want this reincarnation to be good for the neighbourhood and to offer a place where people can meet, and hopefully get into entrepreneurship.
I should say that we know that Gainsborough Sq is just round the corner and it’s bustling with lots of fantastic local enterprises, and we want to add to the area, and not take away from it. If you think that any aspect of what we’re suggesting is not a good idea, please let us know.
I should say it’s very early days — for this to go ahead, a lot of people would need to be on board, including the owner, the planning office, and most importantly you, the residents.
I’d love your feedback before we do anything. We will only proceed if we have support from the neighbourhood.
So… What do you think?

Я выбрал именно эту группу в Facebook, потому что:

  1. Он был активен.
  2. У него было достаточно большое количество членов (хороший размер выборки)
  3. Это была закрытая группа — участники должны были иметь прочную связь с районом, и это проверялось администраторами. Это гарантировало, что выборка будет иметь относительно более высокий уровень качества по сравнению с тем, что было бы с открытой группой.

Мы решили оставить пост в покое на 5 дней. Мы выбрали 5 дней, потому что примерно столько времени потребовалось для поста в этой конкретной группе, чтобы стагнировать. На пятидневной отметке большинство постов перестали привлекать новую активность, такую ​​как ответы, репосты и лайки, поскольку пост был погребен под новым контентом.

Пост был довольно подробным, чтобы избежать сомнений.

Пять дней спустя пришло время подвести итоги.

К 9:00 по Гринвичу 27 января 2020 года пост имел следующую статистику:

  • 63 «Нравится»
  • 6 «Влюбленные сердца»
  • 112 комментариев
  • 10 акций

«Акции» у нас в основном неактивны и особого внимания не привлекали, за исключением одной акции, которая привлекла:

  • 18 комментариев
  • 5 лайков

С учетом других неактивных акций это дало нам в общей сложности:

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

Анализ ответа

Имея «всего» 130 комментариев, я смог просмотреть их вручную, пытаясь классифицировать каждый ответ. Я использовал следующие категории:

  • Положительный ответ
  • Отрицательный ответ
  • Альтернативное предложение (Чтобы отразить мнения жителей, которые не поддерживали и не обескураживали, а скорее хотели «чего-то другого»)

Изначально я воспринимал лайки и сердечки как положительные ответы, и это дало нам очень позитивную картину:

Однако при ближайшем рассмотрении я заметил, что некоторые люди, опубликовавшие комментарии с отказом от предложения, также «лайкнули» этот пост. Поэтому было небезопасно предполагать, что сердечки «Нравится/Люблю» указывали на положительный ответ. Поэтому я сделал им скидку.

Вот что получилось:

В этот момент вы можете спросить: «Так зачем же вы заморачивались с анализом настроений?», и ответ очень прост: я ужасно оцениваю взгляды людей. Я прирожденный пессимист, как знают мои друзья и родственники… Прогоняя данные через более нейтральный алгоритм, я надеялся получить лучшее представление об общем консенсусе, не запятнав его своим пессимизмом.

Подготовка данных

Первое, что нужно было сделать, это очистить данные и представить их так, чтобы их могла использовать CNN. Чтобы получить данные (за исключением копирования и вставки каждого комментария), у нас есть два варианта. Мы можем либо использовать Facebook Graph API, либо извлечь данные из Chrome.

Я выбрал последнее, потому что это быстро, просто и означает, что мне не нужно ждать, пока Facebook одобрит или отклонит мое приложение.

Я вскочил в Chrome, открыл сообщение и зашел в Инструменты разработчика -> Сеть, и я сохранил все запросы graphql/ и сохранил файл HAR.

Я сохранил HAR-файл в формате JSON и написал следующий фрагмент NodeJs, чтобы просмотреть каждый запрос и удалить все, кроме содержания комментариев… Facebook выдает ОГРОМНОЕ количество метаданных, поэтому было важно сначала очистить его.

let fs = require("fs");
let output = [];
let tempRow;
JSON.parse(fs.readFileSync('graph_requests.json')).forEach(request => {
tempRow = response.comments;
tempRow.forEach(comment => {
output.push({ userid: comment.from.id, commentid: comment.id, text: comment.message})
})
})

Для взаимодействия с API Facebook, если вы того пожелаете, вы можете использовать Axios или всегда можете использовать пакет FB NodeJs. Полагаю, есть несколько способов содрать шкуру с кошки...

Вот как может выглядеть ваш код, если вы пойдете по пути API:

const createCsvWriter = require('csv-writer').createObjectCsvWriter;
const csvWriter = createCsvWriter({path: "path/to/destination.csv",header: [{ id: "userid", title: "USERID" },{ id: "commentid", title: "COMMENTID" },{ id: "text", title: "TEXT" }]});
axios = require("axios")
const postsIdArray = ["MY_MAIN_POST_ID", "THE_ID_OF_THE_SHARED_POST"]; //This is the array of post IDs that we want to harvest comments from
axios.get(`https://graph.facebook.com/${postId}/comments?access_token=ACCESS_TOKEN_GOES_HERE`).then(response => {
response.comments.forEach(comment => {
csvWriter.writeRecords({ userid: comments.from.id, commentid: comment.id, text: comment.message}) // returns a promise
}
})

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

P.s. Для энтузиастов Python я бы рекомендовал использовать что-то вроде это.

Получив свой CSV-файл, я в последний раз просмотрел его, чтобы удалить собственные комментарии, чтобы свести к минимуму предвзятость.

Подготовка скрипта анализа настроений

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

Я сосредоточился на сравнительной оценке.

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

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

Выход

Когда набор данных готов, а сервер анализа запущен и работает, пришло время собрать все воедино.

Я добавил диаграммы и таблицы начальной загрузки для анализа файла output.html.

Вот выходной график:

А вот соседняя таблица, отображающая базовые данные:

Вы можете просмотреть скрипт взбалтывания и образец вывода здесь:

https://gist.github.com/timtamimi/5d73eaa74d391782f63e179b6e3a6111

Вот оно. Я не буду комментировать результаты, поскольку они в значительной степени не имеют отношения к целям этого поста, но я бы сказал, что они в целом соответствуют моим ожиданиям. Комментарии в целом были либо очень благосклонными, либо в целом поддерживающими, либо очень обескураживающими. Это, вероятно, объясняет отсутствие результатов во 2-м нижнем квартиле. Улучшение здесь могло бы состоять в том, чтобы уделять больше внимания стандартному отклонению, но пока этого достаточно.

С благодарностью,

Резиденты.

Авторы https://www.npmjs.com/package/sentiment

Люди, которые собрали https://www.chartjs.org/ вместе

https://www.tablesgenerator.com/markdown_tables