数据集规模引发训练集与测试集得分差异的模型问题求助
我尝试使用SOAP描述符将机器学习应用于原子结构研究,目前遇到的问题是:使用不同规模的数据集时,模型的训练集与测试集得分差异极大。当前运行结果显示训练集得分远低于测试集,怀疑模型存在问题,恳请提供解决方案。使用的数据集来自论文《Dataset MoS2(single)》。
代码实现
import numpy as np import pandas as pd import matplotlib.pyplot as plt import ase from dscribe.descriptors import SOAP from dscribe.descriptors import CoulombMatrix from sklearn.model_selection import train_test_split import sklearn from sklearn.linear_model import LinearRegression from sklearn.kernel_ridge import KernelRidge from sklearn.model_selection import GridSearchCV from sklearn.svm import SVR from ase.io import read materials = read('structures.xyz', index=':') materials = materials[:5000] energies = pd.read_csv('Energy.csv') energies = np.array(energies['b']) energies = energies[:5000] species = ["H", 'Mo', 'S'] rcut = 8.0 nmax = 1 lmax = 1 # 设置SOAP描述符 soap = SOAP( species=species, periodic=False, rcut=rcut, nmax=nmax, lmax=lmax, ) coulomb_matrices = soap.create(materials, positions=[[51]]*len(materials)) nsamples, nx, ny = coulomb_matrices.shape d2_train_dataset = coulomb_matrices.reshape((nsamples,nx*ny)) df = pd.DataFrame(d2_train_dataset) df['target'] = energies from sklearn.preprocessing import StandardScaler X = df.iloc[:, 0:12].values y = df.iloc[:, 12:].values st_x = StandardScaler() st_y = StandardScaler() X = st_x.fit_transform(X) y = st_y.fit_transform(y) X_train, X_test, y_train, y_test = train_test_split(X, y) #krr = GridSearchCV( # KernelRidge(kernel="rbf", gamma=0.1), # param_grid={"alpha": [1e0, 0.1, 1e-2, 1e-3], "gamma": np.logspace(-2, 2, 5)}, #) svr = GridSearchCV( SVR(kernel="rbf", gamma=0.1), param_grid={"C": [1e0, 1e1, 1e2, 1e3], "gamma": np.logspace(-2, 2, 5)}, ) svr = svr.fit(X_train, y_train.ravel()) print("训练集得分: {:.4f}".format(svr.score(X_train, y_train))) print("测试集得分: {:.4f}".format(svr.score(X_test, y_test)))
运行得分
训练集得分: 0.0414 测试集得分: 0.9126
针对训练集得分远低于测试集的反常情况,从数据、描述子、模型三个维度给出排查和解决方向:
修正SOAP描述子的设计
当前代码仅提取每个结构中第51个原子的局部SOAP描述子,但目标是整个体系的能量,局部特征无法有效关联体系级属性,这是核心问题。建议改为计算全局SOAP描述子:对每个结构的所有原子SOAP取平均值/求和,或使用dscribe的average="inner"参数直接生成体系级平均描述子,确保特征与目标的物理意义匹配。
同时,当前nmax=1、lmax=1的参数过于简单,无法捕捉原子间复杂相互作用,建议逐步提升nmax(如3-5)和lmax(如3-4),增强描述子的表达能力。验证数据划分与一致性
单次train_test_split的结果可能存在随机性,改用K折交叉验证(如KFold配合cross_val_score)多次验证模型性能,排除偶然因素。同时确认structures.xyz与Energy.csv的样本顺序完全对应,避免数据错位;检查训练集和测试集的结构分布是否一致,必要时手动打乱数据集后再划分。调整模型参数与拟合状态
打印svr.best_params_查看网格搜索的最优参数:如果最优C值偏小(如1e0),说明模型正则化过强导致欠拟合,可扩大C的搜索范围(如1e-1到1e4),同时调整gamma的区间,让模型具备足够复杂度拟合训练数据。另外,回归任务中对y做标准化并非必须,尝试仅标准化X,观察得分变化。检查数据质量
绘制能量数据的分布直方图,排查是否存在异常值或分布极度不均的情况;统计每个结构中第51个原子的物种,确认是否存在物种不一致的情况,这会导致SOAP描述子的特征分布混乱。
内容的提问来源于stack exchange,提问作者Bereru

