How do i replicate this matlab function in numpy? - python

[A,I] = histc([0.9828 0.4662 0.5245 0.9334 0.2163],[0.0191 0.2057 0.2820 0.2851 1.0000])
That is the MATLAB code with the results:
A =
0 1 0 4 0
I =
4 4 4 4 2
What I need is I. I've tried using np.histogram but it gives me this:
>>> a,b = np.histogram([0.9828 , 0.4662 , 0.5245 , 0.9334 , 0.2163],[0.0191 , 0.2057 , 0.2820 , 0.2851 , 1.0000])
>>> a
array([0, 1, 0, 4])
>>> b
array([ 0.0191, 0.2057, 0.282 , 0.2851, 1. ])
I want to get the bins that each element in my array/matrix goes into.

What you are looking for is numpy.digitize:
Return the indices of the bins to which each value in input array belongs.
>>> a = np.digitize([0.9828 , 0.4662 , 0.5245 , 0.9334 , 0.2163],[0.0191 , 0.2057 , 0.2820 , 0.2851 , 1.0000])
>>> print(a)
[4 4 4 4 2]

A correct python implementation of matlab's histc is the following:
import numpy as np
def histc(x, binranges):
indices = np.searchsorted(binranges, x)
return np.mod(indices+1, len(binranges)+1)

Correct implementation of MATLAB histc function in python (source).
def histc(x, bins):
map_to_bins = np.digitize(x, bins) # Get indices of the bins to which each value in input array belongs.
res = np.zeros(bins.shape)
for el in map_to_bins:
res[el-1] += 1 # Increment appropriate bin.
return res

numpy.digitize alone is not a complete reproduction of Matlab histc. This works:
import numpy as np
def histc(X, bins):
map_to_bins = np.digitize(X,bins)
r = np.zeros(bins.shape)
for i in map_to_bins:
r[i-1] += 1
return [r, map_to_bins]
if __name__=="__main__":
X = np.array([0.9828, 0.4662, 0.5245, 0.9334, 0.2163])
bins = np.array([0.0191, 0.2057, 0.2820, 0.2851, 1.0])
[A,I] = histc(X, bins)
print("X", X)
print("bins", bins)
print("A",A,"expecting", [0, 1, 0, 4, 0])
print("I",I,"expecting", [4, 4, 4, 4, 2])

Related

How to use numpy in matrices iterations like Matlab

I am used to make my discrete time control systems simulations in Matlab and now I'm trying python and numpy.
So, my code bellow is working, but I would like to iterate over the numpy vector instead appending values into a list. Is it possible?
In other words, instead of using
xl.append(xt)
ul.append(uc)
I would like to use some Matlab equivalent like x[:, k+1] = np.dot(Ad, x[:, k]) + Bd*uc, but it's not working on my code. If I do that, instead of obtaining a two line column vector that is the expected, I got a 2x2 matrix and an error.
Another question: Why it's neccessary to use plt.plot(tk, u[:, 0], label='u') instead plt.plot(tk, u, label='u') ?
from control.matlab import *
import math
import numpy as np
import matplotlib.pyplot as plt
Ts = 0.1
N = 50
#x = np.zeros((2, N+1))
tk = np.zeros(N)
u = np.zeros(N)
v = np.random.randn(N)/86.6 #% measurement noise
wn = 1.12
wn2 = pow(wn, 2)
A = [[0, 1], [-1.5, -1.4]]
B = [[0], [1.5]]
C = [[1, 0]]
D = 0
# Control gains
K = np.array([2.64, 3.41071429])
# Now build a feedback with control law u = -K*x
Ad = np.eye(2) + np.multiply(A, Ts)
Bd = np.multiply(B, Ts)
Cd = C
xt = [[1.0], [0.12]] # initial states
xl = []
ul = []
for k in range(0, N):
tk[k] = k*Ts
uc = -K.dot(xt)
xt = np.dot(Ad, xt) + Bd*uc
xt[1, 0] += v[k]
xl.append(xt)
ul.append(uc)
x = np.array(xl)
u = np.array(ul)
#x = np.delete(x, N, 1) # delete the last position of x
#s = TransferFunction.s
#Gs = wn2/(s**2 + 0*s + wn2) # This is the KF solution
#yout, T = step(Gs)
plt.rcParams["figure.figsize"] = (10, 7)
plt.figure()
#plt.plot(T, yout, label='Open loop')
plt.plot(tk, x[:, 0], label='x_0')
plt.plot(tk, x[:, 1], label='x_1')
plt.plot(tk, u[:, 0], label='u')
plt.legend()
plt.title('Pendulum ex. 7.14 Franklin book')
plt.xlabel('Time')
plt.ylabel('amp.')
plt.show()
what I want is the code like this:
from control.matlab import *
import math
import numpy as np
import matplotlib.pyplot as plt
Ts = 0.1
N = 50
x = np.zeros((2, N+1))
tk = np.zeros(N)
u = np.zeros(N)
v = np.random.randn(N)/86.6 #% measurement noise
wn = 1.12
wn2 = pow(wn, 2)
A = [[0, 1], [-1.5, -1.4]]
B = [[0], [1.5]]
C = [[1, 0]]
D = 0
# Control gains
K = np.array([2.64, 3.41071429])
# Now build a feedback with control law u = -K*x
Ad = np.eye(2) + np.multiply(A, Ts)
Bd = np.multiply(B, Ts)
Cd = C
for k in range(0, N):
tk[k] = k*Ts
u[k] = -K.dot(x[:, k])
x[1, k] += v[k]
x[:, k+1] = np.dot(Ad, x[:, k]) + Bd*u[k]
x = np.delete(x, N, 1) # delete the last position of x
#s = TransferFunction.s
#Gs = wn2/(s**2 + 0*s + wn2) # This is the KF solution
#yout, T = step(Gs)
plt.rcParams["figure.figsize"] = (10, 7)
plt.figure()
#plt.plot(T, yout, label='Open loop')
plt.plot(tk, x[:, 0], label='x_0')
plt.plot(tk, x[:, 1], label='x_1')
plt.plot(tk, u[:, 0], label='u')
plt.legend()
plt.title('Pendulum ex. 7.14 Franklin book')
plt.xlabel('Time')
plt.ylabel('amp.')
plt.show()
But it results in a following error:
Traceback (most recent call last):
File "C:\Users\ ... \np_matrices_v1.py", line 46, in <module>
x[:, k+1] = np.dot(Ad, x[:, k]) + Bd*u[k]
ValueError: could not broadcast input array from shape (2,2) into shape (2,)
I don't know why, but if you try:
A = np.array([[1, 2], [2, 3]])
x = np.array([[0.5], [2.0]])
y = A.dot(x)
print(y)
xa = np.zeros((2, 10))
xa[:, 2] = A.dot(x)
You'll get:
Traceback (most recent call last):
File "C:\Users\eletr\.spyder-py3\temp.py", line 19, in <module>
xa[:, 2] = A.dot(x)
ValueError: could not broadcast input array from shape (2,1) into shape (2,)
But if you do:
import numpy as np
A = np.array([[1, 2], [2, 3]])
x = np.array([[0.5], [2.0]])
y = A.dot(x)
print(y)
xa = np.zeros((2, 10))
# xa[:, 2] = A.dot(x)
xa[:, [2]] = A.dot(x)
print(xa)
You'll get the correct answer:
[[4.5]
[7. ]]
[[0. 0. 4.5 0. 0. 0. 0. 0. 0. 0. ]
[0. 0. 7. 0. 0. 0. 0. 0. 0. 0. ]]
Can anyone explain it?
In [248]: A = np.array([[1, 2], [2, 3]])
...: x = np.array([[0.5], [2.0]])
In [249]: A.shape, x.shape
Out[249]: ((2, 2), (2, 1))
In [250]: y = A.dot(x)
In [251]: y.shape
Out[251]: (2, 1)
Note the shapes. x is (2,1), and as a result y is too. y can be assigned to a (2,1) slot, but not a (2,) shape.
In [252]: xa = np.zeros((2,5),int)
In [253]: xa
Out[253]:
array([[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]])
In [254]: xa[:,2]
Out[254]: array([0, 0]) # (2,) shape
In [255]: xa[:,[2]]
Out[255]:
array([[0], # (2,1) shape
[0]])
In contrast to MATLAB numpy arrays can be 1d, e.g. (2,). Also leading dimensions are the outermost, as opposed to trailing. MATLAB readily reduces a (2,3,1) shape to (2,3), but a (2,1,1) only becomes (2,1).
broadcasting the way numpy uses arrays that can differ in shape. The two basic rules are that
- leading size 1 dimensions can added automatically to match
- size 1 dimensions can be adjusted to match
Thus a (2,) can become a (1,2).
If you remove the inner [] from x, you get a 1d array:
In [256]: x = np.array([0.5, 2.0])
In [257]: x.shape
Out[257]: (2,)
In [258]: A.dot(x)
Out[258]: array([4.5, 7. ]) # (2,) shape
This can then be assigned to a row of xa: xa[:,2] = A.dot(x)
reshape and ravel can be used to remove dimensions. Also indexing A.dot(x)[:,0]

Add in-between steps into array of numbers (Python)

I am looking for some function that takes an input array of numbers and adds steps (range) between these numbers. I need to specify the length of the output's array.
Example:
input_array = [1, 2, 5, 4]
output_array = do_something(input_array, output_length=10)
Result:
output_array => [1, 1.3, 1.6, 2, 3, 4, 5, 4.6, 4.3, 4]
len(output_array) => 10
Is there something like that, in Numpy for example?
I have a prototype of this function that uses dividing input array into pairs ([0,2], [2,5], [5,8]) and filling "spaces" between with np.linspace() but it don't work well: https://onecompiler.com/python/3xwcy3y7d
def do_something(input_array, output_length):
import math
import numpy as np
output = []
in_between_steps = math.ceil(output_length/len(input_array))
prev_num = None
for num in input_array:
if prev_num is not None:
for in_num in np.linspace(start=prev_num, stop=num, num=in_between_steps, endpoint=False):
output.append(in_num)
prev_num = num
output.append(input_array[len(input_array)-1]) # manually add last item
return output
How it works:
input_array = [1, 2, 5, 4]
print(len(do_something(input_array, output_length=10))) # result: 10 OK
print(len(do_something(input_array, output_length=20))) # result: 16 NOT OK
print(len(do_something(input_array, output_length=200))) # result: 151 NOT OK
I have an array [1, 2, 5, 4] and I need to "expand" a number of items in it but preserve the "shape":
There is numpy.interp which might be what you are looking for.
import numpy as np
points = np.arange(4)
values = np.array([1,2,5,4])
x = np.linspace(0, 3, num=10)
np.interp(x, points, values)
output:
array([1. , 1.33333333, 1.66666667, 2. , 3. ,
4. , 5. , 4.66666667, 4.33333333, 4. ])

Multiple arguments with function and scipy

Following code needs to be optimized and minimised with respect to x by using scipy optimizer.
The issue is it works with single argument but when function is taken multiple values, it can't handle it.
This code works well.
from scipy.optimize import root
b = 1
def func(x):
# result when x = 0, but result equation depends also on b value.
result = x + b
return result
sol = root(func, 0.1)
print(sol.x, sol.fun)
But this is not working.....
b =[ 1, 2, 3, 4, 5]
def func(x, b):
# result when x = 0, but result equation depends also on b value.
result = x + b
return result
for B in b:
sol = root(lambda x,B: func(x, B), 0.1)
print(sol.x, sol.fun)
How can result obtain with iteration through b?
As #hpaulj mentioned, root accepts an args parameter that will be passed onto func. So, we can make the script more flexible:
from scipy.optimize import root
def func(x, *args):
result = 0
for i, a in enumerate(args):
result += a * x ** i
return result
coeff_list = [(6, 3), (-3, 2, 1), (-6, 1, 2)]
for coeffs in coeff_list:
sol = root(func, [-4, 4][:len(coeffs)-1], args = coeffs)
print(*coeffs, sol.x, sol.fun)
Output:
6 3 [-2.] [8.8817842e-16]
-3 2 1 [-3. 1.] [ 1.46966528e-09 -4.00870892e-10]
-6 1 2 [-2. 1.5] [-6.83897383e-14 4.97379915e-14]
Initial answer
I don't understand the need for your lambda function:
from scipy.optimize import root
def func(x):
# result when x = 0, but result equation depends also on b value.
result = x + b
return result
B =[ 1, 2, 3, 4, 5]
for b in B:
sol = root(func, 0.1)
print(b, sol.x, sol.fun)
Output:
1 [-1.] [0.]
2 [-2.] [0.]
3 [-3.] [0.]
4 [-4.] [0.]
5 [-5.] [0.]
I don't see in the scipy documentation any hint of how to pass parameters to func. But this approach also works for multiple parameters:
from scipy.optimize import root
def func(x):
#depending on the parameters, this has 0, 1 or 2 solutions
result = a * x ** 2 + b * x + c
return result
A = range(3)
B = [3, 2, 1]
C = [6, -3, -6]
for a, b, c in zip(A, B, C):
sol = root(func, [-4, 4])
print(a, b, c, sol.x, sol.fun)
Output:
0 3 6 [-2. -2.] [ 8.8817842e-16 0.0000000e+00]
1 2 -3 [-3. 1.] [ 1.46966528e-09 -4.00870892e-10]
2 1 -6 [-2. 1.5] [-6.83897383e-14 4.97379915e-14]

In the third dimension of a numpy array, multiply the first three values by the fourth one

Here is a 3-dimensional numpy array:
import numpy as np
m = np.array([
[
[1,2,3,2], [4,5,6,3]
],
[
[7,8,9,4], [1,2,3,5]
]
])
For each tuple, I need to multiply the first three values by the last one (divided by 10 and rounded), and then to keep only the 3 results. For example in [1,2,3,2]:
The 1 becomes: round(1 * 2 / 10) = 0
The 2 becomes: round(2 * 2 / 10) = 0
The 3 becomes: round(3 * 2 / 10) = 1
So, [1,2,3,2] becomes: [0,0,1].
And the complete result will be:
[
[
[0,0,1], [1,2,2]
],
[
[3,3,4], [1,1,2]
]
]
I tried to separate the last value of each tuple in a alpha variable, and the 3 first values in a rgb variable.
alpha = m[:, :, 3] / 10
rgb = m[:, :, :3]
But after that I'm a beginner in Python and I really don't know how to process these arrays.
A little help from an experienced Python-guy will be most welcome.
Try this
n = np.rint(m[:,:,:3] * m[:,:,[-1]] / 10).astype(int)
Out[192]:
array([[[0, 0, 1],
[1, 2, 2]],
[[3, 3, 4],
[0, 1, 2]]])

How do I overwrite a row vector in a numpy array?

I am trying to normalize each row vector of numpy array x, but I'm facing 2 problems.
I'm unable to update the row vectors of x (source code in image)
Is it possible to avoid the for loop (line 6) with any numpy functions?
import numpy as np
x = np.array([[0, 3, 4] , [1, 6, 4]])
c = x ** 2
for i in range(0, len(x)):
print(x[i]/np.sqrt(c[i].sum())) #prints [0. 0.6 0.8]
x[i] = x[i]/np.sqrt(c[i].sum())
print(x[i]) #prints [0 0 0]
print(x) #prints [[0 0 0] [0 0 0]] and wasn't updated
I've just recently started out with numpy, so any assistance would be greatly appreciated!
I'm unable to update the row vectors of x (source code in image)
Your np.array has no dtype argument, so it uses <type 'numpy.int32'>. If you wish to store floats in the array, add a float dtype:
x = np.array([
[0,3,4],
[1,6,4]
], dtype = np.float)
To see this, compare
x = np.array([
[0,3,4],
[1,6,4]
], dtype = np.float)
print type(x[0][0]) # output = <type 'numpy.float64'>
to
x = np.array([
[0,3,4],
[1,6,4]
])
print type(x[0][0]) # output = <type 'numpy.int32'>
is it possible to avoid the for loop (line 6) with any numpy functions?
This is how I would do it:
norm1, norm2 = np.linalg.norm(x[0]), np.linalg.norm(x[1])
print x[0] / norm1
print x[1] / norm2
You can use:
x/np.sqrt((x*x).sum(axis=1))[:, None]
Example:
In [9]: x = np.array([[0, 3, 4] , [1, 6, 4]])
In [10]: x/np.sqrt((x*x).sum(axis=1))[:, None]
Out[10]:
array([[0. , 0.6 , 0.8 ],
[0.13736056, 0.82416338, 0.54944226]])
For the first question:
x = np.array([[0,3,4],[1,6,4]],dtype=np.float32)
For the second question:
x/np.sqrt(np.sum(x**2,axis=1).reshape((len(x),1)))
Given 2-dimensional array
x = np.array([[0, 3, 4] , [1, 6, 4]])
Row-wise L2 norm of that array can be calculated with:
norm = np.linalg.norm(x, axis = 1)
print(norm)
[5. 7.28010989]
You can not divide array x of shape (2, 3) by norm of shape (2,), the following trick enables that by adding extra dimension to norm
# Divide by adding extra dimension
x = x / norm[:, None]
print(x)
[[0. 0.6 0.8 ]
[0.13736056 0.82416338 0.54944226]]
This solves both your questions

Categories

Resources