Данные, данные, везде, но ни капли информации в поле зрения !

(…Приношу извинения Кольриджу )

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

Чтобы узнать, могут ли методы Data Science / ML помочь мне улучшить свои навыки письма, я создал простое веб-приложение на основе Python Flask, которое быстро анализирует веб-страницы для получения некоторых быстрых идей на основе показателей высокоуровневого анализа текста.

Приложение возвращает статистические показатели, такие как количество слов, предложений и т. д., а также функции НЛП, такие как оценки анализа тональности и оценки удобочитаемости. Используя предварительно обученные модели, созданные некоторыми другими, я также включил код, предсказывающий тип личности автора. В приложении также есть функция «предсказателя хлопков», которая оценивает количество ожидаемых хлопков с помощью двух подходов  — простой модели прогнозирования линейной регрессии (предупреждение, точность довольно низкая) и классификатора, который использует векторизацию встраивания документа (Doc2Vec).

Я разместил код в Интернете, так что не стесняйтесь оставлять мне отзывы или клонировать мой репозиторий и улучшать его (например, создавать собственные наборы данных, переобучать модели и т. д.)

Веб-сайт с демонстрацией приложения:http://35.247.191.22:5000/

Зачем вы это сделали?

Я пишу на темы, связанные с Data Science, на Medium.com уже пару месяцев и изо всех сил пытался улучшить свои статьи и увеличить количество аплодисментов/просмотров. Поэтому я начал задаваться вопросом, могу ли я использовать методы машинного обучения или науки о данных, чтобы писать лучше.

Существуют решения на основе ИИ, такие как Grammarly (помощник по письму на основе ИИ). Однако я решил начать с более скромных амбиций и создать простое веб-приложение, которое могло бы обрабатывать текст и возвращать некоторые ключевые показатели.

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



Схема

1. Извлечение и очистка необработанных данных

2. Обработка данных HTML/текста для извлечения ключевых показателей

3.Создание моделей прогнозирования

3.1. Прогноз личностного анализа — индикатор типа Майерс-Бриггс

3.2. Прогноз личностного анализа — черты Большой пятерки

3.3.Оценщик количества хлопков

3.3.1 Исследовательский анализ данных

3.3.2 «Простой оценщик линейной регрессии»

3.3.3 Классификатор на основе встраивания документов

4. Преобразование кода в простое приложение Flask

5.Заключение

1. Извлечение и очистка данных

Это было довольно просто, так как я использовал библиотеки Python Requests для большей части веб-скрейпинга.

from bs4 import BeautifulSoup
import urllib.request
from urllib.request import Request, urlopen
class ArticleExtract():
def __init__(self,url,text_input=False):
        self.url = url
        self.text_input= text_input # To allow for text input too
#Set get_html and cleaned_text as properties as these get re-used by other functions
@property
def get_html(self):
        user_agent_list = ['Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15','Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0','Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36','Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:77.0) Gecko/20100101 Firefox/77.0','Mozilla/5.0 (Windows NT 10.0; Win64;x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36',]
          if self.text_input==False:
            for i in range(1,4):
                #Pick a random user agent
                user_agent = random.choice(user_agent_list)
                #Set the headers 
                headers = {'User-Agent': user_agent}
          req = Request(self.url, headers=headers)
          self._get_html = urlopen(req).read()
          if self.text_input==True:
                self._get_html = self.url
                
          return self._get_html
...

Я начал с создания класса, который принимает текст или URL-адрес в качестве входных данных и имеет целую кучу методов для обработки данных и сохранения выходных данных. (Однако этот объект класса в конечном итоге раздулся, поэтому мне пришлось реорганизовать его, чтобы он стал набором функций в приложении Flask — подробнее об этом позже)

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

class ArticleExtract():
...
def cleaned_text(htmlinput):
    cleaned_text=BeautifulSoup(htmlinput, "html.parser").get_text("  ").replace("\r", " ").replace("\t", " ").replace("\n", " ").replace(u'\xa0', u' ')
    return cleaned_text
...

2. Обработка данных

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

https://readable.com

https://seoscout.com/tools/keyword-analyzer

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

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



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

class ArticleExtract():
...
@property
def tokens_alpha(self):
        raw = BeautifulSoup(self.get_html, 'html.parser').get_text(strip=True)
        words = nltk.word_tokenize(raw)
        self._tokens_alpha= [word for word in words if word.isalpha()] # or use option of := if word.isalnum()
        return self._tokens_alpha
...

Также следует отметить библиотеку TextBlob, которую я использовал для анализа настроений.



Анализ настроений использует анализ ключевых слов для определения полярности (насколько негативным или позитивным является утверждение) и субъективности (в отличие от нейтральных утверждений, основанных на фактах, например, я думаю…, вам следует… и т. д.). 100% за отрицательные утверждения и +100% за положительные утверждения. Оценка субъективности имеет диапазон, в котором 0,0% очень объективны, а 100% очень субъективны.

class ArticleExtract():
...
def sentiment(self):
        blob = TextBlob(self.cleaned_text)
        split_text=blob.sentences
        
        df=pd.DataFrame((''.join(split_text[i]) for i in   
        range(len(split_text))),columns=['Sentences'])
        
        df[["TextBlob_Polarity","TextBlob_Subjectivity"]]=
        pd.DataFrame((split_text[i].sentiment for i in 
        range(len(split_text))))
        df=df[df['Sentences'].map(len) > 15] #Remove all short 
        sentences
        #Avoid counting any sentences with Polarity 0 or    
        Subjectivity 0 
        
        TextBlob_Overall_Polarity=df[df["TextBlob_Polarity"] != 0]
        ['TextBlob_Polarity'].median()
        
        TextBlob_Overall_Subjectivity=df[df["TextBlob_Subjectivity"] 
        != 0]['TextBlob_Subjectivity'].median()
        
        return 
             TextBlob_Overall_Polarity,TextBlob_Overall_Subjectivity
...

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



Для простоты я в конце концов остановился на единственной метрике под названием Flesch Reading Ease Score, которую я оценил с помощью библиотеки Textstat.

Он рассчитывается по формуле, учитывающей среднюю длину предложения и среднее количество слогов в слове, где чем выше оценка, тем легче читать текст (например, > 90 = очень просто, ‹ 30 = очень запутанно)

class ArticleExtract():
...
def FS_ReadingEaseScore(self):
        
       FS_GradeScore=textstat.flesch_reading_ease(self.cleaned_text)
        return FS_GradeScore
...

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

Урок 1. Не не недооценивайте важность правильной очистки html-текста. Например, я изначально использовал BeautifulSoup.get_text() для очистки HTML-тегов вместо .get_text(“ ”). Поэтому я получил такую ​​ерунду: -

BeautifulSoup('<span>this is a</span>cat').text
Output : u'this is acat

Это означало, что я всегда непреднамеренно соединял слова вместе, а все остальное, что после этого полагалось на «вычищенный текст», было НЕПРАВИЛЬНЫМ  — например, это увеличило длину предложений и ухудшило показатели удобочитаемости, запутало анализ тональности и т. д. Другие области — это такие вещи, как предложения с такими символами, как « — » или «-», или таблицы/списки, которые в зависимости от того, как они были установлены в html, могут заканчиваться как тарабарщина и раздувать количество предложений.

3. Построение прогнозных моделей

Анализ личности

Хотя, строго говоря, профилирование личности не является частью анализа текста как такового, я подумал, что это будет забавным дополнением к приложению. Сначала я хотел разработать свою собственную модель, но это оказалось немного сложнее, чем я ожидал, поэтому вместо этого я адаптировал работу нескольких авторов, размещенных в Интернете.

3.1 Индикатор типа Майерс-Бриггс

Индикатор типа Майерса-Бриггса (MBTI) пытается объяснить, как люди воспринимают мир и принимают решения, и распределяет людей по четырем категориям: интроверсия или экстраверсия, ощущение или интуиция, мышление или чувство, суждение или восприятие. Для получения четырехбуквенного результата теста берется одна буква из каждой категории, например INFJ или ENFP.

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



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

3.2 Анализ личности Большой пятерки

Точно так же другим популярным подходом к профилированию личности является модель Большой пятерки черт (также иногда известная как модель O.C.E.A.N), которая представляет собой группу из пяти основных черт личности:

  • открытость опыту (изобретательный/любопытный против последовательного/осторожного)
  • добросовестность (эффективность/организованность против экстравагантности/небрежности)
  • экстраверсия (общительная/энергичная против уединенной/сдержанной)
  • доброжелательность (дружелюбие/сочувствие против вызова/черствости)
  • невротизм (чувствительный/нервный против стойкого/уверенного)

Я использовал предварительно обученную модель (которая представляет собой комбинацию Random Forest Regressor и Random Forest Classifier) ​​из этого репозитория проекта:



В своем приложении я использовал только их предварительно обученные модели для прогнозирования. Однако масштабы всего проекта впечатляют, так как он объединяет Python, Django и Node JS, который очищает ваши данные FB, сохраняет их в экземпляре базы данных (это может быть ваша собственная база данных) и отображает все результаты на пользовательском веб-сайте. приложение, которое может сравнивать все профили личности вашего друга с вашими собственными.

Итак, для этого раздела моим ключевым выводом было:

Урок 2. Использование чужой работы там, где это уместно (при условии, что это общедоступно и вы отдаете должное авторам оригинала ;-) Я рассмотрел эту тему в предыдущая статья , но стоит повторить — если вы можете определить, что вам нужно, и осознаете потенциальный компромисс между ценой и производительностью / уровнем поддержки / документацией — скорее всего, уже существует услуга или какой-то проект с открытым исходным кодом. решение под рукой.

3.3. Прогнозы аплодисментов

Для предсказания хлопков я мог бы использовать аналогичный подход копировать и адаптировать, так как на эту тему есть довольно много хороших статей [1], [2], [3] и [4]. .Однако задача была достаточно интригующей, и я захотел попробовать ее сам.

3.3.1 Исследовательский анализ данных

Чтобы продолжить, используйте файл ExploratoryDataAnalysis.ipynb в репозитории.

Я использовал сценарий, созданный на шаге 2, чтобы собрать около 200 статей с первых страниц Towards Data Science и Analytics Vidhya. URL-адреса статей и количество хлопков были собраны с помощью Parsehub (отличный инструмент, о котором я рассказал в предыдущей статье) (я знаю, что мог бы сделать это изначально в Python, но после нескольких часов возни с Beautiful Soup, а потом и библиотеку Selenium я забросил — пагинация тяжелая, ладно?)

Я знаю, что 200 крошечный набор данных, но я хотел начать с небольшого «кураторского» набора данных, чтобы лучше понять, как поведут себя модели. К сожалению, позже я узнал, что большинство популярных статей на первой полосе были недавно опубликованы (и в результате количество аплодисментов обычно составляет только трехзначное число, потому что статья еще не успела «созреть»), поэтому я фактически получил несколько несбалансированный набор данных. Я также добавил несколько «отобранных вручную» статей конца 2018/2019 годов, чтобы немного разнообразить возраст и количество хлопков. (Обратите внимание, однако, что эта проблема чрезмерного представления новых статей вернется и укусит меня в @ss, как вы вскоре увидите)

Большинство статей относились к категории с низким количеством аплодисментов, и лишь немногие (в основном старые) с большим количеством аплодисментов.

Учитывая такое поведение типа «степенной закон» в отношении количества хлопков, я создал метрику Log Clap Count, так как думал, что это будет лучшая мера. Сначала я провел простую корреляцию Пирсона, чтобы понять различные показатели и посмотреть, есть ли закономерность или какие-либо сильные корреляции с числом хлопков в логарифме. Результаты были неубедительны, поскольку единственными показателями, которые показали сильную корреляцию, были:

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

  • Подсчет предложений и подсчет слов — это было нелогично, так как казалось, что в более длинных статьях с большим количеством предложений больше аплодисментов?

Я избавлю вас от других диаграмм, но что меня удивило, так это то, что такие показатели, как полярность или субъективность, оценки читабельности и большинство оценок личности были меньше 0,20 в абсолютном выражении.

Чтобы помочь мне по-другому взглянуть на данные и лучше визуализировать некоторые выбросы, которые могут искажать корреляции, я также построил рядом ящичковые диаграммы для подсчета хлопков Hi-Med-Lo (выбрано несколько произвольно как H: > 5k (37). Ст.) , М : 5к-0,5к (58 ст.) , Л : ‹ 0,5к Хлопки (105 ст.) ) из всего 200 ст.

При таком представлении в виде коробчатой ​​диаграммы можно увидеть слабую взаимосвязь между статьями Hi Clap, которые, как правило, имеют немного более высокую оценку FS . Это имеет смысл, так как более низкий балл означает, что текст труднее читать. (Либо это, либо мои данные или обработка данных были плохими)

Хотя не было заметной закономерности между статьями Hi/Mid/Lo Clap по предсказанным типам личности MBTI, было интересно увидеть, что модель логистической регрессии, используемая для классификатора MTBI, похоже, предполагает, что большая часть из 200 статей была написана #- Авторы типа #-TJ.

Если вам интересно, в блокноте IPYNB в репозитории Github есть более подробная информация, но ничего особенного.

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

3.3.2 Прогнозирование хлопков с помощью модели линейной регрессии

Я использовал очень простой ванильный подход, который в ретроспективе, вероятно, не очень хорошо отражает фактические отношения, но я использовал ряд подходов линейной регрессии из набора инструментов обучения SciKit с набором функций, созданным вручную, где я более или менее просто отбрасывал все метрики MTBI и Big5 Personality (поскольку большинство из них в любом случае имели низкую корреляцию)

df = pd.read_excel('Dataset.xlsx')
df['log_claps']=np.log(df.claps)
#Regression Variables were "hand-picked" to exclude non numerical and both MTBI and Big5 OCEAN characteristics
column_for_regression=["Age_19Sep20","sentence_count","title_word_count","average_word_count_per_sentence","text_word_count","vocab_count_excl_commonwords","imgs_per_1000words","FS_GradeScore","vids_per_1000words","polarity","subjectivity"]
X=df.loc[:, df.columns.intersection(column_for_regression)]
y = df['log_claps']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
lasso_alphas = 10**np.linspace(-5,0,1000)
lasso_cv = LassoCV(alphas = lasso_alphas, cv=5)
lasso_cv.fit(X_train, y_train)
lasso_cv.alpha_
lasso = Lasso(alpha=lasso_cv.alpha_)
lasso.fit(X_train, y_train)
predicted_claps_lasso = lasso.predict(X_test)
lasso_mse = mean_squared_error(y_test, predicted_claps_lasso)
r_sq = lasso.score(X_test, y_test)
print("Lasso Regression")
print("")
print('coefficient of determination:', round(r_sq,3))
print("")
print('intercept:', lasso.intercept_)
print("")
print('slope:', lasso.coef_)
print("")
print('Mean Sq Error in Log Claps',lasso_mse)
print("")
print('Mean Sq Error in Claps',np.exp(lasso_mse))

Лассо-регрессия показала себя лучше, чем хребтовая регрессия и базовая нерегуляризованная линейная регрессия.

Итак, насколько хорошо он работает? Как и следовало ожидать — не очень… :(

Ошибки «взорваны», потому что регрессия против Log Claps. Модель, кажется, хорошо работает для статей, которые на самом деле были менее 2000 хлопков, но все, что выше этого, похоже, не работает.

Поэтому я бы посоветовал применить этот прогноз хлопков к новым статьям (6–9 месяцев от даты публикации), которые в любом случае совпадают с большинством обучающих данных. (Каковы были шансы ?! *сарказм*)

3.3.2 Прогнозирование хлопков с помощью модели «классификации»

В этом другом подходе я проигнорировал ВСЕ текстовые метрики и сосредоточился только на содержании (очищенного) текста. Чтобы продолжить, используйте файл Training_A_Doc2Vec_Model.ipynb в репозитории.

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

При этом вы можете численно представить любое слово, проанализированное в том же корпусе, в виде вектора равной длины, а затем найти «расстояние» между этим словом и любыми другими. Таким образом, вы можете сделать некоторые довольно интересные вещи, например добавить вектор для Короля и Женщины и получить вектор, который точно соответствует вектору для Королевы.



Существует эквивалентный процесс для встраивания на уровне ДОКУМЕНТА под названием Doc2Vec, который расширяет эту идею, позволяя переводить целые документы в вектор.



Таким образом, мой общий подход здесь состоял в том, чтобы обучить модель Doc2Vec, используя текст из 200 статей, а затем найти вектор «СРЕДНИЙ» для статей с высоким и низким количеством хлопков. Неявное предположение состоит в том, что в семантическом содержании есть что-то, что может различать статьи «высокий — средний — низкий».

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

Подход был таким, как показано ниже, с использованием библиотеки gensim.

import pandas as pd
import numpy as np
from numpy import save
from numpy import load
from scipy import spatial
import gensim
from nltk.corpus import stopwords
from collections import namedtuple
from gensim.models import doc2vec
from gensim.models.doc2vec import Doc2Vec
from gensim.models.doc2vec import Doc2Vec, TaggedDocument
from nltk.tokenize import word_tokenize
data_source = pd.read_excel('Dataset.xlsx')
data_source.drop(data_source.columns.difference(['ID','title','popularity_level','raw_text']), 1, inplace=True)
data = data_source["raw_text"]
tagged_data = [TaggedDocument(words=word_tokenize(_d.lower()), tags=[str(i)]) for i, _d in enumerate(data)]
#Code adapted from https://medium.com/@mishra.thedeepak/doc2vec-simple-implementation-example-df2afbbfbad5
max_epochs = 100
vec_size = 300
alpha = 0.025
Doc2VecModel = Doc2Vec(vector_size=vec_size,
                alpha=alpha, 
                min_alpha=0.00025,
                min_count=1,
                dm =1)
  
Doc2VecModel.build_vocab(tagged_data)
for epoch in range(max_epochs):
    print('iteration {0}'.format(epoch))
    Doc2VecModel.train(tagged_data,
                total_examples=Doc2VecModel.corpus_count,
                epochs=Doc2VecModel.iter)
    # decrease the learning rate
    Doc2VecModel.alpha -= 0.0002
    # fix the learning rate, no decay
    Doc2VecModel.min_alpha = model.alpha
    
Doc2VecModel.save("Doc2Vec.model")

Используя функцию подобия в Doc2Vec, которая может найти наиболее похожие статьи в модели, она произвела довольно точное совпадение — я не уверен, есть ли какой-то особый стиль письма, который она выбрала, но когда я скормил ей одну из своих статей, она выбрал ВСЕ написанные мною из остальных 199.

В отличие от HML в предыдущем подходе линейной регрессии, я сделал более точное разделение классов VH на VL со следующими деталями: VH, >10000 хлопков (21 статья); H, 5000–10000 хлопков (15 артикулов); М, 1000–5000 хлопков (29 артикулов); Л, 100–1000 хлопков (82 ст.); ВЛ, ‹100 хлопков (53 ст.).

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

Судя по графику TSNE, существует закономерность, при которой предметы с низким хлопком находятся дальше от «центра» (см. голубые и фиолетовые точки). Возможно, это будет преувеличением, но зеленый и темно-синий кажутся ближе к центру. Опять же, проблема в том, что классы несбалансированы (статей с низким количеством аплодисментов больше, чем статей с высоким количеством аплодисментов).

В любом случае доказательство того, что пудинг съеден, так насколько хорошо работает классификатор? Удивительно… довольно хорошо с точностью около 80%!

Урок 3. Методы машинного обучения (выбор модели, настройка гиперпараметров и т. д.) являются лишь частью успешного применения модели. В конечном счете, более ВАЖНЫМ является качество обучающих данных. Это варьируется от всего, что касается полноты (является ли она репрезентативной для того, что вы пытаетесь предсказать/понять — учитывая, что у меня были проблемы с дисбалансом классов с возрастом статей и количеством хлопков), согласованности/правильности (в моем случае я подозреваю, что этапы предварительной обработки могут по-прежнему содержать ошибки) и контекст — то есть понимание того, как будет применяться модель машинного обучения, чтобы дать некоторое представление о допустимом уровне ошибок.

4. Преобразование кода в простое приложение Flask

Первоначально я ожидал, что перевод моего кода в приложение Flask будет относительно простым, поскольку я принял сознательное решение не включать обычные функции веб-приложения (например, без счетчика просмотров, без управления входом в систему, без раздела отзывов/комментариев). Вскоре я обнаружил, что это не так :(

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

Это сработало, потому что я не оптимизировал скорость во время парсинга веб-страниц и все еще находился на исследовательской стадии анализа данных, где после создания экземпляра объекта класса с определенным URL-адресом я выборочно использовал другие методы для вызова конкретных показателей или построения диаграмм. или что-то еще. (То есть я не запускал ВСЕ методы сразу, и мой веб-скрейпинг (который я оставил работать на ночь) был только для высокоуровневых метрик на уровне страницы, а не для подробного анализа предложения за предложением или предсказания хлопков)

Однако вставка всего этого кода в приложение Flask ужасно замедлила работу. Flask работает, создавая представления для каждой страницы, которые работают с HTTP-запросом, отправленным отдельными страницами, — по сути, делая каждое представление отдельной функцией. Поскольку по умолчанию Flask не позволяет обмениваться данными между представлениями [1] , это также означало, что для каждой страницы мне приходилось по существу создавать совершенно новую локальную версию объекта ArticleExtract. для одного и того же URL-адреса и каждый раз ЗАПУСКАТЬ все заново.

У Flask есть функция сеанса, но она может хранить «куки», но это ограничено только 400 КБ, и большая часть документации рекомендует использовать решение для базы данных для «сохранения» данных на разных страницах.

В конце концов я разделил объект ArticleExtract на отдельные функции и создал класс «контейнер» для хранения ключевых данных, которые обычно используются для разных просмотров страниц, чтобы ускорить время обработки.

Урок 4. При разработке кода, который необходимо развернуть, ПЛАНИРУЙТЕ ЗАРАНЕЕ и учитывайте производительность кода с точки зрения эффективности использования памяти во время обработки. Чтобы упростить устранение неполадок, также рекомендуется «модулировать» код на управляемые фрагменты, а не писать монолитный блок кода, который тесно связан (т. е. чем больше зависимостей/ссылок включено в поток кода, тем выше вероятность ошибки). весь код выходит из строя при внесении каких-либо правок)

5. Заключение

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

Подводя итог, мои основные выводы как энтузиаста Data Science и n00b-разработчика заключались в следующем:

  • При выполнении любых текстовых обработок — не стоит недооценивать важность правильной обработки необработанных HTML-данных!
  • При необходимости использовать работу других
  • Методы машинного обучения — это только часть успешного приложения модели — в конечном счете, КРИТИЧЕСКИ ВАЖНО является качество обучающих данных
  • ПЛАНИРУЙТЕ ЗАРАНЕЕ — оцените эффективность требуемого объема памяти и времени обработки для запуска кода

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