Когда вы думаете о том, как подойти к проекту машинного обучения с учителем (ML), процесс, начиная с получения ваших данных и заканчивая развертыванием вашей модели, часто может показаться написанным всего за несколько шагов:
- Получите ваши данные и конвертируйте файл данных в желаемый формат
- Разделите данные на обучающий и тестовый наборы и выберите показатель производительности.
- Исследуйте и визуализируйте свои данные
- Очистите свои данные и выполните проектирование/выбор функций
- Обучайте многочисленные модели и выбирайте самые эффективные
- Выполните настройку гиперпараметров и выберите наиболее эффективную модель
- Разверните эту модель
Те, кто только начинает работать с ML, склонны думать, что есть только один правильный способ выполнения некоторых из вышеперечисленных шагов. Например, думать, что функциональность SKLearn train_test_split() — это единственный способ создать поезд и тестовый набор. (Несмотря на то, что существует множество других способов сделать это). В этой статье будут рассмотрены некоторые важные функции машинного обучения, которые часто упускают из виду, но которые могут значительно улучшить различные аспекты сквозного проекта.
1) Использование StratifiedShuffleSplit() для разделения данных в соответствии с распределением
Обычно при разделении набора данных мы либо используем функцию train_test_split, либо вручную разделяем данные, как показано ниже:
#X and y can be any dataframe for this example. X_train, X_test, y_train, y_test = X[:5], X[5:], y[:5], y[5:] X = [[1, 2], [3, 4], [5, 6], [7, 8]] y = [0, 1, 0, 1] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
Оба этих подхода хороши, когда у нас есть большие и сбалансированные наборы данных, поскольку размер и сбалансированность набора данных повышают вероятность того, что мы получим репрезентативные наборы для обучения и тестирования. Однако этот подход становится проблематичным, когда у нас есть меньшие и/или несбалансированные наборы данных. Например, предположим, что у нас есть данные для 100 выпускников компьютерных наук, такие как их средний балл бакалавриата, наиболее известная компания, в которой они проходили стажировку, их начальная зарплата (которая в этом примере является ярлыком) и т. д. На основе этих данных мы должны обучить модель машинного обучения, которая может предсказать среднюю начальную зарплату будущих выпускников компьютерных наук. Использование train_test_split может легко внести смещение в нашу модель, создавая случайные экземпляры наборов для обучения и/или тестирования, которые сильно отдают предпочтение определенным атрибутам. Возвращаясь к нашему примеру с выпускниками компьютерных наук, предположим, что train_test_split() дал нам обучающий набор, в котором 80% строк были выпускниками, прошедшими стажировку в компании FAANG. Наша модель будет плохо обобщать и делать неточные прогнозы на основе данных о новых выпускниках, потому что наша модель плохо подготовлена для выпускников, которые не проходили стажировку в компаниях FAANG, и выпускников, которые не проходили стажировку ни в одной компании. Нам нужен способ разделения наших обучающих и тестовых наборов таким образом, чтобы выполнялись определенные критерии (пример: только 20% выпускников могут пройти стажировку в FAANG), чтобы предотвратить недостаточное представление определенных групп данных и плохое обобщение новых данных. Этого можно добиться с помощью функции StratifiedShuffleSplit().
Вместо стратификации по самой известной стажерской компании, давайте стратифицируем по целочисленному признаку среднего балла бакалавриата, с которым гораздо проще работать, чем по категориальному признаку стажерской компании.
#cs_grads is the name of the dataframe #cs_grades is the name of the column containing grades from 0.0-4.0 from sklearn.model_selection import StratifiedShuffleSplit cs_grads["grade_dist"] = pd.cut(cs_grads["grades"], bins = [0., 1.0, 2.0, 3.0, 4.0], labels = ["F", "D", "C-B", "B-A"]) split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42) for train, test in split.split(cs_grads, cs_grads["grade_dist"]): stratified_train_set = cs_grads.loc[train] stratified_test_set = cs_grads.loc[test]
В приведенном выше коде мы сначала превращаем числовой атрибут среднего балла бакалавриата в категориальный атрибут, который примерно соответствует их средней буквенной оценке. Затем мы используем StratifiedShuffleSplit() с 0,2% данных, поступающих в тестовый набор и 0,8% процентов в обучающий набор, со случайным состоянием 42 для обеспечения воспроизводимости, а также с циклом для создания обучения и тестирования. наборы.
2) Использование параметра n_jobs для значительного ускорения процессов
При выполнении кода для обучения любой модели или настройки гиперпараметров по умолчанию используется только 1 ЦП, что подходит для небольших наборов данных. Однако, если у нас есть набор данных с 250 000 строк, обучение модели только с 1 процессором займет много часов, если не больше. Здесь в игру вступает параметр n_jobs. Этот параметр позволяет определить количество одновременно работающих ЦП/воркеров, что значительно ускорит обучение моделей и настройку гиперпараметров. Приведенный ниже код и изображение иллюстрируют, как использование увеличенных ЦП для подбора модели может ускорить процессы подбора и настройки.
import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import load_breast_cancer from sklearn.ensemble import RandomForestClassifier import time breast_cancer = load_breast_cancer() execution_times = [] n_jobs_values = range(1, 7) # Test values from 1 to 6 for n_jobs for n_jobs in n_jobs_values: start_time = time.time() model = RandomForestClassifier(n_jobs=n_jobs) model.fit(breast_cancer.data, breast_cancer.target) end_time = time.time() execution_time = end_time - start_time execution_times.append(execution_time) plt.plot(n_jobs_values, execution_times, marker='o') plt.xlabel('n_jobs') plt.ylabel('Execution Time (seconds)') plt.title('Random Forest Classifier Fitting Time vs. n_jobs') plt.grid(True) plt.show()
Приведенный выше код загружает набор данных рака молочной железы, популярный набор данных для классификации. Затем я обучаю классификатор случайного леса с параметром n_jobs, изменяющимся от одного до шести, где шесть — это все процессоры на моем компьютере. Удивительно, но 3 ЦП дают наименьшее время подгонки вместо 6 ЦП. При добавлении большего количества параллельных процессов становится довольно сложно предсказать, сколько времени потребуется для запуска каждого процесса и всего выполнения кода. Из-за этого количество ЦП не обязательно линейно коррелирует с уменьшением времени подбора. На приведенном выше графике 3 процессора, по-видимому, сокращают время работы только на 0,01 секунды, что связано с небольшим размером набора данных о раке молочной железы. Однако, если мы посмотрим на 8%-ное сокращение времени работы между 1 и 3 ЦП, мы увидим, почему параметр n_jobs может быть настолько полезен для больших наборов данных, где увеличение числа ЦП может сократить время работы на много минут или даже часов. .
3) Используйте перекрестную проверку вместо создания набора проверки
Обычно мы создаем обучающий, тестовый и проверочный наборы для обучения, оптимизации и тестирования нашей модели соответственно. Хотя наборы для обучения и тестирования абсолютно необходимы, набор для проверки часто может показаться громоздким и неэффективным. Создается впечатление, что мы не используем данные в полной мере во время обучения, когда мы просто оставляем набор проверки в ожидании до самых последних этапов улучшения нашей модели, прежде чем попробовать модель на тестовых данных. Что, если бы существовал способ иметь только наборы для обучения и тестирования, но при этом иметь возможность оценивать модель на невидимых комбинациях наборов? Оказывается, перекрестная проверка — это наше решение! Короче говоря, перекрестная проверка разбивает ваши данные на k сгибов, где каждый сгиб содержит случайное подмножество обучения и тестирования. Затем перекрестная проверка обучает модель на каждом наборе обучающих данных и возвращает оценку для этих тестовых данных. Приведенный ниже фрагмент кода является частью замечательной книги Практическое машинное обучение с помощью Scikit-Learn, Keras и Tensorflow, и я призываю вас прочитать ее, как это делал я, чтобы узнать все подробности машинного обучения Python. Чтобы просмотреть код из этой книги, посетите этот GitHub: https://github.com/ageron/handson ml2/blob/master/02_end_to_end_machine_learning_project.ipynb.
lin_scores = cross_val_score(lin_reg, housing_prepared, housing_labels, scoring="neg_mean_squared_error", cv=10) lin_rmse_scores = np.sqrt(-lin_scores) display_scores(lin_rmse_scores) def display_scores(scores): print("Scores:", scores) print("Mean:", scores.mean()) print("Standard deviation:", scores.std()) display_scores(tree_rmse_scores)
Сегмент кода использует cross_val_score для разделения данных на 10 групп, каждая из которых содержит обучающие и тестовые подмножества из вышележащего обучающего набора Housing_prepared и перекрывающего тестового набора Housing_labels. Затем функция display_scores используется для вывода оценки для каждой складки и среднего значения + стандартное отклонение для всех 10 сгибов.
Я надеюсь, что эти три важные концепции помогут вам улучшить ваши сквозные проекты машинного обучения. Спасибо за прочтение!