在函数中使用遗传算法(局部)——最小化函数
Using genetic algorithm in a function (locally) - minimizing function
我一直在尝试使用遗传算法,以便在不同的实验中拟合我的幂律。问题是我并不真正完全理解它。我想除了 sumOfSquaredError(parameterTuple) 函数我什么都懂。
我一直在努力理解和使用的代码,它是社区中普遍共享的代码,它是由以下函数构建的:
func(x, a, b) - 适合我们实验数据的模型函数
sumOfSquaredError(parameterTuple) - 通过遗传算法最小化的函数
generate_Initial_Parameters() - 根据SciPy的遗传算法生成初始参数
然后我要做的是使用具有 pandas.DataFrame 作为输入的 main 函数。此函数 select 数据框中的特定行和列(为了获得单个实验)并对其进行处理。
我与发布的一般代码不同的是,我有这个函数和一个 pandas 数据框输入,它只不过是一个索引数据集。然后,我对其施加一些条件,以便从数据集中提取特定数据,以便每次迭代只对整个数据集进行一次实验,并尝试将其定义为 xData 和 yData。
实现
如果尝试输入 xData 和 yData:
yData = np.asarray(y_eff)
xData = np.asarray(x)
# diff_evolution completes by calling curve_fit() using param. bounds
geneticParameters = generate_Initial_Parameters(xData, yData)
为了定义sumOfSquaredError(xData, yData, parameterTuple):
# "seed" the numpy random number generator for repeatable results
result = scipy.optimize.differential_evolution(
sumOfSquaredError(xData, yData, parameterBounds),
parameterBounds, seed=3)
它returns:
文件“/home/josep/programa.py”,第 361 行,在 get_Results
遗传参数 = generate_Initial_Parameters(xData, yData)
文件“/home/josep/programa.py”,第 267 行,在 generate_Initial_Parameters
parameterBounds, seed=3)
文件“/home/josep/anaconda3/lib/python3.7/site-packages/scipy/optimize/_differentialevolution.py”,第 276 行,在 differential_evolution
ret = solver.solve()
文件“/home/josep/anaconda3/lib/python3.7/site-packages/scipy/optimize/_differentialevolution.py”,第 688 行,在求解
self.population)
文件“/home/josep/anaconda3/lib/python3.7/site-packages/scipy/optimize/_differentialevolution.py”,第 794 行,在 _calculate_population_energies
提高 RuntimeError("The map-like callable must be of the"
RuntimeError: 类似地图的可调用函数必须采用 f(func, iterable) 形式,返回与 'iterable'
长度相同的数字序列
我遇到的错误是:
- NameError: 名称 'xData' 未定义
文件“/home/josep/programa.py”,第 245 行,在 sumOfSquaredError 中
val = func(xData, *parameterTuple)
我想我在函数内部调用 sumOfSquaredError(parameterTuple) 时遇到了问题,因为这个函数使用的变量被定义为全局变量。这也可能与 scipy.optimize.differential_evolution() 有关。
如果我尝试输入 xData 和 yData 作为输入参数,那么它还会要求我输入 parameterTuple,我不明白它来自哪里 因为它没有在任何地方定义。
def sumOfSquaredError(parameterTuple):
"""
Input to the genetic algorithm.
Function for the genetic algorithm to minimize (sum of squared error).
Parameters: xData, yData, parameterTuple
----------
Returns
-------
Squared difference between experimental data and predicted data
"""
# do not print warnings by genetic algorithm
warnings.filterwarnings("ignore")
val = func(xData, *parameterTuple)
return np.sum((yData - val) ** 2.0)
我正在使用的其他功能是:
def generate_Initial_Parameters():
"""
Generate initial parameters based on SciPy's genetic algorithm.
Returns
-------
result.x is the optimization result
"""
parameterBounds = []
parameterBounds.append([0, 100.0]) # search bounds for a
parameterBounds.append([0, 100.0]) # search bounds for b
# "seed" the numpy random number generator for repeatable results
result = differential_evolution(sumOfSquaredError, parameterBounds, seed=3)
return result.x
这是我在每次迭代时输入 df 和 select 特定行的代码中调用的主要函数。 (如果有人需要的话,我也在这里写进口)
import numpy
import pandas as pd
import matplotlib.pyplot as plt
import scipy as scipy
from scipy.optimize import differential_evolution
from sklearn import linear_model
from sklearn.metrics import mean_squared_error, r2_score
import warnings
def get_Results(df):
"""
Process df.
Parameters.
----------
df : Dataframe with the data
Returns results which is a DataFrame with columns describing
regression coefficients
-------
"""
columns_results = 'Full_Name', 'Slope', 'Y-intercept', 'MSE', 'R2_score'
results = pd.DataFrame(columns=columns_results)
# Processing - Ht(%) = 0
sample_names = df['Sample'][
df['Ht(%)'] == 0].drop_duplicates()
for i in range(len(sample_names)):
df_i = df[(df['Sample'] == sample_names.values[i])
& (df['Ht(%)'] == 0.0)]
name = 'Ht(%)=' + str(df_i['Ht(%)'].values[i]) \
+ ' ' + 'Sample: ' + df_i['Sample'].values[i]
y_o = pd.DataFrame(df_i['Pressure(Pa)'].values)
x_o = pd.DataFrame(df_i['Velocity(um/s)'].values)
# Create linear regression object
regr = linear_model.LinearRegression()
# Train the model using the dataset
regr.fit(x_o, y_o) # fit(self, X, y[, sample_weight]) - Fit linear model.
# Make predictions using the estimator set
y_pred = regr.predict(x_o)
yData = numpy.asarray(y_o)
xData = numpy.asarray(x_o)
# diff_evolution completes by calling curve_fit() using param. bounds
geneticParameters = generate_Initial_Parameters()
# now call curve_fit without passing bounds from the genetic algorithm,
# just in case the best fit parameters are aoutside those bounds
fittedParameters, pcov = scipy.optimize.curve_fit(
func, xData, yData, geneticParameters)
print('Fitted parameters:', fittedParameters)
print()
modelPredictions = func(xData, *fittedParameters)
absError = modelPredictions - yData
SE = numpy.square(absError) # Squared Errors
MSE = numpy.mean(SE) # Mean Squared Errors
RMSE = numpy.sqrt(MSE) # Root Mean Squared Error, RMSE
Rsquared = 1.0 - (numpy.var(absError) / numpy.var(y_o))
print()
print('RMSE:', RMSE)
print('R-squared:', Rsquared)
# Fill up results DataFrame
df = pd.DataFrame(
[[name,
regr.coef_[0, 0], regr.intercept_[0],
mean_squared_error(y_o, y_pred),
r2_score(y_o, y_pred)]], columns=columns_results)
results = results.append(df, ignore_index=True)
return results
实现 - 解决方案
正如@jeremy_rutman 所建议的,这只是在函数内部全局定义 xData 和 yData 的问题。然而,它的问题是我定义的数组的维度不是需要的。
定义它们时正确引入的代码如下
global xData
global yData
yData = np.asarray(y_eff).reshape(len(y_eff))
xData = np.asarray(x).reshape(len(x))
(在我的例子中,问题是在全局定义时它返回:
值错误:对象对于所需数组来说太深
错误:函数调用的结果不是正确的浮点数组
)
问题可能完全是声明的问题
def sumOfSquaredError(parameterTuple):
显然应该是
def sumOfSquaredError(xdata,ydata,parameterTuple):
虽然这里似乎也没有声明使用func
。
我一直在尝试使用遗传算法,以便在不同的实验中拟合我的幂律。问题是我并不真正完全理解它。我想除了 sumOfSquaredError(parameterTuple) 函数我什么都懂。
我一直在努力理解和使用的代码,它是社区中普遍共享的代码,它是由以下函数构建的:
func(x, a, b) - 适合我们实验数据的模型函数
sumOfSquaredError(parameterTuple) - 通过遗传算法最小化的函数
generate_Initial_Parameters() - 根据SciPy的遗传算法生成初始参数
然后我要做的是使用具有 pandas.DataFrame 作为输入的 main 函数。此函数 select 数据框中的特定行和列(为了获得单个实验)并对其进行处理。
我与发布的一般代码不同的是,我有这个函数和一个 pandas 数据框输入,它只不过是一个索引数据集。然后,我对其施加一些条件,以便从数据集中提取特定数据,以便每次迭代只对整个数据集进行一次实验,并尝试将其定义为 xData 和 yData。
实现
如果尝试输入 xData 和 yData:
yData = np.asarray(y_eff)
xData = np.asarray(x)
# diff_evolution completes by calling curve_fit() using param. bounds
geneticParameters = generate_Initial_Parameters(xData, yData)
为了定义sumOfSquaredError(xData, yData, parameterTuple):
# "seed" the numpy random number generator for repeatable results
result = scipy.optimize.differential_evolution(
sumOfSquaredError(xData, yData, parameterBounds),
parameterBounds, seed=3)
它returns:
文件“/home/josep/programa.py”,第 361 行,在 get_Results 遗传参数 = generate_Initial_Parameters(xData, yData)
文件“/home/josep/programa.py”,第 267 行,在 generate_Initial_Parameters parameterBounds, seed=3)
文件“/home/josep/anaconda3/lib/python3.7/site-packages/scipy/optimize/_differentialevolution.py”,第 276 行,在 differential_evolution ret = solver.solve()
文件“/home/josep/anaconda3/lib/python3.7/site-packages/scipy/optimize/_differentialevolution.py”,第 688 行,在求解 self.population)
文件“/home/josep/anaconda3/lib/python3.7/site-packages/scipy/optimize/_differentialevolution.py”,第 794 行,在 _calculate_population_energies 提高 RuntimeError("The map-like callable must be of the"
RuntimeError: 类似地图的可调用函数必须采用 f(func, iterable) 形式,返回与 'iterable'
长度相同的数字序列我遇到的错误是:
- NameError: 名称 'xData' 未定义 文件“/home/josep/programa.py”,第 245 行,在 sumOfSquaredError 中 val = func(xData, *parameterTuple)
我想我在函数内部调用 sumOfSquaredError(parameterTuple) 时遇到了问题,因为这个函数使用的变量被定义为全局变量。这也可能与 scipy.optimize.differential_evolution() 有关。
如果我尝试输入 xData 和 yData 作为输入参数,那么它还会要求我输入 parameterTuple,我不明白它来自哪里 因为它没有在任何地方定义。
def sumOfSquaredError(parameterTuple):
"""
Input to the genetic algorithm.
Function for the genetic algorithm to minimize (sum of squared error).
Parameters: xData, yData, parameterTuple
----------
Returns
-------
Squared difference between experimental data and predicted data
"""
# do not print warnings by genetic algorithm
warnings.filterwarnings("ignore")
val = func(xData, *parameterTuple)
return np.sum((yData - val) ** 2.0)
我正在使用的其他功能是:
def generate_Initial_Parameters():
"""
Generate initial parameters based on SciPy's genetic algorithm.
Returns
-------
result.x is the optimization result
"""
parameterBounds = []
parameterBounds.append([0, 100.0]) # search bounds for a
parameterBounds.append([0, 100.0]) # search bounds for b
# "seed" the numpy random number generator for repeatable results
result = differential_evolution(sumOfSquaredError, parameterBounds, seed=3)
return result.x
这是我在每次迭代时输入 df 和 select 特定行的代码中调用的主要函数。 (如果有人需要的话,我也在这里写进口)
import numpy
import pandas as pd
import matplotlib.pyplot as plt
import scipy as scipy
from scipy.optimize import differential_evolution
from sklearn import linear_model
from sklearn.metrics import mean_squared_error, r2_score
import warnings
def get_Results(df):
"""
Process df.
Parameters.
----------
df : Dataframe with the data
Returns results which is a DataFrame with columns describing
regression coefficients
-------
"""
columns_results = 'Full_Name', 'Slope', 'Y-intercept', 'MSE', 'R2_score'
results = pd.DataFrame(columns=columns_results)
# Processing - Ht(%) = 0
sample_names = df['Sample'][
df['Ht(%)'] == 0].drop_duplicates()
for i in range(len(sample_names)):
df_i = df[(df['Sample'] == sample_names.values[i])
& (df['Ht(%)'] == 0.0)]
name = 'Ht(%)=' + str(df_i['Ht(%)'].values[i]) \
+ ' ' + 'Sample: ' + df_i['Sample'].values[i]
y_o = pd.DataFrame(df_i['Pressure(Pa)'].values)
x_o = pd.DataFrame(df_i['Velocity(um/s)'].values)
# Create linear regression object
regr = linear_model.LinearRegression()
# Train the model using the dataset
regr.fit(x_o, y_o) # fit(self, X, y[, sample_weight]) - Fit linear model.
# Make predictions using the estimator set
y_pred = regr.predict(x_o)
yData = numpy.asarray(y_o)
xData = numpy.asarray(x_o)
# diff_evolution completes by calling curve_fit() using param. bounds
geneticParameters = generate_Initial_Parameters()
# now call curve_fit without passing bounds from the genetic algorithm,
# just in case the best fit parameters are aoutside those bounds
fittedParameters, pcov = scipy.optimize.curve_fit(
func, xData, yData, geneticParameters)
print('Fitted parameters:', fittedParameters)
print()
modelPredictions = func(xData, *fittedParameters)
absError = modelPredictions - yData
SE = numpy.square(absError) # Squared Errors
MSE = numpy.mean(SE) # Mean Squared Errors
RMSE = numpy.sqrt(MSE) # Root Mean Squared Error, RMSE
Rsquared = 1.0 - (numpy.var(absError) / numpy.var(y_o))
print()
print('RMSE:', RMSE)
print('R-squared:', Rsquared)
# Fill up results DataFrame
df = pd.DataFrame(
[[name,
regr.coef_[0, 0], regr.intercept_[0],
mean_squared_error(y_o, y_pred),
r2_score(y_o, y_pred)]], columns=columns_results)
results = results.append(df, ignore_index=True)
return results
实现 - 解决方案
正如@jeremy_rutman 所建议的,这只是在函数内部全局定义 xData 和 yData 的问题。然而,它的问题是我定义的数组的维度不是需要的。
定义它们时正确引入的代码如下
global xData
global yData
yData = np.asarray(y_eff).reshape(len(y_eff))
xData = np.asarray(x).reshape(len(x))
(在我的例子中,问题是在全局定义时它返回: 值错误:对象对于所需数组来说太深 错误:函数调用的结果不是正确的浮点数组 )
问题可能完全是声明的问题
def sumOfSquaredError(parameterTuple):
显然应该是
def sumOfSquaredError(xdata,ydata,parameterTuple):
虽然这里似乎也没有声明使用func
。