符号回归(Symbolic Regression)是一种有监督的机器学习方法,用于发现某种隐藏的数学表达式或函数,以最佳地拟合给定的数据集。与传统的回归方法不同,符号回归不仅仅是找到一个数学模型的参数,而是通过搜索和组合基本数学运算符和函数,自动构建出一个数学表达式。同时,符号回归也是为数不多的可解释机器学习方法。
人类的好奇心和学习能力使得我们在对一批数据做出预测后想要明白为什么会做出这种决策?得出这样的预测结果?因此在很多场景下,我们需要算法模型具有可解释性,使得我们能够快速地洞察数据之间的因果关系。符号回归的优点在于不依赖先验知识来为非线性系统建立符号模型,而是使用遗传算法、进化策略、粒子群优化等优化算法来进行搜索和优化。这些算法通过迭代地更新种群,逐步改进个体的适应度,最终找到一个最优的数学表达式。符号回归已经被用于发现新材料,设计新材料中。苏州大学尹万健等通过符号回归确定了一个简易的描述子μ/t,基于此描述子成功预测并合成一系列新型、高催化活性的钙钛矿催化剂。
相比于线性回归的只能表示线性关系,符号回归能够输出更加复杂的非线性关系(+、-、*、/、sin、cos、exp等)。然而,由于搜索空间的巨大性和计算复杂性,符号回归算法可能需要较长的时间来找到最优解,而且结果可能受到初始种群和算法参数的影响。因此,在使用符号回归时需要仔细选。择算法和参数,并进行适当的调优和验证。实现符号回归的软件或框架有:Eureqa Formulize、PySR、gplearn(gplearn是Python最成熟的符号回归算法实现)。符号回归的一般步骤如下:
-
定义问题:确定要解决的问题和目标,以及输入和输出的数据。
-
生成初始种群:创建一个初始的随机种群,其中每个个体都是一个数学表达式。
-
评估适应度:使用某种适应度函数来评估每个个体的拟合程度,将其与目标数据进行比较。
-
选择操作:根据适应度函数的结果,选择一些个体作为下一代的父代。
-
变异和交叉操作:对选定的父代进行变异和交叉操作,生成新的个体。
-
更新种群:将新生成的个体加入到种群中,替换掉一些较差的个体。
-
终止条件:根据预设的终止条件(如达到最大迭代次数或达到某个适应度阈值),判断是否终止算法。
-
输出结果:选择适应度最好的个体作为最终的数学表达式,用于预测或建模。
gplearn是一个基于遗传编程(Genetic Programming)的Python库,是最成熟的符号回归算法实现。用于自动发现和构建数学模型。它提供了一种使用遗传算法来优化数学表达式的方法,可以自动从数据中学习和构建复杂的数学模型,包括回归模型和分类模型。gplearn的主要特点和功能如下:
-
遗传编程:gplearn使用遗传编程算法来搜索和优化数学表达式。它通过随机生成和演化一组数学表达式,然后根据预定义的适应度函数对这些表达式进行评估和选择,最终找到最优的数学模型。
-
自动特征衍生:基于gplearn的SymbolicTransformer类可用于特征衍生
-
多种适应度函数:gplearn支持多种适应度函数,包括均方误差(Mean Squared Error)、对数损失(Log Loss)等。用户可以根据具体的问题选择适合的适应度函数来评估和选择数学表达式。
-
可解释性:gplearn生成的数学模型通常具有很好的可解释性,可以通过查看生成的数学表达式来理解模型的工作原理和特征的重要性。
-
灵活性:gplearn提供了丰富的配置选项和参数,可以根据具体的需求进行定制和调整。用户可以控制遗传编程的参数、终止条件、交叉和变异操作等,以获得最佳的结果。
-
高性能:gplearn支持并行计算和多核处理,可以加速遗传编程的过程。
gplearn是一个强大的工具,可以应用于各种机器学习和数据挖掘任务,如回归分析、分类问题、特征选择等。它提供了简单易用的API和丰富的功能,使得使用遗传编程来构建数学模型变得更加容易和高效。
est_gp = SymbolicRegressor(
population_size=5000, #人口数,默认1000,每一代公式个数
generations=20, #迭代几次,默认20
tournament_size, #竞争个数,规模
stopping_criteria=0.01, #终止条件,提前终止需要达到的指标
const_range, #公式中常数项的范围(-1,1),元组,None则无常数
init_depth, #初代树的深度,默认(2,6)
init_method, #初始化方法
function_set,#运算符集
metric,#评估指标
parsimony_coefficient,#精简系数,复杂度惩罚系数
p_crossover=0.7, #进行交叉变异的概率
p_subtree_mutation=0.1,#子树变异的概率
p_hoist_mutation=0.05, #提升变异的概率
p_point_mutation=0.1,#点变异概率
p_point_replace,#点变异时,每个节点变异的概率
max_samples=0.9, # 评估样本的比例
feature_names,#特征名称
n_jobs,#并行计算
verbose=1,#记录过程
random_state=0 #随机数种子)
import pandas as pd
df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/housing/housing.data', header=None, sep='\s+')
df.columns = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
sc = preprocessing.MinMaxScaler()
data = df.iloc[:,:-1]
target = df.iloc[:,-1]
data = sc.fit_transform(data)
train_x,valid_x,train_y,valid_y = train_test_split(data,target,test_size=0.2,random_state=2023)
from gplearn.genetic import SymbolicTransformer,SymbolicRegressor
est_gp = SymbolicRegressor(population_size=5000,
generations=20, stopping_criteria=0.01,
p_crossover=0.7, p_subtree_mutation=0.1,
p_hoist_mutation=0.05, p_point_mutation=0.1,
max_samples=0.9, verbose=1,
parsimony_coefficient=0.01, random_state=0)
est_gp.fit(train_x, train_y)
print(est_gp.score(valid_x,valid_y)) #0.5967867578111098
print(est_gp._program) # sub(div(X5, 0.022), mul(add(mul(X10, X4), sub(X5, 0.502)), sub(div(X10, X12), add(div(mul(add(X5, X5), mul(X12, X10)), sub(0.479, 0.502)), sub(div(X11, X12), sub(0.479, 0.502))))))
import graphviz
dot_data = est_gp._program.export_graphviz()
graph = graphviz.Source(dot_data)
graph
SymbolicTransformer可以将原始特征转换为符号特征,这些符号特征是通过演化生成的数学表达式来表示的。这些数学表达式可以包含各种数学运算符、函数和变量,从而捕捉到原始特征之间的非线性关系。SymbolicTransformer可用于特征生成
function_set = ['add', 'sub', 'mul', 'div',
'sqrt', 'log', 'abs', 'neg', 'inv',
'max', 'min']
gp = SymbolicTransformer(
generations=20,
population_size=2000,
hall_of_fame=100,#竞争的个数
n_components=10,#生成特征的个数
function_set=function_set,#运算符号集合
parsimony_coefficient=0.0005,#惩罚系数
max_samples=0.9,
verbose=1,
random_state=0,
n_jobs=3
)
from sklearn.linear_model import Ridge
est = Ridge()
est.fit(train_x, train_y)
print(est.score(valid_x,valid_y)) # 0.7756452565215287
function_set = ['add', 'sub', 'mul', 'div',
'sqrt', 'log', 'abs', 'neg', 'inv',
'max', 'min']
gp = SymbolicTransformer(generations=20, population_size=2000,
hall_of_fame=100, n_components=10,
function_set=function_set,
parsimony_coefficient=0.0005,
max_samples=0.9, verbose=1,
random_state=0, n_jobs=3)
gp.fit(train_x, train_y)
import numpy as np
# 新特征与原始特征组合
gp_features = gp.transform(data)
new_diabetes = np.hstack((data, gp_features))
print(new_diabetes) # 14个特征扩展到22个特征
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
train_x,valid_x,train_y,valid_y = train_test_split(new_diabetes,target,test_size=0.2,random_state=2023)
est = Ridge()
est.fit(train_x, train_y)
print(est.score(valid_x,valid_y)) # 0.88
本期,我们介绍基于gplearn的符号回归算法基本原理及应用。当然gplearn不仅可以实现分类算法也可以实现回归算法,同时SymbolicTransformer还可以实现新特征的生成。基于gplearn的符号回归是为数不多的可解释机器学习算法,而且可以用于特征衍生。
更多内容:参考订阅号:数道
参考:
【1】http://advances.sciencemag.org/content/5/2/eaav0693
【2】https://gplearn.readthedocs.io/en/stable/examples.html
【3】https://www.bilibili.com/video/BV16j411T7gJ?p=8&spm_id_from=pageDriver&vd_source=12e876d9321bec4269ae1f826cf80ada