Scipy Curve_fit. Separate bounds for multiple parameters - python

I am using Scipy to fit my data to a function. The function give me values for 2 parameters, in this case a and b. I want to use the bound argument to limit the values these parameters can take, each have their own range of acceptable values.
Acceptable values: 15< a <50 and 0.05< b <0.2
I want to know how to implement them. The official documentation only shows how to do them for 1 parameter. This question is similiar to: Python curve fit library that allows me to assign bounds to parameters. Which also only tackles boundaries for 1 parameter.
Here is what i tried:
def Ebfit(x,a,b):
Eb_mean = a*(0.0256/kt) # Eb at bake temperature
Eb_sigma = b*Eb_mean
Foursigma = 4*Eb_sigma
Eb_a = np.linspace(Eb_mean-Foursigma,Eb_mean+Foursigma,N_Device)
dEb = Eb_a[1] - Eb_a[0]
pdfEb_a = spys.norm.pdf(Eb_a,Eb_mean,Eb_sigma)
## Retention Time
DMom = np.zeros(len(x),float)
tau = (1/f0)*np.exp(Eb_a)
for bb in range(len(x)):
DMom[bb]= (1 - 2*(sum(pdfEb_a*(1 - np.exp(np.divide(-x[bb],tau))))*dEb))
return DMom
time = datafile['time'][0:501]
Moment = datafile['25Oe'][0:501]
params,extras = curve_fit(Ebfit,time,Moment, p0=[20,0.1], bounds=[(15,50),(0.05,0.2)])
I have also tried the following variations to see if the parenthesis was the issue:
params,extras = curve_fit(Ebfit,time,Moment, p0=[20,0.1], bounds=[[15,50],[0.02,0.2]])
params,extras = curve_fit(Ebfit,time,Moment, p0=[20,0.1], bounds=((15,50),(0.02,0.2)))
But I get the same error for all of these variations
ValueError: Each lower bound mush be strictly less than each upper
bound.
It only works with a single bound such as:
params,extras = curve_fit(Ebfit,time,Moment, p0=[20,0.1], bounds=[0,50])
Any help is appreciated.
Thank you!

bounds=[[0,50],[0,0.3]]) means the second parameter is greater than 50 but smaller then 0.3. Also the first parameter is fixed at zero.
The format is bounds=(lower, upper).

As per #ev-br suggestion. I tried the following changes for the bounds argument and it worked out great.
bounds=[[15,0.02],[50,0.2]]
So in the end, the argument give should be as follows:
bounds=[[a1,b1],[a2,b2]]
Where a1 is the lower limit for a and a2 the upper limit for a. Sames goes for b.

Related

How to convert value of pyomo variable from float to int?

I'm working on an Task Scheduling problem given in Table 3 of paper Holistic energy awareness for intelligent drones.
Table 3
In the 6th equation: N_d = E_d/B_d
I want to convert floating value of (E_d/B_d) to an integer value of N_d.
I'm using an Abstract model on pyomo (6.4.0) on python 3.7 and glpk 4.65 solver
The basic original code written is
model.Drones = Set() # List of drones
model.Battery_capacity = Param(model.Drones, within=NonNegativeReals) # =170
model.Energy_total = Var(model.Drones, within=NonNegativeReals, initialize=1)
model.Charging_sessions = Var(model.Drones, within=NonNegativeReals, initialize=1)
def battery_charging_sessions_rule(model, d):
return model.Charging_sessions[d] == (model.Energy_total[d]/model.Battery_capacity[d])
model.battery_charging_sessions = Constraint(model.Drones, rule=battery_charging_sessions_rule)
In this case, model.battery_charging_sessions is a floating point value which can be less than 1 also. I've tried various options like
model.Charging_sessions = Var(model.Drones, within=Integers, initialize=1, bounds=(0,None))
and using the following return statement also instead of previous one
return model.Charging_sessions[d] == floor(value((model.Energy_total[d]/model.Battery_capacity[d])))
However, this cause the model.Charging_sessions forced to be 0 and it wont even be generated in results file. Using the logs I found out with no change in original code,
Charging_sessions[d] - (0.0058823530*Energy_total[d])
is lower and upper bounded by 0,where 0.0058823530 = 1/170.
While with the changes the lower and upper bound of
Charging_sessions[d]
are 0. It seems that by using floor(value()) or int(value()) the term (0.0058823530*Energy_total[d]) is reduced to 0.
What are the ways I can get the integer value?

Variable definition as constraint in pyomo

This question is related to my previous question found here. I have managed to solve this problem (big thanks to #AirSquid!) My objective function is something like:
So the avgPrice_n variable is indexed by n. However, it is actually defined as
Meaning that it is indexed by n and i.
So at the moment my objective function is very messy as I have three sums. It looks something like (I expanded the brackets in the objective function and added each component separately, so the avgPrice_n*demand_n looks like):
expr += sum(sum(sum((1/12)*model.c[i]*model.allocation[i,n] for i in model.MP[t]) for t in model.M)*model.demand_n[n] for n in model.N)
And while this works, debugging was quite difficult because the terms are very long. So intead of using the actual definition of avgPrice_n, I was wondering if it would be possible to create a avgPrice_n variable, use this in the objective function and then create a constraint where I define avgPrice_n as I showed above.
The issue I am having is that I created my decision variable, x_{i,n}, as a variable but apparently I can't create a avgPrice_n as a variable where I index it by x_{i,n} as this results in a TypeError: Cannot apply a Set operator to an indexed Var component (allocation) error.
So as of now my decision variable looks like:
model.x = Var(model.NP_flat, domain = NonNegativeReals)
And I tried to create:
model.avg_Price = Var(model.x, domain = NonNegativeReals)
Which resulted in the above error. Any ideas or suggestions would be much appreciated!
You have a couple options. Realize you do not need the model.avg_price variable because you can construct it from other variables and you would have to make some constraints to constrain the value, etc. etc. and pollute your model.
The basic building blocks in the model are pyomo expressions, so you could put in a little "helper function" to build expressions (the cost function shown, which is dependent on n) which are not defined within the model, but just pop out an expression...totally legal). You can also "break up" large expressions into smaller expressions (like the other_stuff below) and then just kludge them all together in the objective (or where needed) this gives you the opportunity to evaluate them independently. I've made several models with an objective function that has a "cost" component and a "penalty" component by dividing it into 2 expressions.... Then when solved, you can inspect them independently.
My suggestion (if you don't like the triple sum in your current model) is to make an avg_cost(n) function to build the expression similar to what is done in the nonsensical function below, and use that as a substitute for a new variable.
Note: the initialization of the variables here is generally unnecessary. I just did it to "simulate solving" or they would be None...
Code:
import pyomo.environ as pyo
m = pyo.ConcreteModel()
m.N = pyo.Set(initialize=[0,1,2])
m.x = pyo.Var(m.N, initialize = 2.0)
def cost(n):
return m.x[n] + 2*m.x[n+1]
m.other_stuff = 3 * m.x[1] + 4 * m.x[2]
m.costs = sum(cost(n) for n in {0,1})
m.obj_expr = m.costs + m.other_stuff
m.obj = pyo.Objective(expr= m.obj_expr)
# inspect cost at a particular value of n...
print(cost(1))
print(pyo.value(cost(1)))
# inspect the pyomo expressions "other_stuff" and total costs...
print(m.other_stuff)
print(pyo.value(m.other_stuff))
print(m.costs)
print(pyo.value(m.costs))
# inspect the objective... which can be accessed by pprint() and display()
m.obj.pprint()
m.obj.display()
Output:
x[1] + 2*x[2]
6.0
3*x[1] + 4*x[2]
14.0
12.0
obj : Size=1, Index=None, Active=True
Key : Active : Sense : Expression
None : True : minimize : x[0] + 2*x[1] + x[1] + 2*x[2] + 3*x[1] + 4*x[2]
obj : Size=1, Index=None, Active=True
Key : Active : Value
None : True : 26.0

Using NEOS as a Pyomo solver

I have recently started in doing some OR, and have been trying to use Pyomo and NEOS to do some optimation problems. I have been following along with one of the UT Austin Pyomo lectures, and when my GLPT was being difficult to be installed, I moved on to NEOS. I am having some difficulty in now receiving a solved answer from NEOS.
What I have so far is this:
from pyomo import environ as pe
import os
os.environ['NEOS_EMAIL'] = 'my registered email'
model = pe.ConcreteModel()
model.x1 = pe.Var(domain=pe.Binary)
model.x2 = pe.Var(domain=pe.Binary)
model.x3 = pe.Var(domain=pe.Binary)
model.x4 = pe.Var(domain=pe.Binary)
model.x5 = pe.Var(domain=pe.Binary)
obj_expr = 3 * model.x1 + 4 * model.x2 + 5 * model.x3 + 8 * model.x4 + 9 * model.x5
model.obj = pe.Objective(sense=pe.maximize, expr=obj_expr)
con_expr = 2 * model.x1 + 3 * model.x2 + 4 * model.x3 + 5 * model.x4 + 9 * model.x5 <= 20
model.con = pe.Constraint(expr=con_expr)
solver_manager = pe.SolverManagerFactory('neos')
results = solver_manager.solve(model, solver = "minos")
print(results)
What I receive in return is number of solutions = 0, while I know for a fact that one exits. I also see that I don't have any bounds set, so how would I go about doing that? Once again, I am very new to this, and have not been able to find any sort of documentation regarding this elsewhere, or perhaps I just don't know how to look.
Thanks for any help!
This is a "problem" with the design of the current results object. For historical reasons, that field reports the number of solutions contained in the results object and is not the number of solutions generated by the solver. By default, Pyomo solvers directly load the solution returned by the solver into the original model (both for convenience and efficiency) and do not return it in the results object. You can change that behavior by providing load_solutions=False to the solve() call.
As for the bounds, what bounds are you referring to? Variable bounds are set using either the bounds= argument to the Var() declaration, or the domain= argument. For your example, because the variables are declared to be Binary, they all have bounds of [0..1]. Bounds on the objective are gathered by parsing the solver output. This is dependent on bother the solver that you are using (many do not report bounds information), and the interface used to parse the solver results.
As a final note, you are sending a MIP problem to a LP/NLP solver (minos). You will get fractional valies for your binary variables back from the solver.
To retrieve the solution from the model, you can use something like:
print(model.x1.value, model.x2.value, model.x3.value, model.x4.value, model.x5.value)
And using solver="cbc" you can avoid fractional values in this example.

Take Values inside of odeint in python

My question is if there's a way to take some values in a function that are not
integrated in odeint.
Exemple: if I have a derivative dy(x)/dt = A*x+ln(x) and before to get this equation I computed A throught of a intermediate equation like A = B*D . I would like to take the A's value during the process.
More detailed (only exemple):
def func(y,t)
K = y[0]
B = 3
A = cos(t**2) + B
dy/dt = A*t+ln(t)
return [dy/dt]
Can I take A's values of function?
The answer for Josh Karpel
The code is like that:
def Reaction(state,t):
# Integrate Results
p = state[0]
T = state[1]
# function determine enthalpy of system
f1(T,p) = enthalpy
# function determine specific volume of system
f2(T,p) = specific volume
# function determine heat release by reactions
f3(T,p,t) = heat release by reactions
# Derivatives
dp/dt = f(T,p,enthalpy,specific volume,heat release by reactions)
dT/dt = f(T,p,enthalpy,specific volume,heat release by reactions)
The real code is bigger than that. But, I would like to know if there is a way to store the values of f1 (enthalpy), f2 (specific volume), f3 (heat release) as a vector or tuple during the process of solution of odeint with the same size of p and T.
It's not entirely clear what you want, but it sounds like you need to pass another value to the function you're integrating over. There are two options I can think of:
scipy.integrate.odeint takes an args argument which contains extra arguments to be passed to the integrand function, which could then have signature y(t, A).
You could use functools.partial to construct a new function which has the argument A for the integrand function y(t, A) already set.

Why does my association model find subgroups in a dataset when there shouldn't any?

I give a lot of information on the methods that I used to write my code. If you just want to read my question, skip to the quotes at the end.
I'm working on a project that has a goal of detecting sub populations in a group of patients. I thought this sounded like the perfect opportunity to use association rule mining as I'm currently taking a class on the subject.
I there are 42 variables in total. Of those, 20 are continuous and had to be discretized. For each variable, I used the Freedman-Diaconis rule to determine how many categories to divide a group into.
def Freedman_Diaconis(column_values):
#sort the list first
column_values[1].sort()
first_quartile = int(len(column_values[1]) * .25)
third_quartile = int(len(column_values[1]) * .75)
fq_value = column_values[1][first_quartile]
tq_value = column_values[1][third_quartile]
iqr = tq_value - fq_value
n_to_pow = len(column_values[1])**(-1/3)
h = 2 * iqr * n_to_pow
retval = (column_values[1][-1] - column_values[1][1])/h
test = int(retval+1)
return test
From there I used min-max normalization
def min_max_transform(column_of_data, num_bins):
min_max_normalizer = preprocessing.MinMaxScaler(feature_range=(1, num_bins))
data_min_max = min_max_normalizer.fit_transform(column_of_data[1])
data_min_max_ints = take_int(data_min_max)
return data_min_max_ints
to transform my data and then I simply took the interger portion to get the final categorization.
def take_int(list_of_float):
ints = []
for flt in list_of_float:
asint = int(flt)
ints.append(asint)
return ints
I then also wrote a function that I used to combine this value with the variable name.
def string_transform(prefix, column, index):
transformed_list = []
transformed = ""
if index < 4:
for entry in column[1]:
transformed = prefix+str(entry)
transformed_list.append(transformed)
else:
prefix_num = prefix.split('x')
for entry in column[1]:
transformed = str(prefix_num[1])+'x'+str(entry)
transformed_list.append(transformed)
return transformed_list
This was done to differentiate variables that have the same value, but appear in different columns. For example, having a value of 1 for variable x14 means something different from getting a value of 1 in variable x20. The string transform function would create 14x1 and 20x1 for the previously mentioned examples.
After this, I wrote everything to a file in basket format
def create_basket(list_of_lists, headers):
#for filename in os.listdir("."):
# if filename.e
if not os.path.exists('baskets'):
os.makedirs('baskets')
down_length = len(list_of_lists[0])
with open('baskets/dataset.basket', 'w') as basketfile:
basket_writer = csv.DictWriter(basketfile, fieldnames=headers)
for i in range(0, down_length):
basket_writer.writerow({"trt": list_of_lists[0][i], "y": list_of_lists[1][i], "x1": list_of_lists[2][i],
"x2": list_of_lists[3][i], "x3": list_of_lists[4][i], "x4": list_of_lists[5][i],
"x5": list_of_lists[6][i], "x6": list_of_lists[7][i], "x7": list_of_lists[8][i],
"x8": list_of_lists[9][i], "x9": list_of_lists[10][i], "x10": list_of_lists[11][i],
"x11": list_of_lists[12][i], "x12":list_of_lists[13][i], "x13": list_of_lists[14][i],
"x14": list_of_lists[15][i], "x15": list_of_lists[16][i], "x16": list_of_lists[17][i],
"x17": list_of_lists[18][i], "x18": list_of_lists[19][i], "x19": list_of_lists[20][i],
"x20": list_of_lists[21][i], "x21": list_of_lists[22][i], "x22": list_of_lists[23][i],
"x23": list_of_lists[24][i], "x24": list_of_lists[25][i], "x25": list_of_lists[26][i],
"x26": list_of_lists[27][i], "x27": list_of_lists[28][i], "x28": list_of_lists[29][i],
"x29": list_of_lists[30][i], "x30": list_of_lists[31][i], "x31": list_of_lists[32][i],
"x32": list_of_lists[33][i], "x33": list_of_lists[34][i], "x34": list_of_lists[35][i],
"x35": list_of_lists[36][i], "x36": list_of_lists[37][i], "x37": list_of_lists[38][i],
"x38": list_of_lists[39][i], "x39": list_of_lists[40][i], "x40": list_of_lists[41][i]})
and I used the apriori package in Orange to see if there were any association rules.
rules = Orange.associate.AssociationRulesSparseInducer(patient_basket, support=0.3, confidence=0.3)
print "%4s %4s %s" % ("Supp", "Conf", "Rule")
for r in rules:
my_rule = str(r)
split_rule = my_rule.split("->")
if 'trt' in split_rule[1]:
print 'treatment rule'
print "%4.1f %4.1f %s" % (r.support, r.confidence, r)
Using this, technique I found quite a few association rules with my testing data.
THIS IS WHERE I HAVE A PROBLEM
When I read the notes for the training data, there is this note
...That is, the only
reason for the differences among observed responses to the same treatment across patients is
random noise. Hence, there is NO meaningful subgroup for this dataset...
My question is,
why do I get multiple association rules that would imply that there are subgroups, when according to the notes I shouldn't see anything?
I'm getting lift numbers that are above 2 as opposed to the 1 that you should expect if everything was random like the notes state.
Supp Conf Rule
0.3 0.7 6x0 -> trt1
Even though my code runs, I'm not getting results anywhere close to what should be expected. This leads me to believe that I messed something up, but I'm not sure what it is.
After some research, I realized that my sample size is too small for the number of variables that I have. I would need a way larger sample size in order to really use the method that I was using. In fact, the method that I tried to use was developed with the assumption that it would be run on databases with hundreds of thousands or millions of rows.

Categories