为什么 LightGBM Python-package 给出错误的预测用于回归任务?
Why LightGBM Python-package gives bad prediction using for regression task?
我有一个样本时间序列 dataset (23, 208), which is a pivot table count for 24hrs count for some users; I was experimenting with different regressors from sklearn which work fine (except for SGDRegressor()), but this LightGBM Python-package 给我非常线性的预测如下:
我试过的代码:
import pandas as pd
dff = pd.read_csv('ex_data2.csv',sep=',')
dff.set_index("timestamp",inplace=True)
print(dff.shape)
from sklearn.model_selection import train_test_split
trainingSetf, testSetf = train_test_split(dff,
#target_attribute,
test_size=0.2,
random_state=42,
#stratify=y,
shuffle=False)
import lightgbm as lgb
from sklearn.multioutput import MultiOutputRegressor
username = 'MMC_HEC_LVP' # select one column for plotting & check regression performance
user_list = []
for column in dff.columns:
user_list.append(column)
index = user_list.index(username)
X_trainf = trainingSetf.iloc[:,:].values
y_trainf = trainingSetf.iloc[:,:].values
X_testf = testSetf.iloc[:,:].values
y_testf = testSetf.iloc[:,:].values
test_set_copy = y_testf.copy()
model_LGBMRegressor = MultiOutputRegressor(lgb.LGBMRegressor()).fit(X_trainf, y_trainf)
pred_LGBMRegressor = model_LGBMRegressor.predict(X_testf)
test_set_copy[:,[index]] = pred_LGBMRegressor[:,[index]]
#plot the results for selected user/column
import matplotlib.pyplot as plt
plt.style.use("fivethirtyeight")
plt.figure(figsize=(12, 10))
plt.xlabel("Date")
plt.ylabel("Values")
plt.title(f"{username} Plot")
plt.plot(trainingSetf.iloc[:,[index]],label='trainingSet')
plt.plot(testSetf.iloc[:,[index]],"--",label='testSet')
plt.plot(test_set_copy[:,[index]],'b--',label='RF_predict')
plt.legend()
所以我缺少的是如果我使用默认(超)参数?
简答
您的数据集的行数非常少,LightGBM 的参数设置了默认值以在 medium-sized 数据集上提供良好的性能。
设置以下参数以强制 LightGBM 适应提供的数据。
min_data_in_bin
= 1
min_data_in_leaf
= 1
长答案
在训练之前,LightGBM 对输入数据做了一些pre-processing。
例如:
- 捆绑稀疏特征
- 将连续特征合并到直方图中
- 删除保证没有信息的特征(例如,不变的特征)
该预处理的结果是一个 LightGBM Dataset
对象,运行 该预处理称为 Dataset
“构造”。 LightGBM 对此 Dataset
对象执行提升,而不是像 numpy
数组或 pandas
数据帧这样的原始数据。
为了加快构建速度并防止训练过程中的过度拟合,LightGBM 提供了防止创建太小的直方图箱 (min_data_in_bin
) 或产生与太少记录匹配的叶节点的拆分 (min_data_in_leaf
).
在小型数据集上进行训练可能需要将这些参数设置为非常低的值。
我创建了以下 minimal, reproducible example,使用 Python 3.8.12、lightgbm==3.3.2
、numpy==1.22.2
和 scikit-learn==1.0.2
演示了此行为。
from lightgbm import LGBMRegressor
from sklearn.metrics import r2_score
from sklearn.datasets import make_regression
# 20-row input data
X, y = make_regression(
n_samples=20,
n_informative=5,
n_features=5,
random_state=708
)
# training produces 0 trees, and predicts mean(y)
reg = LGBMRegressor(
num_boost_round=20,
verbosity=0
)
reg.fit(X, y)
print(f"r2 (defaults): {r2_score(y, reg.predict(X))}")
# 0.000
# training fits and predicts well
reg = LGBMRegressor(
min_data_in_bin=1,
min_data_in_leaf=1,
num_boost_round=20,
verbosity=0
)
reg.fit(X, y)
print(f"r2 (small min_data): {r2_score(y, reg.predict(X))}")
# 0.985
如果您在原始 post 的代码中使用 LGBMRegressor(min_data_in_bin=1, min_data_in_leaf=1)
,您将看到更适合所提供数据的预测。
我有一个样本时间序列 dataset (23, 208), which is a pivot table count for 24hrs count for some users; I was experimenting with different regressors from sklearn which work fine (except for SGDRegressor()), but this LightGBM Python-package 给我非常线性的预测如下:
import pandas as pd
dff = pd.read_csv('ex_data2.csv',sep=',')
dff.set_index("timestamp",inplace=True)
print(dff.shape)
from sklearn.model_selection import train_test_split
trainingSetf, testSetf = train_test_split(dff,
#target_attribute,
test_size=0.2,
random_state=42,
#stratify=y,
shuffle=False)
import lightgbm as lgb
from sklearn.multioutput import MultiOutputRegressor
username = 'MMC_HEC_LVP' # select one column for plotting & check regression performance
user_list = []
for column in dff.columns:
user_list.append(column)
index = user_list.index(username)
X_trainf = trainingSetf.iloc[:,:].values
y_trainf = trainingSetf.iloc[:,:].values
X_testf = testSetf.iloc[:,:].values
y_testf = testSetf.iloc[:,:].values
test_set_copy = y_testf.copy()
model_LGBMRegressor = MultiOutputRegressor(lgb.LGBMRegressor()).fit(X_trainf, y_trainf)
pred_LGBMRegressor = model_LGBMRegressor.predict(X_testf)
test_set_copy[:,[index]] = pred_LGBMRegressor[:,[index]]
#plot the results for selected user/column
import matplotlib.pyplot as plt
plt.style.use("fivethirtyeight")
plt.figure(figsize=(12, 10))
plt.xlabel("Date")
plt.ylabel("Values")
plt.title(f"{username} Plot")
plt.plot(trainingSetf.iloc[:,[index]],label='trainingSet')
plt.plot(testSetf.iloc[:,[index]],"--",label='testSet')
plt.plot(test_set_copy[:,[index]],'b--',label='RF_predict')
plt.legend()
所以我缺少的是如果我使用默认(超)参数?
简答
您的数据集的行数非常少,LightGBM 的参数设置了默认值以在 medium-sized 数据集上提供良好的性能。
设置以下参数以强制 LightGBM 适应提供的数据。
min_data_in_bin
= 1min_data_in_leaf
= 1
长答案
在训练之前,LightGBM 对输入数据做了一些pre-processing。
例如:
- 捆绑稀疏特征
- 将连续特征合并到直方图中
- 删除保证没有信息的特征(例如,不变的特征)
该预处理的结果是一个 LightGBM Dataset
对象,运行 该预处理称为 Dataset
“构造”。 LightGBM 对此 Dataset
对象执行提升,而不是像 numpy
数组或 pandas
数据帧这样的原始数据。
为了加快构建速度并防止训练过程中的过度拟合,LightGBM 提供了防止创建太小的直方图箱 (min_data_in_bin
) 或产生与太少记录匹配的叶节点的拆分 (min_data_in_leaf
).
在小型数据集上进行训练可能需要将这些参数设置为非常低的值。
我创建了以下 minimal, reproducible example,使用 Python 3.8.12、lightgbm==3.3.2
、numpy==1.22.2
和 scikit-learn==1.0.2
演示了此行为。
from lightgbm import LGBMRegressor
from sklearn.metrics import r2_score
from sklearn.datasets import make_regression
# 20-row input data
X, y = make_regression(
n_samples=20,
n_informative=5,
n_features=5,
random_state=708
)
# training produces 0 trees, and predicts mean(y)
reg = LGBMRegressor(
num_boost_round=20,
verbosity=0
)
reg.fit(X, y)
print(f"r2 (defaults): {r2_score(y, reg.predict(X))}")
# 0.000
# training fits and predicts well
reg = LGBMRegressor(
min_data_in_bin=1,
min_data_in_leaf=1,
num_boost_round=20,
verbosity=0
)
reg.fit(X, y)
print(f"r2 (small min_data): {r2_score(y, reg.predict(X))}")
# 0.985
如果您在原始 post 的代码中使用 LGBMRegressor(min_data_in_bin=1, min_data_in_leaf=1)
,您将看到更适合所提供数据的预测。