Прогноз времени с TPOT
Автоматизируйте конвейер машинного обучения, найдите наиболее эффективную модель машинного обучения
Мой коллега по работе порекомендовал мне несколько замечательных библиотек машинного обучения, и некоторые из них были для меня новыми. Поэтому я решил попробовать их по очереди. Сегодня очередь TPOT.
Набор данных был о прогнозировании инженеров Daimler скорости системы тестирования автомобилей Mercedes-Benz, цель состоит в том, чтобы сократить время, которое автомобили тратят на тестирование, с более чем тремя сотнями функций. Честно говоря, у меня мало или совсем нет опыта в автомобильной промышленности. Тем не менее, я постараюсь делать самые точные прогнозы, используя TPOT, инструмент автоматизированного машинного обучения Python, который оптимизирует конвейеры машинного обучения с использованием генетического программирования.
Данные
Этот набор данных содержит анонимный набор переменных, каждая из которых представляет собой особенность автомобиля Mercedes.
Целевая функция помечена буквой y и представляет время (в секундах), которое потребовалось автомобилю, чтобы пройти тестирование для каждой переменной. Набор данных можно найти здесь.
train = pd.read_csv('mer_train.csv') print('Train shape: ', train.shape)
Мы знаем, какие у нас проблемы: слишком много функций (столбцов) и недостаточно строк.
Кроме того, мы не знаем, что это за функции, кроме «y» и «ID».
Целевая особенность
Целевая характеристика «y» - это время (в секундах), которое потребовалось автомобилю для прохождения тестирования по каждой переменной. Посмотрим на его распространение.
plt.figure(figsize = (10, 6)) n, bins, patches = plt.hist(train['y'], 50, facecolor='blue', alpha=0.75) plt.xlabel('y value in seconds') plt.ylabel('count') plt.title('Histogram of y value') plt.show();
train['y'].describe()
plt.figure(figsize = (10, 6)) plt.scatter(range(train.shape[0]), np.sort(train['y'].values)) plt.xlabel('index') plt.ylabel('y') plt.title("Time Distribution") plt.show();
Есть один выброс - максимальное время в 265 секунд.
Особенности исследования
cols = [c for c in train.columns if 'X' in c] print('Number of features except ID and target feature: {}'.format(len(cols))) print('Feature types :') train[cols].dtypes.value_counts()
Из всех функций у нас есть 8 категориальных функций и 368 целочисленных функций. А как насчет количества элементов? Следующие идеи и сценарии были от Mikel Bober Irizar.
counts = [[], [], []] for c in cols: typ = train[c].dtypes uniq = len(train[c].unique()) if uniq == 1: counts[0].append(c) elif uniq == 2 and typ == np.int64: counts[1].append(c) else: counts[2].append(c) print('Constant features: {} Binary features: {} Categorical features: {}\n'.format(*[len(c) for c in counts])) print('Constant features: ', counts[0]) print() print('Categorical features: ', counts[2])
Было 12 функций, в которых содержалось только одно значение (0), они бесполезны для контролируемых алгоритмов, и мы откажемся от них позже.
Остальная часть нашего набора данных состоит из 356 двоичных функций и 8 категориальных функций. Давайте сначала рассмотрим категориальные особенности.
Категориальные особенности
for cat in ['X0', 'X1', 'X2', 'X3', 'X4', 'X5', 'X6', 'X8']: print("Number of levels in category '{0}': \b {1:2}".format(cat, train[cat].nunique()))
Функция X0
sort_X0 = train.groupby('X0').size()\ .sort_values(ascending=False)\ .index plt.figure(figsize=(12,6)) sns.countplot(x='X0', data=train, order = sort_X0) plt.xlabel('X0') plt.ylabel('Occurances') plt.title('Feature X0') sns.despine();
X0 по сравнению с целевой функцией y
sort_y = train.groupby('X0')['y']\ .median()\ .sort_values(ascending=False)\ .index plt.figure(figsize = (14, 6)) sns.boxplot(y='y', x='X0', data=train, order=sort_y) ax = plt.gca() ax.set_xticklabels(ax.get_xticklabels()) plt.title('X0 vs. y value') plt.show();
Функция X1
sort_X1 = train.groupby('X1').size()\ .sort_values(ascending=False)\ .index plt.figure(figsize=(12,6)) sns.countplot(x='X1', data=train, order = sort_X1) plt.xlabel('X1') plt.ylabel('Occurances') plt.title('Feature X1') sns.despine();
X1 и целевая функция y
sort_y = train.groupby('X1')['y']\ .median()\ .sort_values(ascending=False)\ .index plt.figure(figsize = (10, 6)) sns.boxplot(y='y', x='X1', data=train, order=sort_y) ax = plt.gca() ax.set_xticklabels(ax.get_xticklabels()) plt.title('X1 vs. y value') plt.show();
Функция X2
sort_X2 = train.groupby('X2').size()\ .sort_values(ascending=False)\ .index plt.figure(figsize=(12,6)) sns.countplot(x='X2', data=train, order = sort_X2) plt.xlabel('X2') plt.ylabel('Occurances') plt.title('Feature X2') sns.despine();
X2 и целевая функция y
sort_y = train.groupby('X2')['y']\ .median()\ .sort_values(ascending=False)\ .index plt.figure(figsize = (12, 6)) sns.boxplot(y='y', x='X2', data=train, order=sort_y) ax = plt.gca() ax.set_xticklabels(ax.get_xticklabels()) plt.title('X2 vs. y value') plt.show();
Функция X3
sort_X3 = train.groupby('X3').size()\ .sort_values(ascending=False)\ .index plt.figure(figsize=(12,6)) sns.countplot(x='X3', data=train, order = sort_X3) plt.xlabel('X3') plt.ylabel('Occurances') plt.title('Feature X3') sns.despine();
X3 и целевая функция y
sort_y = train.groupby('X3')['y']\ .median()\ .sort_values(ascending=False)\ .index plt.figure(figsize = (10, 6)) sns.boxplot(y='y', x='X3', data=train, order = sort_y) ax = plt.gca() ax.set_xticklabels(ax.get_xticklabels()) plt.title('X3 vs. y value') plt.show();
Функция X4
sort_X4 = train.groupby('X4').size()\ .sort_values(ascending=False)\ .index plt.figure(figsize=(12,6)) sns.countplot(x='X4', data=train, order = sort_X4) plt.xlabel('X4') plt.ylabel('Occurances') plt.title('Feature X4') sns.despine();
X4 и целевая функция y
sort_y = train.groupby('X4')['y']\ .median()\ .sort_values(ascending=False)\ .index plt.figure(figsize = (10, 6)) sns.boxplot(y='y', x='X4', data=train, order = sort_y) ax = plt.gca() ax.set_xticklabels(ax.get_xticklabels()) plt.title('X4 vs. y value') plt.show();
Функция X5
sort_X5 = train.groupby('X5').size()\ .sort_values(ascending=False)\ .index plt.figure(figsize=(12,6)) sns.countplot(x='X5', data=train, order = sort_X5) plt.xlabel('X5') plt.ylabel('Occurances') plt.title('Feature X5') sns.despine();
X5 и целевая функция y
sort_y = train.groupby('X5')['y']\ .median()\ .sort_values(ascending=False)\ .index plt.figure(figsize = (12, 6)) sns.boxplot(y='y', x='X5', data=train, order=sort_y) ax = plt.gca() ax.set_xticklabels(ax.get_xticklabels()) plt.title('X5 vs. y value') plt.show();
Функция X6
sort_X6 = train.groupby('X6').size()\ .sort_values(ascending=False)\ .index plt.figure(figsize=(12,6)) sns.countplot(x='X6', data=train, order = sort_X6) plt.xlabel('X6') plt.ylabel('Occurances') plt.title('Feature X6') sns.despine();
X6 и целевая функция y
sort_y = train.groupby('X6')['y']\ .median()\ .sort_values(ascending=False)\ .index plt.figure(figsize = (12, 6)) sns.boxplot(y='y', x='X6', data=train, order=sort_y) ax = plt.gca() ax.set_xticklabels(ax.get_xticklabels()) plt.title('X6 vs. y value') plt.show();
Функция X8
sort_X8 = train.groupby('X8').size()\ .sort_values(ascending=False)\ .index plt.figure(figsize=(12,6)) sns.countplot(x='X8', data=train, order = sort_X8) plt.xlabel('X8') plt.ylabel('Occurances') plt.title('Feature X8') sns.despine();
X8 и целевая функция y
sort_y = train.groupby('X8')['y']\ .median()\ .sort_values(ascending=False)\ .index plt.figure(figsize = (12, 6)) sns.boxplot(y='y', x='X8', data=train, order=sort_y) ax = plt.gca() ax.set_xticklabels(ax.get_xticklabels()) plt.title('X8 vs. y value') plt.show();
К сожалению, мы не многому научились из вышеупомянутого EDA, это жизнь. Однако мы заметили, что некоторые категориальные особенности влияют на «y», а «X0», по-видимому, оказывает наибольшее влияние.
После изучения мы собираемся закодировать уровни этих категориальных функций в виде цифр с помощью Scikit-learn MultiLabelBinarizer и рассматривать их как новые функции.
Затем мы отбрасываем закодированные константы и категориальные особенности, а также нашу целевую функцию «y».
train_new = train.drop(['y','X11', 'X93', 'X107', 'X233', 'X235', 'X268', 'X289', 'X290', 'X293', 'X297', 'X330', 'X347', 'X0', 'X1', 'X2', 'X3', 'X4', 'X5', 'X6', 'X8'], axis=1)
Затем мы добавляем закодированные функции, чтобы сформировать окончательный набор данных, который будет использоваться с TPOT.
train_new = np.hstack((train_new.values, X0_trans, X1_trans, X2_trans, X3_trans, X4_trans, X5_trans, X6_trans, X8_trans))
Окончательный набор данных имеет форму массива numpy в форме (4209, 552).
TPOT
Пришло время построить и настроить регрессор TPOT. По завершении TPOT отобразит гиперпараметры «лучшей» модели (на основе тестовых данных MSE в нашем случае), а также выведет конвейеры в виде готового к выполнению файла сценария Python для дальнейшего использования или нашего исследования.
Выполнение приведенного выше кода обнаружит конвейер как результат, который достигает 56 среднеквадратичной ошибки (MSE) на тестовом наборе:
print("TPOT cross-validation MSE") print(tpot.score(X_test, y_test))
Вы могли заметить, что MSE - отрицательное число, согласно этому потоку, это neg_mean_squared_error
для TPOTRegressor, что означает отрицательное значение среднеквадратичной ошибки. Давай попробуем еще раз.
from sklearn.metrics import mean_squared_error print('MSE:') print(mean_squared_error(y_test, tpot.predict(X_test)))
print('RMSE:') print(np.sqrt(mean_squared_error(y_test, tpot.predict(X_test))))
Итак, разница между нашим прогнозируемым временем и реальным временем составляет около 7,5 секунд. Это неплохой результат! И модель, которая дает этот результат, соответствует модели RandomForestRegressor, объединенной с алгоритмом KNeighborsRegressor в наборе данных.
Наконец, мы собираемся экспортировать этот конвейер:
tpot.export('tpot_Mercedes_testing_time_pipeline.py')
Мне понравилось изучать и использовать TPOT, надеюсь, вы такие же. Блокнот Jupyter можно найти на Github. Хороших выходных!
Ссылка: Учебник TPOT