Matrix of polynomial elements - python

I am using NumPy for operations on matrices, to calculate matrixA * matrixB, the trace of the matrix, etc... And elements of my matrices are integers. But what I want to know is if there is possibility to work with matrices of polynomials. So for instance I can work with matrices such as [x,y;a,b], not [1,1;1,1], and when I calculate the trace it provides me with the polynomial x + b, and not 2. Is there some polynomial class in NumPy which matrices can work with?

One option is to use the SymPy Matrices module. SymPy is a symbolic mathematics library for Python which is quite interoperable with NumPy, especially for simple matrix manipulation tasks such as this.
>>> from sympy import symbols, Matrix
>>> from numpy import trace
>>> x, y, a, b = symbols('x y a b')
>>> M = Matrix(([x, y], [a, b]))
>>> M
Matrix([
[x, y],
[a, b]])
>>> trace(M)
b + x
>>> M.dot(M)
[a*y + x**2, a*b + a*x, b*y + x*y, a*y + b**2]

Related

plug np.array into sympy expression

I need to subs a numpy.array into an indexed symbol of Sympy expression to numerically calculate the sum. (1+2+3+4+5=15).
My below code still produce symbolic expression. Please help~
from sympy import *
import numpy as np
i = Symbol("i")
y = Symbol("y")
y_ = np.array([1,2,3,4,5])
h = Sum(Indexed("y","i"),(i,0,4))
h.subs([(y,y_)])
smichr answer is solid, however considering that the numerical values of h_ are going to be converted by SymPy to symbolic numbers, the easiest and fastest way is to do this:
new_h = h.subs(y, Array(y_))
# out: Sum([1, 2, 3, 4, 5][i], (i, 0, 4))
# alternatively:
# new_h = h.subs(y, sympify(y_))
new_h.doit()
# out: 15
Another alternative is to convert your symbolic expression to a numerical function with lambdify. However, this approach works as long as the there is not infinity on the bounds of the summation:
f = lambdify([y], h)
f(y_)
# out: 15
Perhaps something like this will work?
>>> y = IndexedBase("y")
>>> h = Sum(y[i],(i,0,4));h.doit()
y[0] + y[1] + y[2] + y[3] + y[4]
>>> _.subs(dict(zip([y[i] for i in range(len(y_))],y_)))
15

What's the easiest way to calculate regression coefficient in python?

I have a 100 by 1 response variable Y, and a 100 by 3 predictor matrix X. I want to calcualte the regression coefficient (X'X)^{-1}X'Y.
Currently I'm doing it as follows:
invXpX=inv(np.dot(np.transpose(X),X))
XpY=np.dot(np.transpose(X),Y)
betahat=np.dot(invXpX,XpY)
This looks pretty cumbersome, while in MATLAB we could do it just like the original math formula: inv(X'*X)*X'*Y. Is there an easier way to calculate this regression coefficient in python?
Thanks!
Yes it can be written more compact, but note that this will not always improve your code, or the readability.
The transpose of a numpy array can be found using dot T (.T). If you use numpy matrix instead of numpy arrays you can also use .I for the inverse, but I would recommend you to use ndarray. For the dot product you can use #. Thereby np.dot(X,Y) = X.dot(Y) when X and Y are numpy arrays.
import numpy as np
# Simulate data using a quadratic equation with coefficients y=ax^2+bx+c
a, b, c = 1, 2, 3
x = np.arange(100)
# Add random component to y values for estimation
y = a*x**2 + b*x + c + np.random.randn(100)
# Get X matrix [100x3]
X = np.vstack([x**2, x, np.ones(x.shape)]).T
# Estimate coefficients a, b, c
x_hat = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y)
>>> array([0.99998334, 2.00246583, 2.95697339])
x_hat = np.linalg.inv(X.T#(X))#(X.T)#(y)
>>> array([0.99998334, 2.00246583, 2.95697339])
# Use matrix:
X_mat = np.matrix(X)
x_hat = (X_mat.T#X_mat).I#X_mat.T#y
>>> matrix([[0.99998334, 2.00246583, 2.95697339]])
# without noise:
y = a*x**2 + b*x + c
x_hat = (X_mat.T#X_mat).I#X_mat.T#y
>>> matrix([[1., 2., 3.]])
You can try this:
np.invert(X.T # X) # (X.T # Y)

How can I evaluate a not so trivial double integral that involves imaginary unit using SymPy (or a similar Python framework)?

I have the following integral (inspired by this question) involving two real variables a and b (and the imaginary unit I):
f = integrate(exp((-a*t**2+I*b*t)/(3*t**2+1)+I*t*x)*(x/(3*t**2+1)), (t, -oo, oo), (x, 0, oo))
I would like to iterate both variables a and b, let us say in the range from -10 to 10, e.g. for a in range(-10,11): followed by an inner loop for b in range(-10,11): and then evaluate the integral, which allows me to draw a surface depending from both variables a and b.
The approach looks as follows:
from sympy.abc import a, b, x, t
from sympy import *
from sympy import var, Integral, init_printing
init_printing()
a, b, x, t = symbols('a b x t')
integrand = exp((-a*t**2+I*b*t)/(3*t**2+1)+I*t*x)*(x/(3*t**2+1))
for i in range(-1,1,0.1):
for j in range(-1,1,0.1):
print(Integral(integrand.subs(a,i).subs(b,j), (t, -oo, oo), (x, 0, oo)).evalf())
I tried to evaluate it using:
Integral(exp((-a*t**2+I*b*t)/(3*t**2+1)+I*t*x)*(x/(3*t**2+1)), (t, -oo, oo), (x, 0, oo)).evalf()
but without success (syntactically it seems to be correct). It would be great to know how we can approach such evaluations. I am open to any alternative approach. I am really curious to know what the surface F(a,b) looks like.
Under the hood when you use evalf for an integral SymPy will use the corresponding routines from the mpmath library:
https://mpmath.org/doc/current/calculus/integration.html
Although mpmath supports numerically evaluating double integrals SymPy will only attempt this for single integrals. You can use mpmath directly though:
In [46]: import mpmath
In [47]: a = 1
In [48]: b = 1
In [49]: I = mpmath.sqrt(-1)
In [50]: f = lambda x, t: mpmath.exp((-a*t**2+I*b*t)/(3*t**2+1)+I*t*x)*(x/(3*t**2+1))
In [51]: mpmath.quad(f, [0, mpmath.inf], [-mpmath.inf, mpmath.inf])
Out[51]: mpc(real='-1.1728243698636993e+37', imag='0.0')
I think that -1e37 result probably just means that the integral doesn't converge (or at least that the numerical algorithm trying to compute it doesn't converge). Picking finite values for the upper limit of the outer integral suggests that this does not converge:
In [54]: for c in [1, 10, 100, 1000, 10000]:
...: print(mpmath.quad(f, [0, c], [-mpmath.inf, mpmath.inf]))
...:
(0.496329567173036 + 0.0j)
(3.47061267913388 + 0.0j)
(6.20670960862542 + 0.0j)
(-245.035824572364 + 0.0j)
(149439.86145905 + 0.0j)
Maybe it converges for some values of a and b but not others.

How to solve symbolic equations on numpy arrays?

I try to solve an equation with solve from Sympy. But my approach doesn't work as desired.
My equation : 0.00622765954483725 = (x * 24.39 * 0.921107170819325) / 143860432.178345.
My code :
from sympy import symbols, solve
import numpy as np
x = symbols('x')
sol = solve((np.array([[x],[x]]) * np.array([[24.39],[293.6]]) * np.array([[0.921107170819325],[1]])) / np.array([[143860432.178345],[143860432.178345]]) - np.array([[0.00622765954483725],[0.0089267519953503]]))
I had success with a linear expression, but I have a DataFrame and I want to solve all data at the same time.
from sympy import symbols, solve
x = symbols('x')
sol = solve((x * 24.39 * 0.921107170819325) / 143860432.178345 - 0.00622765954483725)
Numpy doesn't understand about sympy's symbols, nor does sympy understand about numpy arrays. The only way to make them work together, is with sympy's lambdify which can convert a symbolic sympy expression to a numpy function. In your case, you first need to create a symbolic solution, lambdify it, and call it on your arrays:
from sympy import symbols, solve, Eq, lambdify
a, b, c, d = symbols('a b c d', real=True)
x = symbols('x')
sol = solve(Eq(x * a * b / c, d), x) # solve returns a list of solutions, in this case a list with just one element
np_sol = lambdify((a, b, c, d), sol[0]) # convert the first solution to a (numpy) function
# everything before is only sympy, everything from here is only numpy
import numpy as np
a_np = np.array([[24.39], [293.6]])
b_np = np.array([[0.921107170819325], [1]])
c_np = np.array([[143860432.178345], [143860432.178345]])
d_np = np.array([[0.00622765954483725], [0.0089267519953503]])
np_sol(a_np, b_np, c_np, d_np)
Result:
array([[39879.],
[ 4374.]])

Avoiding double for-loops in NumPy array operations

Suppose I have two 2D NumPy arrays A and B, I would like to compute the matrix C whose entries are C[i, j] = f(A[i, :], B[:, j]), where f is some function that takes two 1D arrays and returns a number.
For instance, if def f(x, y): return np.sum(x * y) then I would simply have C = np.dot(A, B). However, for a general function f, are there NumPy/SciPy utilities I could exploit that are more efficient than doing a double for-loop?
For example, take def f(x, y): return np.sum(x != y) / len(x), where x and y are not simply 0/1-bit vectors.
Here is a reasonably general approach using broadcasting.
First, reshape your two matrices to be rank-four tensors.
A = A.reshape(A.shape + (1, 1))
B = B.reshape((1, 1) + B.shape)
Second, apply your function element by element without performing any reduction.
C = f(A, B) # e.g. A != B
Having reshaped your matrices allows numpy to broadcast. The resulting tensor C has shape A.shape + B.shape.
Third, apply any desired reduction by, for example, summing over the indices you want to discard:
C = C.sum(axis=(1, 3)) / C.shape[0]

Categories

Resources