От време на време всички се сблъскваме с един и същ проблем — анализ на данни. Как да намерим полезна информация в безформена маса от данни. Това е доста типичен проблем, когато сме изправени пред модернизация от подобно на електронни таблици съхранение на данни.

Импортирането в релационна база данни е доста лесно, но тогава качеството на данните и възможността за заявки обикновено са много ниски.

Наскоро се сблъсках с абсолютно същия проблем. В моя случай това беше анализ на отговорите на обратната връзка. По същество имаше значително количество (50k) записи, които бяха предимно обикновен текст.

Разгледайте данните си

Първата ми стъпка беше да разгледам самите данни, просто един кратък поглед наоколо, за да събера възможно най-много знания за естеството на данните, с които щях да работя. Качество, типични правописни грешки, типове данни, точки на интерес - всичко, което би било от полза по време на следващите фази на работа.

По време на тази фаза открих няколко интересни факта:

  • записите са написани без никаква проверка на правописа,
  • структурата на данните беше подобна на дърво, а не подобна на таблица,
  • данните бяха контекстуално излишни, но анализът на обикновен текст нямаше да го покаже.

Това беше наистина страхотно, да започнем санализ с просто око. Човешкиятсофтуер за разпознаване на образи доста бързо забелязва тези неща.

Импортиране на данни

Както обикновено, имах ограничено време за това упражнение. Идеята ми беше да използвам „копаене на текстови данни“ като набор от техники за обработка на данни и моделиране на данни.

Поради спецификата на данните (подобие на дърво) започнах с импортиране на данни в MongoDB с помощта на mongoimport от CSV текстов файл.

mongoimport -d misc-data -c <collenction-name> --type csv --file <filename.csv> --headerline

Това ми даде възможност да правя заявки за данни с помощта на функцията find с някои основни филтри и прогнози, защото не всички данни бяха интересни от моя гледна точка.

db.getCollection('collection-name').find({<some filters here>},{ <some projection here>}).map( function(u) { return u["Some prop"]; } )

Следващата стъпка беше да изчистите въведените данни. Това приличаше повече на изследване на данни с помощта на node REPL, а не на внимателно проектиран подход. Но като цяло дойде доста добре.

Реших, че като краен резултат трябва да имам чисти статистически данни за използването на някои ключови думи, базирани на структурен модел.

Почистване на бъркотията

Започнах с всеки запис като един обект (с .reduce()) и след това приложих regex-es за премахване на URL адреси, бели интервали и други маловажни части.

var str = line.reduce((prev, curr) => prev + " " + curr); var lower = str.toLowerCase(); var no_url = lower.replace(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#$?&//=]*)/gi, " "); var clean = no_url.replace(/(\.|:|\(|\)|\\|\/|\-|<|>|\&)/g, " ");

Последното нещо беше да произведем tokens от първичен запис.

var tokens = clean.split(' ');

Премахване на общи думи

Следващото нещо беше премахването на най-често срещаните 100 английски думи като 'a', 'the', 'in' и т.н. от списъка с токени. Бях използвал библиотека, наречена common-words. Кодът изглежда горе-долу така.

var common = require('common-words'); function removeCommonWords(words, common) { common.forEach(function (obj) { var word = obj.word; while (words.indexOf(word) !== -1) { words.splice(words.indexOf(word), 1); } }); return words; };

Прегледайте данните си - отново

Останалото беше доста стандартно. Току-що създадох Map с всички токени и count от всеки от тях.

Сега беше моментът да прегледам данните си отново. Въз основа на най-добрите статистики подготвих модел — в моя случай това беше JS обект с дървовидна структура за картографиране в токени, което беше важно за моето изследване. Изглеждаше така:

var groups = [ { name: 'groupName1', list: [ 'token11', 'token12', 'token13'] }, { name: 'groupName2', list: [ 'token21', 'token21', 'token23'] } ]

Крайна статистика

Използвайки моя модел, извлечен директно от данни, минах през всички tokens и ги съпоставих с модела. Въз основа на това успях да събера основни статистики с допълнителна информация за групата.

Цялото упражнение ми отне около 3-4 часа и крайният резултат беше „достатъчно добър“ за мен.

Последни мисли

Както обикновено в екосистемата на JS, има библиотека, която да ви помогне да преминете през този процес, без да преоткривате колелото. Нарича се text-miner, направено от Philipp Burckhardt @burckhap .

Има API като .removeInterpunctuation() и .removeWords(words[, case_sensitive]), които ще ви помогнат да премахнете автоматично нежелано съдържание.

Страхотното е, че поддържа и по-сложен модел, използващ Terms за матрица термин-документ.

Почерпих малко вдъхновение от страхотна лекция на конференция, наречена „От мощните акорди до силата на моделите“ от OreDev 2016 от Ali Kheyrollahi @aliostadhttps:// vimeo.com/191120690

Поради факта, че токените, събрани от мен, са основно без контекст, може да се събере допълнителна дълбочина на данни чрез създаване на вектори на думи с дълбоко обучение, описано в тази статия и тук. Библиотеката за използване на тези методи е достъпна на npm - node-word2vec.

Първоначално публикувано в warzycha.pl на 15 март 2017 г.