Parameter Optimization Using Minimize in Python - python
I have written the following two functions to calibrate a model :
The main function is:
def function_Price(para,y,t,T,tau,N,C):
# y= price array
# C = Auto and cross correlation array
# a= paramters need to be calibrated
a=para[0:]
temp=0
for j in range(N):
price_j = a[j]*C[j]*P[t:T-tau,j]
temp=temp+price_j
Price=temp
return Price
The objective function is :
def GError_function_Price(para,y,k,t,T,tau,N,C):
# k is the price need to be fitted
return sum((function_Price(para,y,t,T,tau,N,C)-k[t+tau:T]) ** 2)
Now, I am calling these two functions to do the optimization of the model:
import numpy as np
from scipy.optimize import minimize
# Prices (example)
y = np.array([[1,2,3,4,5,4], [4,5,6,7,8,9], [6,7,8,7,8,6], [13,14,15,11,12,19]])
# Correaltion (example)
Corr= np.array([[1,2,3,4,5,4], [4,5,6,7,8,9], [6,7,8,7,8,6], [13,14,15,11,12,19],[1,2,3,4,5,4],[6,7,8,7,8,6]])
# Define
tau=1
Size = y.shape
N = Size[1]
T = Size[0]
t=0
# initial Values
para=np.zeros(N)
# Bounds
B = np.zeros(shape=(N,2))
for n in range(N):
B[n][0]= float('-inf')
B[n][1]= float('inf')
# Calibration
A = np.zeros(shape=(N,N))
for i in range (N):
k=y[:,i] #fitted one
C=Corr[i,:]
parag=minimize(GError_function_Price,para,args=(y,Y,t,T,tau,N,C),method='SLSQP',bounds=B)
A[i,:]=parag.x
Once, I run the model, It should produce an N by N array of optimized values of paramters. But, except for the first column, it keeps zeros for the rest. Something is wrong.
Can you help me fix the problem, please?
I know how to do it in Matlab.
The following is Matlab Code :
main function
function Price=function_Price(para,P,t,T,tau,N,C)
a=para(:,:);
temp=0;
for j=1:N
price_j = a(j).*C(j).*P(t:T-tau,j);
temp=temp+price_j;
end
Price=temp;
end
The objective function:
function gerr=GError_function_Price(para,P,Y,t,T,tau,N,C)
gerr=sum((function_Price(para,P,t,T,tau,N,C)-Y(t+tau:T)).^2);
end
Now, I call these two functions in the following way:
P = [1,2,3,4,5,4;4,5,6,7,8,9;6,7,8,7,8,6;13,14,15,11,12,19];
AutoAndCrossCorr= [1,2,3,4,5,4;4,5,6,7,8,9;6,7,8,7,8,6;13,14,15,11,12,19;1,2,3,4,5,4;6,7,8,7,8,6];
tau=1;
Size = size(P);
N =6;
T =4;
t=1;
for i=1:N
Y=P(:,i); % fitted one
C=AutoAndCrossCorr(i,:);
para=zeros(1,N);
lb= repmat(-inf,N,1);
ub= repmat(inf ,N,1);
parag=fminsearchbnd(#(para)abs(GError_function_Price(para,P,Y,t,T,tau,N,C)),para,lb,ub);
a(i,:)=parag;
end
The problem seems to be that you're passing the result of a function call to minimize, rather than the function itself. The arguments get passed by the args parameter. So instead of:
minimize(GError_function_Price(para,y,k,t,T,tau,N,C),para,method='SLSQP',bounds=B)
the following should work
minimize(GError_function_Price,para,args=(y,k,t,T,tau,N,C),method='SLSQP',bounds=B)
Related
Solving an ODE with scipy.integrate.solve_bvp, the return of my function is not able to be broadcast into the appropriate array shape for solve_bvp
I am trying to solve a second order ODE with solve_bvp. I have split the second order ODE into a system of tow first oder ODEs. I have a changing set of constants depending on the x (mesh) value. So I am passing these as an array of shape (N,) into my function numdens. While trying to run solve_bvp I get the error that the returns have different shapes namely (N,) and (N-1,) and thus cannot be broadcast into one array. But when I check each return back manually outside of the function it has the shape (N,). If I run the solver without my changing constants I get a solution akin to the right one. import numpy as np from scipy.integrate import solve_bvp,odeint import matplotlib.pyplot as plt E_0 = 1 * 0.0000016021773 #erg: gcm^2/s^2 m_H = 1.6*10**(-24) #g c = 3e11 #cm sigma_c = 2*10**(-23) n_0 = 1*10**(20) #1/cm^3 v_0 = (2*E_0/m_H)**(0.5) #cm/s T = 10**7 b = 20.3 n_eq = b*T**3 n_s = 2.03*10**(19) Q = 1 def velocity(v,x): dvdx = -sigma_c*n_0*v_0*((8*v_0*v-7*v**2-v_0**2)/(2*v*c)) return dvdx n_num = 100 x_num = np.linspace(-1*10**(6),3*10**(6), n_num) sol_velo = odeint(velocity,0.999999999999*v_0,x_num) sol_new = np.reshape(sol_velo,n_num) def constants(v): D1 = (c*v/(3*n_0*v_0*sigma_c)) D2 = ((v**2-8*v_0*v+v_0**2)/(6*v)) D3 = sigma_c*n_0*v_0*((8*v_0*v-7*v**2-v_0**2)/(2*v*c)) return D1,D2,D3 def numdens(x,y): v = sol_new D1,D2,D3 = constants(v) return np.vstack((y[1],(-D2*y[1]-D3*y[0]+Q*((1-y[0])/n_eq))/(D1))) def bc_num(ya, yb): return np.array([ya[0]-n_s,yb[0]-n_eq]) y_num = np.array([np.linspace(n_s, n_eq, n_num),np.linspace(n_s, n_eq, n_num)]) sol_num = solve_bvp(numdens, bc_num, x_num, y_num) plt.plot(sol_num.x, sol_num.y[0], label='$n(x)$') plt.plot(x_num, sol_velo-v_0/7, label='$v(x)$') plt.yscale('log') plt.grid(alpha=0.5) plt.legend(framealpha=1) plt.show()
You need to take into account that the BVP solver uses an adaptive mesh. That is, after refining the initial guess on the initial grid the solver identifies regions with overly large errors and creates new mesh nodes there. As far as I have seen, the opposite is not implemented, even if it may be in some applications sensible to reduce the number of mesh nodes on especially "nice" segments. Thus what you are doing the the numdens function is incomprehensible, it has to function exactly like any other function that you would pass to an ODE solver. If I had to propose some fast fix, and without knowing what the underlying problem is that you want to solve, I would change the assignment of v to v = np.interp(x,x_num,sol_velo) as that should at least produce an array of the correct format.
Evaluate sum of step functions
I have a fairly large number (around 1000) of step functions, each with only two intervals. I'd like to sum them up and then find the maximum value. What is the best way to do this? I've tried out sympy, with code as follows: from sympy import Piecewise, piecewise_fold, evalf from sympy.abc import x from sympy.plotting import * import numpy as np S = 20 t = np.random.random(20) sum_piecewise = None for s in range(S): p = Piecewise((np.random.random(), x<t[s]), (np.random.random(), x>=t[s])) if not sum_piecewise: sum_piecewise = p else: sum_piecewise += p print sum_piecewise.evalf(0.2) However, this outputs a large symbolic expression and not an actual value, which is what I want.
As it appears that you consider numerical functions, it is better (in terms of performance) to work with Numpy. Here's one approach: import numpy as np import matplotlib.pyplot as plt np.random.seed(10) S = 20 # number of piecewise functions # generate S function parameters. # For example, the k-th function is defined as equal to # p_values[k,0] when t<t_values[k] and equal to # p_values[k,1] when t>= t_values[k] t_values = np.random.random(S) p_values = np.random.random((S,2)) # define a piecewise function given the function's parameters def p_func(t, t0, p0): return np.piecewise(t, [t < t0, t >= t0], p0) # define a function that sums a set of piecewise functions corresponding to # parameter arrays t_values and p_values def p_sum(t, t_values, p_values): return np.sum([p_func(t, t0, p0) for t0, p0 in zip(t_values,p_values)]) Here is the plot of the sum of functions: t_range = np.linspace(0,1,1000) plt.plot(t_range, [p_sum(tt,t_values,p_values) for tt in t_range]) Clearly, in order to find the maximum, it suffices to consider only the S time instants contained in t_values. For this example, np.max([p_sum(tt,t_values,p_values) for tt in t_values]) 11.945901591934897
What about using substitution? Try changing sum_piecewise.evalf(0.2) by sum_piecewise.subs(x, 0.2)
Simple Linear Regression in Python
I am trying to implement this algorithm to find the intercept and slope for single variable: Here is my Python code to update the Intercept and slope. But it is not converging. RSS is Increasing with Iteration rather than decreasing and after some iteration it's becoming infinite. I am not finding any error implementing the algorithm.How Can I solve this problem? I have attached the csv file too. Here is the code. import pandas as pd import numpy as np #Defining gradient_decend #This Function takes X value, Y value and vector of w0(intercept),w1(slope) #INPUT FEATURES=X(sq.feet of house size) #TARGET VALUE=Y (Price of House) #W=np.array([w0,w1]).reshape(2,1) #W=[w0, # w1] def gradient_decend(X,Y,W): intercept=W[0][0] slope=W[1][0] #Here i will get a list #list is like this #gd=[sum(predicted_value-(intercept+slope*x)), # sum(predicted_value-(intercept+slope*x)*x)] gd=[sum(y-(intercept+slope*x) for x,y in zip(X,Y)), sum(((y-(intercept+slope*x))*x) for x,y in zip(X,Y))] return np.array(gd).reshape(2,1) #Defining Resudual sum of squares def RSS(X,Y,W): return sum((y-(W[0][0]+W[1][0]*x))**2 for x,y in zip(X,Y)) #Reading Training Data training_data=pd.read_csv("kc_house_train_data.csv") #Defining fixed parameters #Learning Rate n=0.0001 iteration=1500 #Intercept w0=0 #Slope w1=0 #Creating 2,1 vector of w0,w1 parameters W=np.array([w0,w1]).reshape(2,1) #Running gradient Decend for i in range(iteration): W=W+((2*n)* (gradient_decend(training_data["sqft_living"],training_data["price"],W))) print RSS(training_data["sqft_living"],training_data["price"],W) Here is the CSV file.
Firstly, I find that when writing machine learning code, it's best NOT to use complex list comprehension because anything that you can iterate, it's easier to read if written when normal loops and indentation and/or it can be done with numpy broadcasting And using proper variable names can help you better understand the code. Using Xs, Ys, Ws as short hand is nice only if you're good at math. Personally, I don't use them in the code, especially when writing in python. From import this: explicit is better than implicit. My rule of thumb is to remember that if I write code I can't read 1 week later, it's bad code. First, let's decide what is the input parameters for gradient descent, you will need: feature_matrix (The X matrix, type: numpy.array, a matrix of N * D size, where N is the no. of rows/datapoints and D is the no. of columns/features) output (The Y vector, type: numpy.array, a vector of size N) initial_weights (type: numpy.array, a vector of size D). Additionally, to check for convergence you will need: step_size (the magnitude of change when iterating through to change the weights; type: float, usually a small number) tolerance (the criteria to break the iterations, when the gradient magnitude is smaller than tolerance, assume that your weights have convereged, type: float, usually a small number but much bigger than the step size). Now to the code. def regression_gradient_descent(feature_matrix, output, initial_weights, step_size, tolerance): converged = False # Set a boolean to check for convergence weights = np.array(initial_weights) # make sure it's a numpy array while not converged: # compute the predictions based on feature_matrix and weights. # iterate through the row and find the single scalar predicted # value for each weight * column. # hint: a dot product can solve this easily predictions = [??? for row in feature_matrix] # compute the errors as predictions - output errors = predictions - output gradient_sum_squares = 0 # initialize the gradient sum of squares # while we haven't reached the tolerance yet, update each feature's weight for i in range(len(weights)): # loop over each weight # Recall that feature_matrix[:, i] is the feature column associated with weights[i] # compute the derivative for weight[i]: # Hint: the derivative is = 2 * dot product of feature_column and errors. derivative = 2 * ???? # add the squared value of the derivative to the gradient magnitude (for assessing convergence) gradient_sum_squares += (derivative * derivative) # subtract the step size times the derivative from the current weight weights[i] -= (step_size * derivative) # compute the square-root of the gradient sum of squares to get the gradient magnitude: gradient_magnitude = ??? # Then check whether the magnitude is lower than the tolerance. if ???: converged = True # Once it while loop breaks, return the loop. return(weights) I hope the extended pseudo-code helps you better understand the gradient descent. I won't fill in the ??? so as to not spoil your homework. Note that your RSS code is also unreadable and unmaintainable. It's easier to do just: >>> import numpy as np >>> prediction = np.array([1,2,3]) >>> output = np.array([1,1,5]) >>> residual = output - prediction >>> RSS = sum(residual * residual) >>> RSS 5 Going through numpy basics will go a long way to machine learning and matrix-vector manipulation without going nuts with iterations: http://docs.scipy.org/doc/numpy-1.10.1/user/basics.html
I have solved my own problem! Here is the solved way. import numpy as np import pandas as pd import math from sys import stdout #function Takes the pandas dataframe, Input features list and the target column name def get_numpy_data(data, features, output): #Adding a constant column with value 1 in the dataframe. data['constant'] = 1 #Adding the name of the constant column in the feature list. features = ['constant'] + features #Creating Feature matrix(Selecting columns and converting to matrix). features_matrix=data[features].as_matrix() #Target column is converted to the numpy array output_array=np.array(data[output]) return(features_matrix, output_array) def predict_outcome(feature_matrix, weights): weights=np.array(weights) predictions = np.dot(feature_matrix, weights) return predictions def errors(output,predictions): errors=predictions-output return errors def feature_derivative(errors, feature): derivative=np.dot(2,np.dot(feature,errors)) return derivative def regression_gradient_descent(feature_matrix, output, initial_weights, step_size, tolerance): converged = False #Initital weights are converted to numpy array weights = np.array(initial_weights) while not converged: # compute the predictions based on feature_matrix and weights: predictions=predict_outcome(feature_matrix,weights) # compute the errors as predictions - output: error=errors(output,predictions) gradient_sum_squares = 0 # initialize the gradient # while not converged, update each weight individually: for i in range(len(weights)): # Recall that feature_matrix[:, i] is the feature column associated with weights[i] feature=feature_matrix[:, i] # compute the derivative for weight[i]: #predict=predict_outcome(feature,weights[i]) #err=errors(output,predict) deriv=feature_derivative(error,feature) # add the squared derivative to the gradient magnitude gradient_sum_squares=gradient_sum_squares+(deriv**2) # update the weight based on step size and derivative: weights[i]=weights[i] - np.dot(step_size,deriv) gradient_magnitude = math.sqrt(gradient_sum_squares) stdout.write("\r%d" % int(gradient_magnitude)) stdout.flush() if gradient_magnitude < tolerance: converged = True return(weights) #Example of Implementation #Importing Training and Testing Data # train_data=pd.read_csv("kc_house_train_data.csv") # test_data=pd.read_csv("kc_house_test_data.csv") # simple_features = ['sqft_living', 'sqft_living15'] # my_output= 'price' # (simple_feature_matrix, output) = get_numpy_data(train_data, simple_features, my_output) # initial_weights = np.array([-100000., 1., 1.]) # step_size = 7e-12 # tolerance = 2.5e7 # simple_weights = regression_gradient_descent(simple_feature_matrix, output,initial_weights, step_size,tolerance) # print simple_weights
It is so simple def mean(values): return sum(values)/float(len(values)) def variance(values, mean): return sum([(x-mean)**2 for x in values]) def covariance(x, mean_x, y, mean_y): covar = 0.0 for i in range(len(x)): covar+=(x[i]-mean_x) * (y[i]-mean_y) return covar def coefficients(dataset): x = [] y = [] for line in dataset: xi, yi = map(float, line.split(',')) x.append(xi) y.append(yi) dataset.close() x_mean, y_mean = mean(x), mean(y) b1 = covariance(x, x_mean, y, y_mean)/variance(x, x_mean) b0 = y_mean-b1*x_mean return [b0, b1] dataset = open('trainingdata.txt') b0, b1 = coefficients(dataset) n=float(raw_input()) print(b0+b1*n) reference : www.machinelearningmastery.com/implement-simple-linear-regression-scratch-python/
Scipy odeint giving index out of bounds errors
I am trying to solve a differential equation in python using Scipy's odeint function. The equation is of the form dy/dt = w(t) where w(t) = w1*(1+A*sin(w2*t)) for some parameters w1, w2, and A. The code I've written works for some parameters, but for others I get given index out of bound errors. Here's some example code that works import numpy as np import scipy.integrate as integrate t = np.arange(1000) w1 = 2*np.pi w2 = 0.016*np.pi A = 1.0 w = w1*(1+A*np.sin(w2*t)) def f(y,t0): return w[t0] y = integrate.odeint(f,0,t) Here's some example code that doesn't work import numpy as np import scipy.integrate as integrate t = np.arange(1000) w1 = 0.3*np.pi w2 = 0.005*np.pi A = 0.15 w = w1*(1+A*np.sin(w2*t)) def f(y,t0): return w[t0] y = integrate.odeint(f,0,t) The only thing that changes between these is that the three parameters w1, w2, and A are smaller in the second, but the second one always gives me the following error line 13, in f return w[t0] IndexError: index 1001 is out of bounds for axis 0 with size 1000 This error continues even after restarting python and running the second code first. I've tried with other parameters, some seem to work, but others give me different index out of bounds errors. Some say 1001 is out of bounds, some say 1000, some say 1008, ect. Changing the initial condition on y (the second input for odeint, which I have as 0 on the above codes) also changes the number on the index error, so it might be that I'm misunderstanding what to put here. I wasn't told what the initial conditions should be other than that y is used as a phase of a signal, so I presumed it to be initially 0.
What you want to do is def w(t): return w1*(1+A*np.sin(w2*t)) def f(y,t0): return w(t0) Array indices are typically integers, time arguments and values of solutions of differential equations are typically real numbers. Thus there is some conceptual difficulty in invoking w[t0]. You might also try to integrate directly the function w, there is no inherent difficulty in this example. As for coupled systems, you solve them as coupled systems. def w(t): return w1*(1+A*np.sin(w2*t)) def f(y,t): wt = w(t) return np.array([ wt, wt*sin(y[1]-y[0]) ])
Working out an equation
I'm trying to solve a differential equation numerically, and am writing an equation that will give me an array of the solution to each time point. import numpy as np import matplotlib.pylab as plt pi=np.pi sin=np.sin cos=np.cos sqrt=np.sqrt alpha=pi/4 g=9.80665 y0=0.0 theta0=0.0 sina = sin(alpha)**2 second_term = g*sin(alpha)*cos(alpha) x0 = float(raw_input('What is the initial x in meters?')) x_vel0 = float(raw_input('What is the initial velocity in the x direction in m/s?')) y_vel0 = float(raw_input('what is the initial velocity in the y direction in m/s?')) t_f = int(raw_input('What is the maximum time in seconds?')) r0 = x0 vtan = sqrt(x_vel0**2+y_vel0**2) dt = 1000 n = range(0,t_f) r_n = r0*(n*dt) r_nm1 = r0((n-1)*dt) F_r = ((vtan**2)/r_n)*sina-second_term r_np1 = 2*r_n - r_nm1 + dt**2 * F_r data = [r0] for time in n: data.append(float(r_np1)) print data I'm not sure how to make the equation solve for r_np1 at each time in the range n. I'm still new to Python and would like some help understanding how to do something like this.
First issue is: n = range(0,t_f) r_n = r0*(n*dt) Here you define n as a list and try to multiply the list n with the integer dt. This will not work. Pure Python is NOT a vectorized language like NumPy or Matlab where you can do vector multiplication like this. You could make this line work with n = np.arange(0,t_f) r_n = r0*(n*dt), but you don't have to. Instead, you should move everything inside the for loop to do the calculation at each timestep. At the present point, you do the calculation once, then add the same only result t_f times to the data list. Of course, you have to leave your initial conditions (which is a key part of ODE solving) OUTSIDE of the loop, because they only affect the first step of the solution, not all of them. So: # Initial conditions r0 = x0 data = [r0] # Loop along timesteps for n in range(t_f): # calculations performed at each timestep vtan = sqrt(x_vel0**2+y_vel0**2) dt = 1000 r_n = r0*(n*dt) r_nm1 = r0*((n-1)*dt) F_r = ((vtan**2)/r_n)*sina-second_term r_np1 = 2*r_n - r_nm1 + dt**2 * F_r # append result to output list data.append(float(r_np1)) # do something with output list print data plt.plot(data) plt.show() I did not add any piece of code, only rearranged your lines. Notice that the part: n = range(0,t_f) for time in n: Can be simplified to: for time in range(0,t_f): However, you use n as a time variable in the calculation (previously - and wrongly - defined as a list instead of a single number). Thus you can write: for n in range(0,t_f): Note 1: I do not know if this code is right mathematically, as I don't even know the equation you're solving. The code runs now and provides a result - you have to check if the result is good. Note 2: Pure Python is not the best tool for this purpose. You should try some highly optimized built-ins of SciPy for ODE solving, as you have already got hints in the comments.