two dimensional fit with python - python

I need to fit a function
z(u,v) = C u v^p
That is, I have a two-dimensional data set, and I have to find two parameters, C and p. Is there something in numpy or scipy that can do this in a straightforward manner? I took a look at scipy.optimize.leastsq, but it's not clear to me how I would use it here.

def f(x,u,v,z_data):
C = x[0]
p = x[1]
modelled_z = C*u*v**p
diffs = modelled_z - z_data
return diffs.flatten() # it expects a 1D array out.
# it doesn't matter that it's conceptually 2D, provided flatten it consistently
result = scipy.optimize.leastsq(f,[1.0,1.0], # initial guess at starting point
args = (u,v,z_data) # alternatively you can do this with closure variables in f if you like
)
# result is the best fit point
For your specific function you might be able to do it better - for example, for any given value of p there is one best value of C that can be determined by straightforward linear algebra.

You can transform the problem into a simple linear least squares problem, and then you don't need leastsq() at all.
z[i] == C * u[i] * v[i]**p
becomes
z[i]/u[i] == C * v[i]**p
And then
log(z[i]/u[i]) == log(C) + p * log(v[i])
Change variables and you can solve as a simple linear problem:
Z[i] == L + p * V[i]
Using numpy and assuming you have the data in arrays z, u and v, this is rendered as:
Z = log(z/u)
V = log(v)
p, L = np.polyfit(V, Z, 1)
C = exp(L)
You probably ought to put a try: and except: around it in case some of the u values are zero or there are negative values.

Related

Attempting to solve a system of linear equations, where one of my outputs is unknown but I do know it needs to be maximized

I have a set of linear equations that I am attempting to solve. I have five variables that are randomly assigned and sum to 1. I applied these variables row-wise to a matrix (i.e., Ax = B) However, the caveat is that one of my B variables needs to be maximized, subject to the constraint that the rest of my B variables are 0. My data is below:
import pandas as pd
A = [[0.031982, 0.02606, 0.055933, 0.004529, 0.064116],
[-0.000167, 0.181031, 0.145465, 0.120430, 0.114093],
[0.627812, 0.254377, 0.138211, 0.41156, -0.000801],
[-0.228139, 0.377169, 0.085415, 0.008888, -0.020791],
[-0.067697, -0.114113, 0.089583, 0.100222, -0.005291]]
B = [[maximized],
[0],
[0],
[0],
[0]]
x = [x1, x2, x3, x4, x5]
Note: 'maximized' is the value that I am attempting to maximize
What I've done so far:
import numpy as np
ABC=[]
A = DataFrame(A)
N=1000 #my attempt at maximizing by repeating the sequence N times and taking the largest value that results
for i in range(N):
x = np.random.rand(5) #creating random variables
x/= np.sum(x) #so that they sum to one
x=x*A.T[0] #I apply the variables to my data. I want to maximize the sum of the first column, so I transpose and take a slice that I sum below
x=x.sum()
ABC.append(x)
ABC = DataFrame(ABC)
A2=ABC.sort_values(by=0,ascending=False).head(1) #I sort by largest first and take the highest value and store in a new dataframe
maximized=np.array(A2) #I convert the dataframe back into an array
B = [[maximized],[0],[0],[0],[0]]
X = np.linalg.inv(A).dot(B)
X
Obviously this has a lot of error and isn't really achieving what I want. What I want to do is to run a maximization function that gives me the largest value and input that value into my matrix. I don't really know where to go from here, or what sort of maximization function applies in this case. If anyone has any ideas, that would be super appreciated!
If I understand you correctly, you have a given matrix A. Then you want to find a positive vector x with sum 1 such that if Ax = b then b is the all-zeroes vector except that the first entry is maximized, rather than zero.
Let A0 be the first row of matrix A and Ar be the rest. Then we can rephrase your problem as:
Find vector x such that its entries are non-negative, sum to 1, where Ar x = b, b = 0 and maximizing A0 x.
This is simply a standard linear programming instance (handling the 'sum-to-1' requirement by adding a single all-ones row to Ar and a 1 entry to b).
This isn't really a maximization problem I think. There's only one answer with the specified result. If our maximized number is c, then b = [[c,0,0,0,0]].T = c*[[1,0,0,0,0]].T Lets' set b_ as [[1,0,0,0,0]].T so b = c*b_
If we solve A # x_ = b_ by x_ = Ainv # b_, we get a single x_ matrix that still needs to be normalized to form x. If len_x_ = np.linalg.norm(x_), then:
A # (c * x_) = (c * b_) # multiplying `c` though
A # (c * x_) = b # substituting `b = c * b_`
c * x_ = x = x_ / len_x_ # therefore . . .
c = 1 / len_x_
c can only take one value if A is postive-definite, and thus x can only take one value:
b_ = np.array([[1,0,0,0,0]])
x_ = np.linalg.inv(A).dot(b_)
c = 1 / np.linalg.norm(x_)
b = b_ * c
x = x_ * c
Now, it'll get a lot more interesting if A isn't definite (i.e. it doesn't have an inverse). But I'm not sure that's within scope, since you're currently solving by inverting A.

solving differential equation with step function

I am trying to solve this differential equation as part of my assignment. I am not able to understand on how can i put the condition for u in the code. In the code shown below, i arbitrarily provided
u = 5.
2dx(t)dt=−x(t)+u(t)
5dy(t)dt=−y(t)+x(t)
u=2S(t−5)
x(0)=0
y(0)=0
where S(t−5) is a step function that changes from zero to one at t=5. When it is multiplied by two, it changes from zero to two at that same time, t=5.
def model(x,t,u):
dxdt = (-x+u)/2
return dxdt
def model2(y,x,t):
dydt = -(y+x)/5
return dydt
x0 = 0
y0 = 0
u = 5
t = np.linspace(0,40)
x = odeint(model,x0,t,args=(u,))
y = odeint(model2,y0,t,args=(u,))
plt.plot(t,x,'r-')
plt.plot(t,y,'b*')
plt.show()
I do not know the SciPy Library very well, but regarding the example in the documentation I would try something like this:
def model(x, t, K, PT)
"""
The model consists of the state x in R^2, the time in R and the two
parameters K and PT regarding the input u as step function, where K
is the infimum of u and PT is the delay of the step.
"""
x1, x2 = x # Split the state into two variables
u = K if t>=PT else 0 # This is the system input
# Here comes the differential equation in vectorized form
dx = [(-x1 + u)/2,
(-x2 + x1)/5]
return dx
x0 = [0, 0]
K = 2
PT = 5
t = np.linspace(0,40)
x = odeint(model, x0, t, args=(K, PT))
plt.plot(t, x[:, 0], 'r-')
plt.plot(t, x[:, 1], 'b*')
plt.show()
You have a couple of issues here, and the step function is only a small part of it. You can define a step function with a simple lambda and then simply capture it from the outer scope without even passing it to your function. Because sometimes that won't be the case, we'll be explicit and pass it.
Your next problem is the order of arguments in the function to integrate. As per the docs (y,t,...). Ie, First the function, then the time vector, then the other args arguments. So for the first part we get:
u = lambda t : 2 if t>5 else 0
def model(x,t,u):
dxdt = (-x+u(t))/2
return dxdt
x0 = 0
y0 = 0
t = np.linspace(0,40)
x = odeint(model,x0,t,args=(u,))
Moving to the next part, the trouble is, you can't feed x as an arg to y because it's a vector of values for x(t) for particular times and so y+x doesn't make sense in the function as you wrote it. You can follow your intuition from math class if you pass an x function instead of the x values. Doing so requires that you interpolate the x values using the specific time values you are interested in (which scipy can handle, no problem):
from scipy.interpolate import interp1d
xfunc = interp1d(t.flatten(),x.flatten(),fill_value="extrapolate")
#flatten cuz the shape is off , extrapolate because odeint will go out of bounds
def model2(y,t,x):
dydt = -(y+x(t))/5
return dydt
y = odeint(model2,y0,t,args=(xfunc,))
Then you get:
#Sven's answer is more idiomatic for vector programming like scipy/numpy. But I hope my answer provides a clearer path from what you know already to a working solution.

Integrating numerical data with scipy

Basically I have 2 arrays obtained from a set of data points one array for the x values and one for the y values. I need to numerically integrate the y values with respect to the x values - i.e. an element from the y integrated with respect to the corresponding element in x. This should then generate a new array of elements. I have tried simpson's rule but I get one value back instead of an array. A general idea or approach is all I'm looking for. Any help, however, will be much appreciated.
Thanks.
# check out this:
def integration_by_simpsons_3_8_th_rule(i,X,Y,Fd):
h = X[i]-X[i-1]
y_n = Y[i]
y_n_1 = signal[i-1]
y_n_2 = signal[i-2]
y_n_3 = signal[i-3]
Area = (3/8)*h*( y_n_3 + 3*(y_n_2 + y_n_1) + y_n )
return (X[i-1],Area)
def rolling_integration(X,Y,Fd):
Y_int = []
corres_X = []
for i in range(3,len(signal),1):
x,y = integration_by_simpsons_3_8_th_rule(i,X,Y,Fd)
Y_int.append(float(y))
corres_X.append(float(x))
return (np.array(corres_X)+(np.array(1/(4*float(Fd)))),np.array(Y_int))
#Fd : for phase correction

Get vector space coordinates from symbolic polynomial

I'm trying to get the vector coordinates from the polynomial p in the follow code assuming that x,y and z belong to GF(2) but I get error
TypeError: can't initialize vector from nonzero non-list.
How I will be able to fix that?
reset()
var("x")
var("y")
var("z")
pp = 2
k.<t>=GF(2^pp)
VS = k.vector_space()
p = z*x*t^2 + t*y + 1
print VS.coordinates(p)
Maybe you can use the coefficient list of the polynomial as its vectoral coordinates, and then you may convert this list to a vector. But in that case, it is better to define GF(2^2) as GF(4,'a')={0,1,a,a+1}.
For example you may do something like this:
sage
K = GF(4,'a')
R = PolynomialRing(GF(4,'a'),"x")
x = R.gen()
a = K.gen()
p = (a+1)*x^3 + x^2 + a
p.list()
If you need to fix the dimension n to a bigger value than the degree of p, then you may do the following;
n = 6
L = p.list(); l=len(L); i = n-l; L_ = [0]*i; L.extend(L_)
L
gives you the 6-dimensional coordinates of p.
If you need to use this coefficient list as a vector afterwards, you may just use vector(L) instead of L.

Solving an implicit quadratic system of 3 variables

I am trying to solve a system of equations that has 3 variables and a variable number of equations.
Basically, the system is between 5 and 12 equations long, and regardless of how many equations there are, I am trying to solve for 3 variables.
It looks like this:
(x-A)**2 + (y-B)**2 + (z-C)**2 = (c(t-d))**2
I know A,B,C, and the whole right side.
A,B,C and the right side are all arrays of length n, where n varies randomly between 5 and 12. So then we have a system of equations that changes in size.
I believe I need to use numpy's lstsq function and do something like:
data,data1 = getData() # I will have to do this for 2 unique systems.
A = data[:,0]
B = data[:,1]
C = data[:,2]
tid = data[:,3]
P = (x-A)**2 + (y-B)**2 + (z-C)**2
b = tid
solved = lstsq(P,b)
print solved
This however doesn't work, as we know that x,y,z are implicit, and therefore need to be taken out of P in order for this to work.
Help!
What you probably need is scipy.optimize.minimize() which works with arbitrary (nonlinear) equations. numpy.linalg.lstsq() only solves a system of linear equations, and this problem is pretty definitely nonlinear (although there are techniques to linearize systems of equations, I think this is not what you want in this case).
It is likely that a system of >3 equations in 3 variables has no solution, so you have to define how to measure how good a given "solution" is even though it doesn't actually solve the system of equations. How to pose this as a minimization problem depends on the physical or problem-domain interpretation what you are trying to actually do. One possibility is, for the following equations (which are a slightly rearranged version of yours)
(x-A1)**2 + (y-B1)**2 + (z-C1)**2 - T1**2 = 0
(x-A2)**2 + (y-B2)**2 + (z-C2)**2 - T2**2 = 0
...
try to minimize the sum of the absolute values of all the left hand sides (which should be zero if the equation is solved exactly). In other words, you want the x, y, z that produce the minimum of the following function
sum( abs( (x-A1)**2 + (y-B1)**2 + (z-C1)**2 - T1**2 ) + abs( (x-A2)**2 + (y-B2)**2 + (z-C2)**2 - T2**2 ) + ... )
Code example: v is ndarray of (3,) containing x, y, z; and A, B, C, tid are ndarrays of (N,) where N is the number of equations.
def F(v, A, B, C, tid):
x = v[0]
y = v[1]
z = v[2]
return numpy.sum( numpy.abs( (x-A)**2 + (y-B)**2 + (z-C)**2 - tid ) )
v_initial = numpy.array([x0, y0, z0]) # starting guesses
result = scipy.optimize.minimize(F, v_initial, args=(A, B, C, tid))
v = result.x
x, y, z = v.tolist() # the best solution found
This should be close to working but I haven't tested it. You may need some extra arguments to minimize(), for example method, tol, ...

Categories