Создавайте модели, которые помогут организациям, занимающимся стихийными бедствиями, спасти жизни людей.
И снова привет! Добро пожаловать в мою четвертую статью о машинном обучении. Недавно я реализовал проект, который считаю социально значимым. Я дам краткий обзор, что это такое, и сразу погрузлюсь в код :)
В этом проекте я применяю навыки инженерии данных для создания API (интерфейса прикладного программирования), который классифицирует сообщения о бедствиях из различных источников (Twitter, текстовые сообщения) по 36 категориям. Эта проблема классификации является разновидностью машинного обучения с учителем, поскольку модель учится классифицировать результат на основе предоставленных ей данных. Т.е. с чем связано сообщение: вода, еда, кров, деньги и т. д.? Причина в том, что когда случается бедствие, миллионы сообщений отправляются и публикуются в Твиттере, чтобы проинформировать об этом. Однако о стихийных бедствиях заботятся разные организации. Продовольствие может предлагать одна организация, а о тушении пожаров позаботится другая организация. Следовательно, полезность этого приложения будет заключаться в том, чтобы разделить эти сообщения на различные типы, чтобы можно было понять, какой тип помощи необходим для конкретного бедствия.
Структура проекта
Проект состоит из трех частей:
- Конвейер ETL
Извлечение, преобразование и загрузка данных. Это связано с обработкой данных. А именно я загрузил, объединил и очистил набор данных сообщений и категорий. Я сохранил в базе данных SQLite, чтобы модель могла использовать его на следующем этапе обучения. - Конвейер машинного обучения
Конвейер машинного обучения предназначен для обучения модели и ее тестирования. Конвейер включает часть обработки текста, потому что она имеет дело с текстовыми источниками, как упоминалось в начале. Я также использовал GridSearchCV для дальнейшей настройки модели и сохранения ее как файла pickle. - Веб-приложение Flask
run.py
process_data
иtrain_classifier
- это, по сути, конвейер ETL и конвейер ML, включенные в рабочее пространство терминала для обеспечения работы приложения.
Трубопровод ETL
В первой части проекта моя цель - извлечь нужные мне данные, произвести необходимые преобразования, чтобы потом использовать их при построении алгоритма. После того, как я взглянул на два набора данных, которые мне нужны: categories
и messages
, я объединил два набора данных, используя общий идентификатор.
# merge data sets df = messages.merge(categories, on = [‘id’]) df.head()
Затем я разделил категории на отдельные столбцы категорий и дал каждому столбцу отдельное имя категории.
# create a dataframe of the 36 individual category columns categories = df['categories'].str.split(';', expand = True) row = categories.head(1) category_colnames = row.applymap(lambda x: x[:-2]).iloc[0, :].tolist() # rename the columns of `categories` categories.columns = category_colnames categories.head()
Поскольку модели используют числа в качестве входных данных, я преобразовал значения категорий только в числа 0 или 1.
for column in categories: # set each value to be the last character of the string categories[column] = categories[column].astype(str).str[-1] # convert column from string to numeric categories[column] = categories[column].astype(int) categories.head()
После преобразования столбцов категорий я внес изменения во фрейм данных. Я заменил исходный столбец категории новыми столбцами категорий.
# drop the original categories column from `df` df.drop('categories', axis = 1, inplace = True) # concatenate the original dataframe with the new `categories` dataframe df = pd.concat([df, categories], axis = 1) df.head()
Проверив дубликаты в своих данных, я избавился от них.
# check number of duplicates df[df.duplicated].shape (170, 40) # drop duplicates df.drop_duplicates(inplace = True) # check number of duplicates df[df.duplicated].count()
Я наконец сохранил чистый набор данных в базе данных SQLite.
# Save the clean dataset into a sqlite database. engine = create_engine('sqlite:///disaster.db') df.to_sql('messages_disaster', engine, index=False)
ML конвейер
Во второй части проекта я создал конвейер машинного обучения, который использовался для классификации сообщений о бедствиях по различным категориям. Причина того, что его называют «конвейером», заключается в том, что этот инструмент моделирования состоит из нескольких этапов, которые обрабатывают входные данные для генерации выходных данных. В данном случае я использовал токенизацию для обработки текстовых данных.
# load data from database engine = create_engine('sqlite:///disaster.db') df = pd.read_sql_table('messages_disaster', con = engine) X = df['message'] Y = df.drop(['message', 'genre', 'id', 'original'], axis = 1) # Tokenization function to process text data. def tokenize(text): tokens = word_tokenize(text) lemmatizer = WordNetLemmatizer() clean_tokens = [] for tok in clean_tokens: clean_tok = lemmatizer.lemmatize(tok).lower().strip() clean_tokens.append(clean_tok) return clean_tokens
Конвейер машинного обучения будет использовать столбец message
как входную и выходную классификацию по 36 категориям в наборе данных. Это проблема обработки естественного языка; т.е. обработка текста для извлечения смысла из сообщения. Разве это не потрясающе?
pipeline = Pipeline([ ('vect', CountVectorizer()), ('tfidf', TfidfTransformer()), ('clf', MultiOutputClassifier(RandomForestClassifier())) ])
Как и в случае со всеми другими моделями машинного обучения, у нас должны быть наборы для обучения и тестирования. Причина в том, что мы не хотим, чтобы наша модель хорошо справлялась с обучающим набором, и в то же время не могла правильно классифицировать наши категории, когда она видит новые данные. Следовательно, мы должны использовать только часть наших данных, чтобы обучить их и посмотреть, как они работают на тестовой выборке.
# Split data into train and test tests. X_train, X_test, y_train, y_test = train_test_split(X,Y, test_size = 0.2, random_state = 45) # Train the model. pipeline.fit(X_train, y_train)
Когда дело доходит до тестирования моей модели, я хочу иметь несколько объективных показателей производительности. А именно я посмотрю на оценку f1, точность и запоминаемость.
# Test the model and print the classification report for each of the 36 categories. def performance(model, X_test, y_test): y_pred = model.predict(X_test) for i, col in enumerate(y_test): print(col) print(classification_report(y_test[col], y_pred[:, i])) performance(pipeline, X_test, y_test)
При создании моделей всегда полезно стремиться к улучшению. Попробуйте отрегулировать параметры модели, чтобы получить лучший результат. Это то, что я пытаюсь здесь сделать. Это тот же процесс, но с другим конвейером.
# Improve the pipeline. pipeline2 = Pipeline([ ('vect', CountVectorizer()), ('best', TruncatedSVD()), ('tfidf', TfidfTransformer()), ('clf', MultiOutputClassifier(AdaBoostClassifier())) ]) # Train the adjusted pipeline. pipeline2.fit(X_train, y_train) # Check the performance of the adjusted model. performance(pipeline2, X_test, y_test)
Я пошел еще дальше и использовал другой набор параметров с определенным диапазоном значений. С помощью GridSearchCV модель выбирает лучшие параметры.
parameters2 = { 'tfidf__use_idf': (True, False), 'clf__estimator__n_estimators': [50, 100], 'clf__estimator__learning_rate': [1,2] } cv2 = GridSearchCV(pipeline2, param_grid=parameters2) cv2.fit(X_train, y_train) performance(cv2, X_test, y_test)
Создайте API
Наконец, я завершил этот проект созданием API, который принимает сообщения о бедствиях и классифицирует их по наиболее вероятным категориям бедствий. Таким образом, мы можем помочь организациям, занимающимся бедствиями, лучше понять, какая катастрофа произошла и какая помощь необходима.
Заключительные слова
Если вы зашли так далеко, большое спасибо за чтение! Надеюсь, это даст вам представление о том, насколько полезным может быть машинное обучение. И насколько широк спектр его приложений. Мы можем буквально спасти жизни людей, зная, как обрабатывать текстовые данные и реализовывать модели. Кстати о моделях, вот полный проект на моем github.
Желаю вам всего наилучшего и оставайтесь счастливыми :)
P.S. Давайте подключимся к Linkedin!