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

1. Введение

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

2. Мотивация: работа с табличными данными

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

3. Обзор общего конвейера машинного обучения

Ниже приведен код универсального конвейера машинного обучения:

# from sklearn.datasets import load_boston
import pandas as pd
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split, GridSearchCV
import lightgbm as lgb
from sklearn.metrics import mean_squared_error, r2_score
import joblib
# the California housing dataset
from sklearn.datasets import fetch_california_housing
# the Ames housing dataset
from sklearn.datasets import fetch_openml

# data = fetch_california_housing()
data = fetch_openml(name="house_prices", as_frame=True)

# data = load_boston()
filename = 'ames_housing.csv'
df = pd.DataFrame(data.data, columns=data.feature_names)
df['label'] = data.target
# first time save data on disk to avoid downloading again
# df.to_csv(filename, index=False)

# 1. Data Loading
# df = pd.read_csv(filename)

# 2. Data Exploration
print(df.describe())
print(df.isnull().sum())
print(df.head())
#
# 3. Data Preprocessing

# Identify numeric and categorical columns
print(len(df.columns))
numeric_features = df.select_dtypes(include=['int64', 'float64']).columns.tolist()
categorical_features = df.select_dtypes(exclude=['int64', 'float64']).columns.tolist()
print(len(categorical_features))
print(categorical_features[:5])
numeric_features.remove('label')  # Assuming target column is numeric
print(len(numeric_features))
print(numeric_features[:5])

# Transformers
numeric_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='mean')),
    ('scaler', StandardScaler())
])

categorical_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
    ('onehot', OneHotEncoder(handle_unknown='ignore'))
])

preprocessor = ColumnTransformer(
    transformers=[
        ('num', numeric_transformer, numeric_features),
        ('cat', categorical_transformer, categorical_features)
    ])

# 4. Train-Test Split
X = df.drop('label', axis=1)
y = df['label']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 5. Feature Selection using RandomForestRegressor
# Note: For simplicity, we'll apply the transformer and then the regressor sequentially, though you could use a pipeline.
X_train_transformed = preprocessor.fit_transform(X_train)
X_test_transformed = preprocessor.transform(X_test)

rf = RandomForestRegressor(n_estimators=100)
rf.fit(X_train_transformed, y_train)

# explicit feature importance extraction here
# the one-hot encoding complicates direct column referencing.
# Getting feature importances and corresponding names
feature_importances = rf.feature_importances_
print(feature_importances)

# Get feature names from the preprocessor
# For one-hot encoded columns, it'll add more complexity due to multiple columns being added for one categorical feature
onehot_columns = list(preprocessor.named_transformers_['cat'].named_steps['onehot'].get_feature_names_out(input_features=categorical_features))
print(onehot_columns)
all_features = numeric_features + onehot_columns

# Get the top 20 features' indices
sorted_idx = feature_importances.argsort()[-20:][::-1]
print(sorted_idx)
# Subset the data for the top features
X_train_transformed_top = X_train_transformed[:, sorted_idx]
X_test_transformed_top = X_test_transformed[:, sorted_idx]

# 6. Model Building using LightGBM
# Preparing the dataset for LightGBM
d_train = lgb.Dataset(X_train_transformed_top, label=y_train)

params = {
    'objective': 'regression',
    'metric': 'rmse'
}

lgbm = lgb.train(params, d_train, 100)

# 7. Hyperparameter Tuning using GridSearchCV
lgbm_regressor = lgb.LGBMRegressor()
param_grid = {
    'learning_rate': [0.01, 0.05, 0.1],
    'n_estimators': [20, 40, 60],
    'num_leaves': [31, 61]
}

grid_search = GridSearchCV(lgbm_regressor, param_grid, cv=5, n_jobs=-1, scoring='neg_mean_squared_error')
grid_search.fit(X_train_transformed_top, y_train)

best_lgbm_model = grid_search.best_estimator_

# 8. Model Evaluation
y_pred = best_lgbm_model.predict(X_test_transformed_top)
mse = mean_squared_error(y_test, y_pred)
print(f"Mean Squared Error: {mse}")

r2 = r2_score(y_test, y_pred)
print(f"R^2 Score: {r2}")

# 9. Model Saving
joblib.dump(best_lgbm_model, 'best_lgbm_model.pkl')

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

Загрузка данных. Получает набор данных из источника, который в нашем примере содержит данные.
Исследование данных: углубляется в набор данных, извлекая информацию и понимание. свои нюансы.
Предварительная обработка данных: подготавливает данные для моделирования, обрабатывая отсутствующие значения, выбросы и т. д.
Выбор функций: использует такие методы, как RandomForestRegressor. чтобы точно определить важные функции.
Построение модели: строит прогностическую модель. Хотя я использовал алгоритм LightGBM для прогнозирования цен на жилье, структура может работать с любой моделью.
Настройка гиперпараметров: совершенствует параметры модели для достижения максимальной производительности.
>Оценка модели: оценивает, насколько хорошо работает модель.
Сохранение модели: гарантирует, что усилия не будут потрачены впустую, сохраняя модель для будущего использования.

4. Адаптация пайплайна к другим задачам прогнозирования

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

5. Вывод

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