DataWhale AI夏令营——机器学习
- 学习记录一
- 1. 异常值分析
- 2. 单变量箱线图可视化
- 3. 特征重要性分析
- 学习记录2 (2023.07.27更新)
- 1. 数据层面
- 2. 特征工程
- 3. 数据划分方式
- 4. 后处理
学习记录一
锂电池电池生产参数调控及生产温度预测挑战赛
已配置环境,跑通baseline,并在此基础上对数据进行了简单的分析。
1. 异常值分析
对训练集中的缺失值和异常值进行分析
train_data.info()
train_data.describe()
观察到数据中不存在缺失值,存在异常值train_dataset['下部温度9'] == -32768.000000]
。删除该缺失值。
train_dataset.drop(train_dataset[train_dataset['下部温度9'] == -32768.000000].index).reset_index(drop=True)
2. 单变量箱线图可视化
对训练集和测试集中的流量、上部设定温度和下部设定温度的数据分布进行了箱线图可视化
观察到上部和下部温度设定数据中存在一些异常值,对应数据中2023/1/7、2023/1/8,2023/1/9 三日的数据。
在Baseline(6.29551)基础上进行了两处改动:
- 删除了数据中存在的一处错误值(6.72811)
- 删除2023/1/7、2023/1/8,2023/1/9 三日的数据(6.73844)
3. 特征重要性分析
接着尝试了分析对于单个预测变量的有效特征分析
- 计算相关性矩阵
df = pd.concat([X, y.iloc[:,0]], axis = 1) # X是处理后的训练数据,y是标签
corr_matrix = df.corr()
corr_matrix['上部温度1'].sort_values(ascending=False)
- 对于
lightgbm
的特征重要性
feature_importance = model.feature_importance()
sorted_features = sorted(zip(X.columns, feature_importance), key=lambda x: x[1], reverse=True)
# 打印按照feature_importance值降序排列的特征列表
for feature, importance in sorted_features:
print(f"{feature}: {importance}")
相关性矩阵计算的是线性相关性,所以结果观察到和lightgbm的特征重要性的结果是有些不同的。
下一步打算在针对每个预测输出的结果构建衍生不同的特征并进行特征筛选。
学习记录2 (2023.07.27更新)
这几天主要是和Baseline的斗争,然后全部失败。从数据层面,特征工程,数据划分方式,后处理都做了尝试。
1. 数据层面
之前上一次发现的数据中存在缺失值(为0)和异常值,采用了查找筛选出然后改动。而最近通过可视化发现,几乎每个特征都存在异常值。尤其体现在流量特征中。
上图是17个流量特征在训练数据中的折线图,可以看到还是有很大的波动。
通过利用中位数进行滑动窗口滤波后得到的结果,其中红色曲线是测试集滤波后的结果。
滤波采用的代码:
def smooth_t(df, cols):
df = df.copy()
window_size = 5
for col in cols:
df[f'smoothed_{col}'] = df[col].rolling(window=window_size, center=True).median()
outlier_threshold = 5.0
df['absolute_diff'] = abs(df[col] - df[f'smoothed_{col}'])
outliers = df['absolute_diff'] > outlier_threshold
df.loc[outliers, col] = df.loc[outliers, f'smoothed_{col}']
df.drop(columns=[f'smoothed_{col}', 'absolute_diff'], inplace=True)
return df
结果:滤波后的数据在测试集上MAE并没有减少。
2. 特征工程
主要从三个方面进行:
- 流量特征:构造了一定时间范围内(一天中)的方差、均值和变异系数。其中变异系数表现较好,在树模型的特征重要性中得分高于原始的流量特征,但用该特征训练后在测试集上的表现并没有更好,该怎样保留和删除特征仍有些疑惑。
- 温度设定特征:这些特征在corr相关性中和target的线性相关性较强,但在树模型的特征重要性评价中表现很差,而且值比较平稳,不容易构建衍生特征。我尝试了构建成离散特征,分别用最多的n 个值代替所有值,同时用1,0,-1构建其前后的变化。但这些特征表现都很差。
- 接着尝试了使用全自动特征生成器openFE。效果也一般。
from openfe import OpenFE, transform, tree_to_formula
ofe = OpenFE()
features = ofe.fit(data = train_x, label = train_y, n_jobs=12) # n_jobs:指定CPU内核数
train_x_feature, test_dataset_feture = transform(train_x, test_x, features[:20], n_jobs = 12)
# 查看前20个高分特征
for feature in ofe.new_features_list[:20]:
print(tree_to_formula(feature))
3. 数据划分方式
因为是时间序列数据,直接使用train_test_split
有穿越,所以使用了针对时序数据的TimeSeriesSplit
,效果很差,使用了KFold
表现也不如train_test_split
。
4. 后处理
- Hillclimbing库 —— 用于模型融合
找到的一个用于模型融合的库,但因为目前只用了lightgbm,所以还未尝试。
!pip install hillclimbers
from hillclimbers import climb, partial
def climb_hill(
train=None,
oof_pred_df=None,
test_pred_df=None,
target=None,
objective=None,
eval_metric=None,
negative_weights=False,
precision=0.01,
plot_hill=True,
plot_hist=False
) -> np.ndarray: # Returns test predictions resulting from hill climbing
- 后处理技巧
发现的一个有意思的处理技巧,但在这个数据集上不适用,但借鉴这个思路我用来构建了温度设定特征的离散编码,虽然效果也很差。
# 1. 存储target唯一值
unique_targets = np.unique(trian['yield'])
# 2. 完成对训练和测试数据的预测
off_preds = model.prdict(X_val[features])
test_preds += model.predict(test[features]) / n_splits
# 四舍五入到最接近的唯一目标值
off_preds = [min(unique_targets, key = lambda x: abs(x-pred)) for pred in oof_preds]
test_preds = [min(unique_targets, key = lambda x: abs(x-pred)) for pred in test_preds]