from pymatgen import Composition, Element
import pandas as pd
import urllib.request
import numpy as np
from sklearn.model_selection import train_test_split
import lightgbm as lgb
from sklearn import datasets
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
from sklearn import datasets
from bayes_opt import BayesianOptimization
#文件获取地址
url = 'https://raw.githubusercontent.com/onecoinbuybus/Database_chemoinformatics/master/bondgap_database.csv'
urllib.request.urlretrieve(url, 'bondgap_database.csv')
#获取文件
trainFile = pd.read_csv('bondgap_database.csv', sep=',', header=None)
trainFile.columns = ['formula', 'bondgap']
#数据集是二元系的无机分子式以及能隙数据一共4096个。
print(trainFile.shape) #(4096, 2)
print(trainFile.head())
#之后我们把它丢给pymatgen,这里的处理有点类似于将有机分子转化成mol文件的过程。
form=trainFile['formula']
#将化学式拆分
materials=list(map(lambda x: Composition(x), form))
print(materials)
#下面是计算描述子的函数
#这里使用了这么几个描述子,
# atomic_number:第一个和第二个原子的原子序数,
# electronegativity是电负性,element_group是周期。
# 最后还有fraction,这里我用sort让一个分子式里的原子数量按照从大到小配比然后求一个比例值。
# 就这么几个简单的东西作为X来预测y能隙。
def mat_descriptor_calculation(material):
#将化学式拆分
mat=Composition(material)
#lambda x: mat.get_atomic_fraction(x), mat mat为lambda x中x的参数
#mat.get_atomic_fraction(x) x为mat中的元素,获取该元素在化学式中的成分比
fraction_list=list(map(lambda x: mat.get_atomic_fraction(x), mat))
#降序
sort_frac=fraction_list.sort(reverse=True)
if sort_frac is not None:
fraction=sort_frac[0]/sort_frac[1]
else:
fraction=1
#原子叙述
atomic_number=list(map(lambda x: x.Z, mat))
#电负性
electronegativity=list(map(lambda x: x.X, mat))
#周期
element_group=list(map(lambda x: x.group, mat))
#将上述相加
descriptor=atomic_number+electronegativity+element_group
#附加原子数比值
descriptor.append(fraction)
return descriptor
#将上述下载得到的数据集中元素都计算其描述子
X=np.array(list(map(lambda x: mat_descriptor_calculation(x), materials)))
#单独获取bondgap列,作为数据集结果
y=trainFile['bondgap']
#拆分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.8, random_state=369)
#这里试了lightbgm和贝叶斯优化随便选了几个参数进行调参。
#首先对参数范围,初期点数量以及迭代次数进行设定。
#num_leaves:每个树上的叶子数,树模型复杂度,默认31
#max_depth:树模型的最大深度
#n_estimators:随机森林中树的数量
#learning_rate:学习率
pbonds={
'num_leaves': (5,100),
'max_depth': (2,10),
'n_estimators': (300,700),
'learning_rate': (0.001,0.8)
}
init_points= 5
n_iter= 20
#然后调参。这里用的标准是r2。
def rfc_cv(num_leaves, max_depth, n_estimators, learning_rate, data, targets):
estimator = lgb.LGBMRegressor(
num_leaves=num_leaves,
max_depth=max_depth,
n_estimators=n_estimators,
learning_rate=learning_rate,
random_state=9527
)
cval = cross_val_score(estimator, data, targets,scoring='r2', cv=5)
return cval.mean()
def optimize_rfc(data, targets):
def rfc_crossval(num_leaves, max_depth, n_estimators, learning_rate):
return rfc_cv(
num_leaves=int(num_leaves),
max_depth=int(max_depth),
n_estimators=int(n_estimators),
learning_rate=max(min(learning_rate, 0.999), 1e-3),
data=data,
targets=targets,
)
optimizer = BayesianOptimization(
f=rfc_crossval,
pbounds=pbonds,
random_state=2234,
verbose=2
)
optimizer.maximize(n_iter=n_iter,init_points=init_points)
params=optimizer.max['params']
modify_para=list(params.values())
best_param={
'learning_rate':round(modify_para[0],3),
'max_depth':int(modify_para[1]),
'n_estimators':int(modify_para[2]),
'num_leaves':int(modify_para[3])
}
print(best_param)
print(round(optimizer.max['target'],4))
return(best_param)
optimize_rfc(X_train, y_train)
#最后使用调出来的参数代到模型然后对训练集进行预测:
best_para={'learning_rate': 0.321, 'max_depth': 5, 'n_estimators': 390, 'num_leaves': 16}
clf=lgb.LGBMRegressor(**best_para)
clf.fit(X_train,y_train)
y_pred=clf.predict(X_test)
#最后对结果进行预测:
from sklearn.metrics import r2_score
from sklearn.metrics import mean_squared_error
import math
R2 = r2_score(y_test, y_pred)
RMSE = math.sqrt(mean_squared_error(y_test, y_pred))
print('R2:{}'.format(R2))
print('RMSE:{}'.format(RMSE))
print()