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

Моей целью было испытать различные комбинации и посмотреть, смогу ли я добиться приличной точности. Я научился разрабатывать легкие веб-приложения, используя streamlit и python. Если вы ничего не знаете о Streamlit, я рекомендую вам ознакомиться с моим учебником по визуализации данных, чтобы вы начали.

Полный код этого руководства, а также данные можно найти на моем гитхабе.

Настройка streamlit и создание приложения

Если вы никогда этого не делали, вы можете установить streamlit с помощью этой простой команды:

$ pip install streamlit

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

import streamlit as st
import pandas as pd
import numpy as np
import os
from sklearn.preprocessing import OneHotEncoder, StandardScaler, MinMaxScaler, RobustScaler
from sklearn.impute import SimpleImputer
from sklearn.pipeline import make_pipeline, Pipeline
from sklearn.compose import make_column_transformer
from sklearn.model_selection import KFold, cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier

Импорт данных

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

#Loading the data
def get_data_titanic():
    return pd.read_csv(os.path.join(os.getcwd(), 'titanic.csv'))

Давайте посмотрим, все ли работает нормально, загрузив данные и отобразив фрейм данных:

#configuration of the page
st.set_page_config(layout="wide")
st.title('Classification exploratory tool')
st.markdown("""
This app allows you to test different machine learning
algorithms and combinations of preprocessing techniques
to classify passengers from the Titanic dataset!
""")
#load the data
df = get_data_titanic()
st.header('Original dataset')
st.write(df)

Streamlit предлагает различные способы отображения текста: st.title, st.header и st.write довольно просты; st.markdown позволяет форматировать текст, используя синтаксис уценки.

Запустите ваше приложение

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

$ streamlit run classification.py

Разделение столбцов на категории

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

target_selected = 'Survived'
cat_cols_missing = ['Embarked']
num_cols_missing = ['Age']
cat_cols = ['Pclass', 'SibSp', 'Parch', 'Sex']
num_cols = ['Fare']
drop_cols = ['PassengerId']
X = df.drop(columns = target_selected)
y = df[target_selected].values.ravel()

Теперь данные готовы к предварительной обработке. Мы создадим разные шаги предварительной обработки в зависимости от категории.

Построение конвейера предварительной обработки

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

  • Читаемость кода и организация
  • Нужно всего лишь один раз назвать пригодным и преобразить
  • Использование GridSearch для тестирования различных параметров и поиска наиболее оптимизированного конвейера.

В нашем случае конвейер предварительной обработки будет состоять из трех основных преобразований:

  • Вменение для заполнения столбцов недостающими данными
  • OneHotEncoding для преобразования категориальных данных в числовые.
  • Масштабирование для стандартизации данных и ограничения влияния выбросов

Создание виджетов для настройки конвейера предварительной обработки

В streamlit мы можем создавать объекты или виджеты для взаимодействия с пользователем. Это позволит ему выбрать, в нашем случае, тип импьютера, кодировщика и масштабирования для использования в конвейере предварительной обработки.

#Sidebar
st.sidebar.title('Preprocessing')
cat_imputer_selected = st.sidebar.selectbox('Handling categorical missing values', ['None', 'Most frequent value'])
num_imputer_selected = st.sidebar.selectbox('Handling numerical missing values', ['None', 'Median', 'Mean'])
encoder_selected = st.sidebar.selectbox('Encoding categorical values', ['None', 'OneHotEncoder'])
scaler_selected = st.sidebar.selectbox('Scaling', ['None', 'Standard scaler', 'MinMax scaler', 'Robust scaler'])

Мы создали четыре объекта поля выбора. Теперь они отображаются сбоку в нашем приложении. Теперь нам нужно учесть выбранные шаги предварительной обработки и добавить их в конвейер. Для этого мы создадим функции, которые будут возвращать импортер, масштабатор или кодировщик из sklearn. Эти три функции довольно просты. Не забудьте поместить эти функции в начало кода, например сразу после функции get_data_titanic.

def get_imputer(imputer):
    if imputer == 'None':
        return 'drop'
    if imputer == 'Most frequent value':
        return SimpleImputer(strategy='most_frequent', missing_values=np.nan)
    if imputer == 'Mean':
        return SimpleImputer(strategy='mean', missing_values=np.nan)
    if imputer == 'Median':
        return SimpleImputer(strategy='median', missing_values=np.nan)
def get_encoder(encoder):
    if encoder == 'None':
        return 'drop'
    if encoder == 'OneHotEncoder':
        return OneHotEncoder(handle_unknown='ignore', sparse=False)
def get_scaler(scaler):
    if scaler == 'None':
        return 'passthrough'
    if scaler == 'Standard scaler':
        return StandardScaler()
    if scaler == 'MinMax scaler':
        return MinMaxScaler()
    if scaler == 'Robust scaler':
        return RobustScaler()

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

def get_pip_mis_num(imputer, scaler):
    if imputer == 'None':
        return 'drop'
    pipeline = make_pipeline(get_imputer(imputer))
    pipeline.steps.append(('scaling', get_scaler(scaler)))
    return pipeline
def get_pip_mis_cat(imputer, encoder):
    if imputer == 'None' or encoder == 'None':
        return 'drop'
    pipeline = make_pipeline(get_imputer(imputer))
    pipeline.steps.append(('encoding', get_encoder(encoder)))
    return pipeline

Эти две функции могут возвращать двухэтапный конвейер, если нам это нужно.

Конвейер предварительной обработки

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

preprocessing = make_column_transformer( 
(get_pip_mis_cat(cat_imputer_selected, encoder_selected) , cat_cols_missing),
(get_pip_mis_num(num_imputer_selected, scaler_selected) , num_cols_missing),
(get_encoder(encoder_selected), cat_cols),
(get_scaler(scaler_selected), num_cols),
("drop" , drop_cols)
)
preprocessing_pipeline = Pipeline([
    ('preprocessing' , preprocessing)
])

Мы успешно построили конвейер предварительной обработки. Теперь мы приспособим этот конвейер к данным и преобразуем данные. Давайте посмотрим на это в действии.

preprocessing_pipeline.fit(X)
X_preprocessed = preprocessing_pipeline.transform(X)
st.header('Preprocessed dataset')
st.write(X_preprocessed)

Выбрав импьютер, кодировщик и масштабатор, мы могли бы получить такой результат:

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

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

Мы можем предоставить пользователю выбор классификатора и добавить выбранную модель в наш финальный конвейер.

st.sidebar.title('Model selection')
classifier_list = ['Logistic regression', 'Support vector', 'K nearest neighbors', 'Random forest']
classifier_selected = st.sidebar.selectbox('', classifier_list)
pipeline = Pipeline([
    ('preprocessing' , preprocessing),
    ('ml', get_ml_algorithm(classifier_selected))
])

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

def get_ml_algorithm(algorithm):
    if algorithm == 'Logistic regression':
        return LogisticRegression()
    if algorithm == 'Support vector':
        return SVC()
    if algorithm == 'K nearest neighbors':
        return KNeighborsClassifier()
    if algorithm == 'Random forest':
        return RandomForestClassifier()

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

folds = KFold(n_splits = 10, shuffle=True, random_state = 0)
cv_score = cross_val_score(pipeline, X, y, cv=folds)
st.subheader('Results')
st.write('Accuracy : ', round(cv_score.mean()*100,2), '%')
st.write('Standard deviation : ', round(cv_score.std()*100,2), '%')

Конечный результат

Мы подошли к концу этого урока. Вы должны получить приложение, которое выглядит так.

Мы видим, что с хорошими шагами предварительной обработки и алгоритмом KNN мы достигаем точности 80,25%. Вы можете поиграть с различными параметрами предварительной обработки, чтобы увидеть, как они влияют на результат.

Заключение

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

Следующие шаги

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

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

Ссылки

  • Мой предыдущий урок, чтобы понять основы Streamlit.
  • Учебное пособие по лучшему пониманию конвейеров можно найти здесь.
  • Точный код этого руководства и файлы csv можно найти здесь.
  • На основе этого я создаю более продвинутый проект, доступ к которому можно получить по адресу https://ml-exploration-tool.herokuapp.com/.
  • Полный код этого продвинутого проекта доступен на моем гитхабе.