Введение

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

Методы обработки естественного языка (NLP) могут применяться в режиме реального времени для автоматической классификации сообщений социальных сетей о стихийных бедствиях. Благодаря передаче полезной информации первым лицам и спасательным организациям можно значительно повысить эффективность операций по реагированию на стихийные бедствия. В этой статье мы создадим применение НЛП для реагирования на стихийные бедствия, сосредоточив внимание на классификации стихийных бедствий в социальных сетях Twitter.

Сбор данных и предварительная обработка

Сбор данных

Для сбора данных мы использовали Twitter API для потоковой передачи твитов, связанных со стихийными бедствиями. Твиты были отфильтрованы с использованием набора ключевых слов, в этом проекте мы будем использовать «землетрясение» и «наводнение». Всего для этого проекта мы собрали 10 000 твитов.

import tweepy
import pandas as pd

# Authenticate with Twitter
consumer_key = "YOUR_CONSUMER_KEY"
consumer_secret = "YOUR_CONSUMER_SECRET"
access_token = "YOUR_ACCESS_TOKEN"
access_token_secret = "YOUR_ACCESS_TOKEN_SECRET"

auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)

# Create API object
api = tweepy.API(auth)

# Define search query and number of tweets to scrape
query = "earthquake"
max_tweets = 10000

# Get tweets
tweets = tweepy.Cursor(api.search_tweets,
                       q=query,
                       tweet_mode='extended',
                       lang='id').items(max_tweets)

# Create DataFrame to store tweets
tweet_df = pd.DataFrame(columns=['username', 'tweet_text'])

# Save tweets to DataFrame
for tweet in tweets:
    tweet_df = tweet_df.append({'username': tweet.user.screen_name,
                                'tweet_text': tweet.full_text},
                               ignore_index=True)

# Save DataFrame to CSV file
tweet_df.to_csv('tweets_gempa.csv', index=False

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

Предварительная обработка

Прежде чем мы сможем обучить нашу модель классификации, нам нужно предварительно обработать необработанные текстовые данные. Вот шаги, которые мы предприняли:

  1. Очистка: мы очистили текстовые данные, удалив любую нерелевантную информацию, такую ​​как URL-адреса, теги HTML и специальные символы.
def cleaning(text):
    text = re.sub(r'pic.twitter.com.[\w]+', '', text)
    text = re.sub('((www\.[^\s]+)|(https?://[^\s]+)|(http?://[^\s]+))',' ',text) 
    text = re.sub('\n',' ',text) 
    text = re.sub(r'[^\x00-\x7F]+',' ', text)
    text = ' '.join(re.sub('(?<=^|(?<=[^a-zA-Z0-9-_\.]))@([A-Za-z]+[A-Za-z0-9-_]+)','',text).split())
    text = re.sub('(<a).*(>).*(</a>)', '', text)
    text = re.sub('(\xa0)', '', text)  
    text = re.sub('[0-9]','', text)
    to_delete = ['hypertext', 'transfer', 'protocol', 'over', 'secure', 'socket', 'layer', 'dtype', 'tweet', 'name', 'object'
                 ,'twitter','com', 'pic', ' ya ']
    
    for word in to_delete:
        text = re.sub(word,'', text)
        text = re.sub(word.upper(),' ',text)
    
    retweet_user = [' rt ', ' user ']
    
    for word in retweet_user:
        text = re.sub(word,' ',text) # Remove every retweet symbol & username
        text = re.sub(word.upper(),' ',text)
        
    text = re.sub('  +', ' ', text) # Remove extra spaces
    return text

df['Tweet'] = df['Tweet'].apply(cleaning)

2. Нижний регистр: преобразуйте весь текст в нижний регистр, чтобы одно и то же слово в разных регистрах не рассматривалось как разные слова.

df['Tweet'] = df['Tweet'].str.lower()

3. Токенизация: токенизация текста на отдельные слова или токены.

import nltk
from nltk.stem import PorterStemmer
from nltk.tokenize import sent_tokenize, word_tokenize

def identify_token(row):
    description = row['Tweet']
    tokens = word_tokenize(str(description))
    token_words = [w for w in tokens if w.isalpha()]
    return token_words
df['Tweet'] = df.apply(identify_token, axis=1)

4. Удаление стоп-слов: удалите общие слова, которые не несут особого смысла, такие как «ada», «eh», «ya» и т. д. Мы пропустили этот шаг для твитов о землетрясении, потому что они часто имеют короткие сообщения или сообщения с минимальным количеством символов, а удаление стоп-слов может значительно снизить точность.

stopword_dict = pd.read_csv("stopword_dict.csv")
def remove_stopword(text): 
    text = ' '.join(['' if word in stopword_dict.stopword.values else word for word in text.split(' ')])
    text = re.sub(' +',' ', text)
    text = text.strip()
    return text

5. Stemming: Сократите каждое слово до его основной или корневой формы. Например, «бергерак», «дигеракан» и «менгеракан» будут сокращены до «герак».

from Sastrawi.Stemmer.StemmerFactory import StemmerFactory

factory = StemmerFactory()
stemmer = factory.create_stemmer()
def stemming(text):
    my_list = text['Tweet']
    stemmed= ' '.join([stemmer.stem(Tweet) for Tweet in my_list])
    return (stemmed)

df['Tweet'] = df.apply(stemming, axis=1)

в этом проекте мы разделим данные о наводнениях и землетрясениях на разные этапы предварительной обработки. Как мы уже упоминали, этапы предварительной обработки, описанные выше, будут использоваться только для данных о наводнениях, для данных о землетрясениях мы не будем использовать этапы удаления стоп-слов. Я объясню причину этого решения позже вместе с извлечением признаков, которое мы используем, а именно TF-IDF.

TF-IDF

После этапов предварительной обработки мы преобразовываем токенизированный текст в числовое представление, используя технику Term Frequency-Inverse Document Frequency (TF-IDF). Этот метод присваивает каждому слову вес, который пропорционален его частоте в документе, но обратно пропорционален его частоте в корпусе.

from sklearn.model_selection import train_test_split

x_train,x_test,y_train,y_test=train_test_split(x,y,random_state=42,test_size=0.2)

from sklearn.feature_extraction.text import TfidfVectorizer
cv=TfidfVectorizer(ngram_range = (1,1))

x_train_trans=cv.fit_transform(x_train)

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

Как я объяснял ранее в разделе предварительной обработки, мы решили не удалять стоп-слова из данных о землетрясениях в этом проекте. Это связано с тем, что большинство твитов о землетрясениях отличаются от твитов о наводнениях. Твиты о землетрясениях обычно короткие и содержат много стоп-слов. На самом деле, некоторые из них содержат только стоп-слово и слово «землетрясение», например: «Eh ada gempa» и «Gempa woy». Поскольку мы используем метод TF-IDF, удаление стоп-слов привело бы к уменьшению ценности большинства данных (предложений/твитов), что может негативно повлиять на процесс обучения модели классификации. Чтобы помочь вам лучше понять это, я представил демонстрацию того, как удаление стоп-слов может повлиять на значения данных TF-IDF.

как мы можем видеть на картинке выше, если бы мы использовали удаление стоп-слов, землетрясение будет единственным словом в твитах.

Основываясь на формуле TF-IDF, если мы удалим стоп-слова из твитов о землетрясении, мы получим значение TF-IDF, равное 0, для слова «Гемпа». Вот почему удаление стоп-слов может негативно сказаться на процессе обучения, ведь мы не сможем определить категорию твита только по наличию слова «Землетрясение». Поэтому мы решили не удалять стоп-слова из твитов о землетрясении, чтобы обеспечить эффективное обучение модели классификации.

Модель обучения

После того, как векторы признаков были созданы с использованием метода TF-IDF, мы использовали алгоритм машины опорных векторов (SVM) для обучения нашей модели. SVM — популярный алгоритм для задач классификации текста, поскольку он хорошо работает с многомерными данными и эффективен при разделении данных на классы. Мы разделили наш набор данных на набор для обучения и набор для тестирования, при этом 80% данных использовались для обучения, а 20% — для тестирования.

Для обучения нашей модели SVM мы использовали библиотеку scikit-learn на Python. Вот пример кода простой версии для раздела «Обучение».

from sklearn.svm import SVC
clf = SVC(kernel='linear', decision_function_shape='ovo')
clf = clf.fit(x_train_trans, y_train)

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

pred = clf.predict(cv.transform(x_test))

Оценка

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

Мы использовали функцию accuracy_score из библиотеки scikit-learn для вычисления показателя точности нашей модели на тестовом наборе:

from sklearn.metrics import accuracy_score
from sklearn.model_selection import cross_val_score

pred = clf.predict(cv.transform(x_test))
score = accuracy_score(y_test, pred)
print('Accuracy LinearSVC: ',score)

После тестирования нашей модели на тестовых наборах данных для твитов о наводнениях и землетрясениях мы достигли оценки точности 88,8 % для данных о наводнениях и 87,4 % для данных о землетрясениях. Эти оценки показывают, что наша модель хорошо справляется с точной классификацией твитов, связанных со стихийными бедствиями.

Заключение

В заключение мы показали, как методы обработки естественного языка (NLP) могут применяться для классификации твитов, связанных с катастрофами. Наши результаты показывают, что использование метода TF-IDF и алгоритма машины опорных векторов (SVM) может обеспечить высокую точность классификации твитов о наводнениях и землетрясениях. Мы также обнаружили, что этап предварительной обработки, особенно удаление стоп-слов, по-разному влияет на точность моделей классификации наводнений и землетрясений. Из-за уникальных характеристик твитов о землетрясениях мы решили не удалять стоп-слова для этого набора данных.

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

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