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

1. Ваша первая модель машинного обучения

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

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

2. Набор данных

2.1. Наборы данных игрушек

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

Хотя оба являются отличными примерами для начала, обычно большинство руководств фактически не загружает эти данные непосредственно из внешнего источника (например, из файла CSV), а вместо этого импортирует их из библиотеки Python, такой как datasetsсуб- модуль scikit-learn.

Например, для загрузки набора данных Iris можно использовать следующий блок кода:

from sklearn import datasets
iris = datasets.load_iris()
X = iris.data
y = iris.target

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

2.2. Ваш собственный набор данных

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

Набор данных, который мы используем сегодня, — это solubilityнабор данных. Он состоит из 1444 строк и 5 столбцов. Каждая строка представляет собой уникальную молекулу, и каждая описывается 4 молекулярными свойствами (первые 4 столбца), а последний столбец представляет собой целевую переменную, которую необходимо предсказать. Эта целевая переменная представляет собой растворимость молекулы, которая является важным параметром терапевтического препарата, поскольку помогает молекуле перемещаться внутри организма, чтобы достичь своей цели. Ниже приведены первые несколько строк набора solubilityданных.

2.2.1. Загрузка данных

Полный solubilityнабор данных доступен на GitHub Data Professor по следующей ссылке: Скачать набор данных растворимости .

Чтобы их можно было использовать в любом проекте по науке о данных, содержимое данных из файлов CSV можно считывать в среду Python с помощью библиотеки Pandas. Я покажу вам, как это сделать, на примере ниже:

import pandas as pd
df = pd.read_csv('data.csv')

Первая строка импортирует pandasбиблиотеку в виде короткой аббревиатуры, называемой pd(для удобства ввода). Из pdмы собираемся использовать эту read_csv()функцию и поэтому вводим pd.read_csv(). Таким образом, вводя pdспереди, мы знаем, к какой библиотеке read_csv()принадлежит функция.

Входным аргументом внутри read_csv()функции является имя файла CSV, которое в нашем примере выше 'data.csv’. Здесь мы присваиваем содержимое данных из файла CSV переменной с именем df.

В этом уроке мы собираемся использовать набор данных о растворимости (доступен по адресу). Таким образом, мы будем загружать данные, используя следующий код:

import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/dataprofessor/data/master/delaney_solubility_with_descriptors.csv')

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

Теперь, когда у нас есть данные в виде фрейма в переменной df, нам нужно подготовить их в подходящем формате для использования библиотекой scikit-learn , поскольку dfбиблиотека еще не может их использовать.

Как мы это делаем? Нам нужно будет разделить их на 2 переменные: Xи y.

Первые 4 столбца, за исключением последнего, будут присвоены переменной X, а последний будет присвоен переменной y.

2.2.2.1. Присвоение переменных X

Чтобы назначить первые 4 столбца переменной X, мы будем использовать следующие строки кода:

X = df.drop(['logS'], axis=1)

Как мы видим, мы сделали это, отбросив или удалив последний столбец ( logS).

2.2.2.2. Присвоение переменной y

Чтобы назначить последний столбец переменной y, мы просто выбираем последний столбец и присваиваем его переменной yследующим образом:

y = df.iloc[:,-1]

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

y = df['logS']

А второй подход заключается в следующем:

y = df.logS

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

3. Разделение данных

Разделение данных позволяет объективно оценить производительность модели на свежих данных, которые модель ранее не видела. В частности, если полный набор данных разделен на обучающий и тестовый с использованием соотношения разделения 80/20, то модель можно построить с использованием подмножества данных 80% (т. е. который мы можем назвать обучающим набором) и впоследствии оценить на 20% подмножестве данных (т.е. которое мы можем назвать тестовым набором). Помимо применения обученной модели к тестовому набору мы также можем применить ее к обучающему набору (т. е. к данным, которые в первую очередь использовались для построения модели).

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

Для выполнения разделения данных в scikit-learnбиблиотеке есть train_test_split()функция, которая позволяет нам это сделать. Пример использования этой функции для разделения набора данных на обучающий и тестовый показан ниже:

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42)

В приведенном выше коде первая строка импортирует функцию train_test_split()из sklearn.model_selectionподмодуля. Как мы видим, входной аргумент состоит из Xи yвходных данных, размер тестового набора указан равным 0,2 (т. е. 20% данных пойдут в тестовый набор, а остальные 80% — в обучающий) и случайное начальное число. Номер установлен на 42.

Из приведенного выше кода мы видим, что одновременно создали 4 переменные, состоящие из разделенных переменных Xи yдля обучающего ( X_trainи y_train) и тестового наборов ( X_testи y_test).

Теперь мы готовы использовать эти 4 переменные для построения модели.

4. Построение модели

А вот и самое интересное! Теперь мы собираемся построить несколько регрессионных моделей.

4.1. Линейная регрессия

4.1.1. Построение модели

Начнем с традиционной линейной регрессии.

from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(X_train, y_train)

Первая строка импортирует LinearRegression()функцию из sklearn.linear_modelподмодуля. Затем LinearRegression()функция присваивается переменной lr, и .fit()функция выполняет фактическое обучение модели на входных данных X_trainи y_train.

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

y_lr_train_pred = lr.predict(X_train)
y_lr_test_pred = lr.predict(X_test)

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

4.1.2. Производительность модели

Теперь мы собираемся рассчитать показатели производительности, чтобы иметь возможность определить производительность модели.

lr_train_mse = mean_squared_error(y_train, y_lr_train_pred) 
lr_train_r2 = r2_score(y_train, y_lr_train_pred)
lr_test_mse = mean_squared_error(y_test, y_lr_test_pred) 
lr_test_r2 = r2_score(y_test, y_lr_test_pred)

В приведенном выше коде мы импортируем функции mean_squared_errorи r2_scoreиз sklearn.metricsподмодуля для вычисления показателей производительности. Входными аргументами для обеих функций являются фактические и прогнозируемые значения Y ( y_lr_train_predи y_lr_test_pred).

Давайте поговорим об используемом здесь соглашении об именах: мы назначаем функцию не требующим пояснений переменным, явно указывающим, что содержит переменная. Например, lr_train_mseи lr_train_r2явно сообщает, что переменные содержат метрики производительности MSE и R2 для моделей, построенных с использованием линейной регрессии на обучающем наборе. Преимущество использования этого соглашения об именах заключается в том, что показатели производительности любых будущих моделей, построенных с использованием другого алгоритма машинного обучения, можно легко идентифицировать по именам их переменных. Например, мы могли бы использовать его rf_train_mseдля обозначения MSE обучающего набора для модели, построенной с использованием случайного леса.

Показатели производительности можно отобразить, просто распечатав переменные. Например, чтобы распечатать MSE для обучающего набора:

print(lr_train_mse)

что дает 1.0139894491573003.

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

Другой способ — создать аккуратное отображение четырех показателей следующим образом:

lr_results = pd.DataFrame(['Linear regression',lr_train_mse, lr_train_r2, lr_test_mse, lr_test_r2]).transpose()
lr_results.columns = ['Method','Training MSE','Training R2','Test MSE','Test R2']

который создает следующий кадр данных:

4.2. Случайный лес

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

4.2.1. Построение модели

Давайте теперь построим RF‑модель, используя следующий код:

from sklearn.ensemble import RandomForestRegressor
rf = RandomForestRegressor(max_depth=2, random_state=42)
rf.fit(X_train, y_train)

В приведенном выше коде первая строка импортирует функцию RandomForestRegressor(т.е. ее также можно назвать регрессором) из подмодуля sklearn.ensemble. Здесь следует отметить, что RandomForestRegresso — это версия регрессии (т. е. она используется, когда переменная Y содержит числовые значения), а ее родственная версия — это RandomForestClassifierверсия классификации (т. е. она используется, когда переменная Y содержит категориальные значения). ).

В этом примере мы устанавливаем max_depthпараметр равным 2, а случайное начальное число (через random_state) — 42. Наконец, модель обучается с использованием функции rf.fit(), в которой мы установили X_trainи y_trainв качестве входных данных.

Теперь мы собираемся применить построенную модель для прогнозирования обучающего и тестового наборов следующим образом:

y_rf_train_pred = rf.predict(X_train)
y_rf_test_pred = rf.predict(X_test)

Аналогично тому, как это используется в lrмодели, rfмодель также применяется для прогнозирования с помощью rf.predict()функции на обучающем и тестовом наборах.

4.2.2. Производительность модели

Давайте теперь посчитаем показатели производительности для построенной модели случайного леса следующим образом:

from sklearn.metrics import mean_squared_error, r2_score
rf_train_mse = mean_squared_error(y_train, y_rf_train_pred)
rf_train_r2 = r2_score(y_train, y_rf_train_pred)
rf_test_mse = mean_squared_error(y_test, y_rf_test_pred)
rf_test_r2 = r2_score(y_test, y_rf_test_pred)

Для консолидации результатов воспользуемся следующим кодом:

rf_results = pd.DataFrame(['Random forest',rf_train_mse, rf_train_r2, rf_test_mse, rf_test_r2]).transpose()
rf_results.columns = ['Method','Training MSE','Training R2','Test MSE','Test R2']

который производит:

4.3. Другие алгоритмы машинного обучения

Чтобы построить модели с использованием других алгоритмов машинного обучения (кроме того sklearn.ensemble.RandomForestRegressor, который мы использовали выше), нам нужно только решить, какие алгоритмы использовать из доступных регрессоров (поскольку переменная Y набора данных содержит категориальные значения).

4.3.1. Список регрессоров

Давайте посмотрим на некоторые примеры регрессоров, из которых мы можем выбрать:

  • sklearn.linear_model.Ridge

  • sklearn.linear_model.SGDRegressor

  • sklearn.ensemble.ExtraTreesRegressor

  • sklearn.ensemble.GradientBoostingRegressor

  • sklearn.neighbors.KNeighborsRegressor

  • sklearn.neural_network.MLPRegressor

  • sklearn.tree.DecisionTreeRegressor

  • sklearn.tree.ExtraTreeRegressor

  • sklearn.svm.LinearSVR

  • sklearn.svm.SVR

Более обширный список регрессоров можно найти в Scikit-learnсправочнике по API .

4.3.2. Использование регрессора

Допустим, то, что мы хотели бы использовать, sklearn.tree.ExtraTreeRegressor, мы бы использовали следующим образом:

from sklearn.tree import ExtraTreeRegressoret = ExtraTreeRegressor(random_state=42) et.fit(X_train, y_train)

Обратите внимание, как мы импортируем функцию регрессора sklearn.tree.ExtraTreeRegressorследующим образом:
from sklearn.tree import ExtraTreeRegressor

После этого функция регрессора присваивается переменной (т. е. etв этом примере) и подвергается обучению модели с помощью .fit()функции, как в et.fit().

4.4. Объединение результатов

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

Поскольку обе переменные являются кадрами данных, мы собираемся объединить их с помощью pd.concat()функции, как показано ниже:

pd.concat([lr_results, rf_results])

Это создает следующий кадр данных:

Следует отметить, что метрики производительности для дополнительных методов обучения также можно добавить, дополнив список [lr_results, rf_results].

Например, svm_results можно было бы добавить в список, который затем стал бы [lr_results, rf_results, svm_results].

5. Визуализация данных результатов прогнозирования

Давайте теперь визуализируем взаимосвязь фактических значений Y с их прогнозируемыми значениями Y, то есть экспериментальным logS и прогнозируемыми значениями logS.

Как показано выше, мы собираемся использовать Matplotlibбиблиотеку для построения диаграммы рассеяния, а Numpy используется для создания линии тренда данных. Здесь мы устанавливаем размер фигуры 5 × 5 с помощью figsizeпараметра функции plt.figure().

Функция plt.scatter()используется для создания диаграммы рассеяния, где y_trainи y_lr_train_pred(т. е. прогнозы обучающего набора, сделанные с помощью линейной регрессии) используются в качестве входных данных. Цвет устанавливается зеленым с использованием цветового кода HTML (шестнадцатеричный код) #7CAE00.

Линия тренда на графике с помощью np.polyfit()функции отображается с помощью plt.plot()функции, как показано выше. Наконец, метки осей X и Y добавляются с помощью функций plt.xlabel()и plt.ylabel()соответственно.

Визуализированная диаграмма рассеяния показана выше.

Что дальше?

Поздравляем с созданием вашей первой модели машинного обучения!

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

Комментарии (5)


  1. CrazyElf
    09.09.2023 18:16

    Много лет уже как в Pandas завезли более понятные варианты многих методов, позволяющие обойтись без невнятного параметра axis, указывая просто конкретную сущность, с которой мы работаем. Например, мы хотим выбросить столбцы и так и пишем "выбросить столбцы такие-то":

    X = df.drop(columns=['logS'])
    


  1. Kwent
    09.09.2023 18:16
    +1

    Уже примерно миллион туториалов "как сделать первую модель", зачем ещё один? Чем этот лучше других? Сильно не хватает статей уровня "как обучить сотую модель, но в этот раз нормально"


  1. BOOTor
    09.09.2023 18:16

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


    1. CrazyElf
      09.09.2023 18:16

      А как вы ими хотите дальше пользоваться? Их разве что для "sanity check" имеет смысл глянуть, "вручную" вы их всё-равно же не будете использовать, а будете дёргать predict у натренированной модели.


      1. BOOTor
        09.09.2023 18:16

        Иногда очень даже надо вручную...