Gradient boosting este un algoritm puternic de învățare automată în ansamblu pentru modelarea predictivă care poate fi aplicat pe date tabelare. Crearea de predicții cu modele precum xgboost este adesea folosită în proiectele de data science. Dar fără o bună cunoaștere a datelor în combinație cu parametrii modelului, acest lucru poate duce rapid la un model prost/supra-antrenat. Controlul parametrilor, cum ar fi „rundele de oprire timpurie”, poate fi cu siguranță de ajutor.
Parametrii pot fi reglați, iar o combinație de parametri poate duce la predicții mai precise. Căutarea în combinații de parametri se face adesea prin gridsearch-uri. Un gridsearch vine cu costuri computaționale ridicate și poate duce ușor la modele supra-antrenate, deoarece spațiul de căutare poate conține cu ușurință zeci de mii de combinații de evaluat.
Din fericire, avem modele de optimizare, cum ar fi hyperopt, care pot face munca grea folosind optimizarea bayesiană. Dar există mai mult de atât, pentru că o abordare optimizată de gridsearch poate totuși duce la modele supra-antrenate. Este înțelept să-ți împarți cu atenție datele în seturi independente de evaluare, antrenament și test, și să examinezi apoi spațiul hiperparametrilor prin validare încrucișată k-fold.
Scopul acestei biblioteci (hgboost) este de a determina cel mai robust model de gradient boosting prin evaluare pe un set independent de validare. Setul optim de parametri este determinat prin hiperoptimizare bayesiană folosind o abordare de validare încrucișată k-fold pe seturi independente de antrenament/test. hgboost poate fi aplicat pentru sarcini de clasificare, cum ar fi cele două clase sau multi-clase, și pentru sarcini de regresie folosind xgboost, catboost sau lightboost.
Scopul hgboost este de a determina cel mai robust model căutând eficient în spațiul parametrilor folosind hiperoptimizare pentru care pierderea este evaluată folosind un set de antrenament/test cu validare încrucișată k-fold. În plus, modelul optimizat final este evaluat pe un set independent de validare.
hgboost este o biblioteca python pentru optimizarea hiperparametrilor pentru xgboost, catboost și lightboost folosind validare încrucișată și evaluând rezultatele pe un set independent de validare. Există multe implementări ale gradient boosting-ului, unele folosind eficient GPU, în timp ce altele au interfețe specifice. Pentru această bibliotecă hgboost, am încorporat eXtreme Gradient Boosting xgboost, Light Gradient Boosting Machine LightGBM, și Category Gradient Boosting catboost. Am creat, de asemenea, opțiunea de a învăța un model in ansamblu.
Exemplu de implementare xgboost pentru o regresie temporara
Pentru acest exemplu am folosit in fisier (forecast3.csv) cu 3 coloane: code, ds, y. Unde code – reprezinta codul articolulul, ds – data, y – cantitatea vanduta (predictor)
Codul poate fi folosit in Google Colab.
# Instalează librăriile necesare
!pip install -U hgboost
!pip install catboost
import numpy as np
import pandas as pd
from hgboost import hgboost
import matplotlib.pyplot as plt
import seaborn as sns
from IPython.display import display # Pentru a afișa DataFrames în Colab
# --- 1. Inițializarea hgboost ---
hgb = hgboost(max_eval=50, threshold=0.5, cv=5, test_size=0.2, val_size=0.2, top_cv_evals=10, random_state=None, verbose=3)
# --- 2. Încărcarea și Pregătirea Datelor pentru Antrenament ---
df_train_initial = pd.read_csv('forecast3.csv') # Load raw data
# Converteste coloana 'ds' la datetime pentru extragerea caracteristicilor
df_train_initial['ds'] = pd.to_datetime(df_train_initial['ds'], format='%d/%m/%Y')
# Extrage caracteristici generalizabile de dată (an, luna, zi, ziua saptamanii)
df_train_initial['year'] = df_train_initial['ds'].dt.year
df_train_initial['month'] = df_train_initial['ds'].dt.month
df_train_initial['day'] = df_train_initial['ds'].dt.day
df_train_initial['dayofweek'] = df_train_initial['ds'].dt.dayofweek
# Curăță coloana 'code' de valori non-numerice și apoi convertește la int
df_train_initial = df_train_initial[df_train_initial['code'].apply(lambda x: str(x).isdigit())]
df_train_initial['code'] = df_train_initial['code'].astype(int)
# Convert 'y' to numeric, handling commas and errors
df_train_initial['y_original_sales'] = df_train_initial['y'].astype(str).str.replace(',', '').astype(float)
# Identifică și filtrează rândurile unde 'y_original_sales' nu este NaN
I = ~np.isnan(df_train_initial['y_original_sales'])
df_train_filtered = df_train_initial.loc[I, :].copy()
# Salveaza informatia originala in 'y' pentru comparatii istorice
y_original_for_historical = df_train_filtered['y_original_sales'].values
# Ensure y contains only non-negative values before log transformation
y_original_for_historical[y_original_for_historical < 0] = 0
# This is the 'df_train' that subsequent cells expect (features without original 'y' and 'ds')
df_train = df_train_filtered.drop(['y', 'ds', 'y_original_sales'], axis=1)
# Pregateste y pentru model training (log1p transformation)
y_for_model_training = np.log1p(y_original_for_historical) # Use the preserved 'y' for transformation
# X for model training is the preserved 'df_train'
X_for_model_training = df_train.copy()
print("Antrenarea modelului XGBoost...")
# --- 3. Antrenarea Modelului ---
results = hgb.xgboost_reg(X_for_model_training, y_for_model_training)
print("Antrenare finalizată.")
# --- 4. Pregătirea Datelor pentru Predicții Viitoare --- (ex: cod = 919010017, interval predictie: Aprilie 2026)
# @param target_cod {type: "number"}
target_cod = 919010017 #@param
# @param start_date {type: "string"}
start_date = '2026-04-01' #@param
# @param end_date {type: "string"}
end_date = '2026-05-30' #@param
# Convert start_date to datetime to extract the prediction month and year
prediction_start_dt = pd.to_datetime(start_date)
prediction_month = prediction_start_dt.month
prediction_year = prediction_start_dt.year
prediction_month_name = prediction_start_dt.strftime('%B') # e.g., 'April'
date_range = pd.date_range(start=start_date, end=end_date, freq='D')
df_predict = pd.DataFrame({
'code': [target_cod] * len(date_range),
'ds': date_range
})
df_predict['year'] = df_predict['ds'].dt.year
df_predict['month'] = df_predict['ds'].dt.month
df_predict['day'] = df_predict['ds'].dt.day
df_predict['dayofweek'] = df_predict['ds'].dt.dayofweek
X_predict = df_predict.drop('ds', axis=1).copy()
print(f"\nGenerarea predicțiilor pentru produsul {target_cod} în perioada {start_date} - {end_date}...")
# --- 5. Realizarea Predicțiilor ---
y_pred_month_log, _ = hgb.predict(X_predict) # Model predicts log-transformed values
y_pred_month = np.expm1(y_pred_month_log) # Inverse transform predictions to original scale
# Ensure non-negative predictions
y_pred_month[y_pred_month < 0] = 0
print("Predicții generate.")
# --- 6. Aplicarea filtrului rafinat pentru zilele istorice de vânzare --- (se extrage din lista de predictii zilnice, zilele cu cea mai mare probabilitate de a inregistra vanzari, pe baza istoricului de vanzare)
# Identify unique days of the prediction month with sales from historical data for the target product (across all years)
historical_sales_days_for_month = df_train_filtered[
(df_train_filtered['code'] == target_cod) &
(df_train_filtered['month'] == prediction_month)
]['day'].unique()
print(f"\nZilele istorice cu vânzări în {prediction_month_name} pentru produsul {target_cod} (toți anii): {sorted(historical_sales_days_for_month)}")
# Calculate the maximum number of distinct days with sales in any single prediction month from historical data
max_days_with_sales = 0
# Iterate through historical years present in the data
for year_val in df_train_filtered['year'].unique():
days_with_sales_in_year = df_train_filtered[
(df_train_filtered['code'] == target_cod) &
(df_train_filtered['month'] == prediction_month) &
(df_train_filtered['year'] == year_val)
]['day'].nunique()
max_days_with_sales = max(max_days_with_sales, days_with_sales_in_year)
print(f"Numărul maxim de zile distincte cu vânzări în {prediction_month_name} pentru produsul {target_cod} în oricare an istoric: {max_days_with_sales}")
# Create a copy of df_predict to store the refined filtered predictions
df_predict_refined = df_predict.copy()
df_predict_refined['predicted_y_original'] = y_pred_month # Store original predictions
# Initialize the new refined filtered prediction column to 0
df_predict_refined['predicted_y_refined_filtered'] = 0.0
# Filter the predictions to only include days that historically had sales in the prediction month for this product
# and then sort by predicted value to pick the top 'max_days_with_sales'
potential_prediction_days_for_selection = df_predict_refined[
df_predict_refined['day'].isin(historical_sales_days_for_month)
].copy()
# Sort these potential days by their predicted sales in descending order
# and select only the top 'max_days_with_sales' days
if not potential_prediction_days_for_selection.empty and max_days_with_sales > 0:
selected_top_days = potential_prediction_days_for_selection.sort_values(
by='predicted_y_original', ascending=False
).head(max_days_with_sales)
# Assign predicted values only for the selected top days
for _, row in selected_top_days.iterrows():
df_predict_refined.loc[df_predict_refined['ds'] == row['ds'], 'predicted_y_refined_filtered'] = row['predicted_y_original']
# Recalculate the total estimated quantity with the refined filtered predictions
total_estimated_quantity_refined_filtered = df_predict_refined['predicted_y_refined_filtered'].sum()
print(f"\nCantitatea totală estimată *filtrată rafinat* pentru codul {target_cod} în perioada {start_date} - {end_date} este: {total_estimated_quantity_refined_filtered:.2f}")
print("\nPredicții zilnice *filtrate rafinat* pentru luna specificată:")
display(df_predict_refined[['ds', 'day', 'predicted_y_original', 'predicted_y_refined_filtered']])
# --- 7. Graficul Predicțiilor Filtrate Rafinat ---
plt.figure(figsize=(12, 6))
sns.lineplot(x='ds', y='predicted_y_refined_filtered', data=df_predict_refined)
plt.title(f'Predicții zilnice *filtrate rafinat* de vânzări pentru produsul {target_cod} în {prediction_month_name} {prediction_year}')
plt.xlabel('Data')
plt.ylabel('Cantitate Predisă (filtrată rafinat)')
plt.grid(True, linestyle='--', alpha=0.7)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()