How to manipulate multidimensional numpy array in python - python

I am new with array in python, please help me.
I have a multidimensional numpy array like this:
array([[ 0., 2073., 2352., 1119., 2074., 1344., 4035., 1980., 2213.,
2363., 2655., 2322., 1148., 2046., 2234., 1076., 1647., 2957.,
1968., 2246., 1723.],
[1517., 0., 891., 1537., 1993., 2231., 2574., 689., 1561.,
2157., 1517., 3275., 1566., 757., 774., 2190., 822., 1355.,
2152., 1575., 1064.],
[1597., 1329., 0., 1617., 1106., 1345., 1951., 1551., 1938.,
1270., 629., 2320., 1646., 1619., 862., 2267., 1357., 934.,
1264., 687., 342.]])
I want to add 0 at the beginning in every array, and at the end i want to add 22 of 0 of array so it becomes like this:
array([[0., 0., 2073., 2352., 1119., 2074., 1344., 4035., 1980., 2213.,
2363., 2655., 2322., 1148., 2046., 2234., 1076., 1647., 2957.,
1968., 2246., 1723.],
[0.,1517., 0., 891., 1537., 1993., 2231., 2574., 689., 1561.,
2157., 1517., 3275., 1566., 757., 774., 2190., 822., 1355.,
2152., 1575., 1064.],
[0.,1597., 1329., 0., 1617., 1106., 1345., 1951., 1551., 1938.,
1270., 629., 2320., 1646., 1619., 862., 2267., 1357., 934.,
1264., 687., 342.],
[0.,0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0, 0., 0, 0., 0.,
0., 0., 0.]])
please help me to code this

If the array is arr then you can use:
np.pad(arr, ((0, 1), (1, 0)))

You can insert 0 at the beginning of every array and then append a list of 22 0.
import numpy as np
data = np.array([[0., 2073., 2352., 1119., 2074., 1344., 4035., 1980., 2213.,
2363., 2655., 2322., 1148., 2046., 2234., 1076., 1647.,
2957.,
1968., 2246., 1723.],
[1517., 0., 891., 1537., 1993., 2231., 2574., 689., 1561.,
2157., 1517., 3275., 1566., 757., 774., 2190., 822., 1355.,
2152., 1575., 1064.],
[1597., 1329., 0., 1617., 1106., 1345., 1951., 1551., 1938.,
1270., 629., 2320., 1646., 1619., 862., 2267., 1357., 934.,
1264., 687., 342.]])
updated = np.insert(data, 0, 0, axis=1)
updated = np.append(updated, [[0] * 22], axis=0)
print(updated)
Output:
[[ 0. 0. 2073. 2352. 1119. 2074. 1344. 4035. 1980. 2213. 2363. 2655.
2322. 1148. 2046. 2234. 1076. 1647. 2957. 1968. 2246. 1723.]
[ 0. 1517. 0. 891. 1537. 1993. 2231. 2574. 689. 1561. 2157. 1517.
3275. 1566. 757. 774. 2190. 822. 1355. 2152. 1575. 1064.]
[ 0. 1597. 1329. 0. 1617. 1106. 1345. 1951. 1551. 1938. 1270. 629.
2320. 1646. 1619. 862. 2267. 1357. 934. 1264. 687. 342.]
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]
Explanation:
We have inserted in axis 1 to add 0 in the existing multidimensional array.
We have appended the list of 22 0's to axis 0 at the end.
References:
Numpy documentation on insert method
Numpy documentation on append method

Related

CV2 Distance with projectPoints

is it possible to calculate the distance between points which i created with cv2.projectPoints?
I have two aruco markers and from both markers i have created (with cv2.projectPoints) points which are in a specific distance to the marker. Now i want to know how far these points are away from each other?
I know you cant give a specific code without an MVP and it is not necessary i only need an idea how this is possible to calculate. I would be awesome if someone knows maybe a cv2 function or a way to calculate these?
Thank you very much <3
Edit:
I generated the four identity matrixes and inversed all of them. Code and result ist below.
#T_point1_marker1 = np.linalg.inv(T_marker1_point1)
#T_marker1_cam = np.linalg.inv(T_cam_marker1)
T_point1_marker1 = np.array([
[ 1., 0., 0., -0.1 ],
[ 0., 1., 0., -0.05],
[ 0., 0., 1., 0. ],
[ 0., 0., 0., 1. ],
])
T_marker1_cam = np.array([
[ 1., 0., 0., 0.10809129],
[ 0., 1., 0., 0.03833054],
[ 0., 0., 1., -0.35931477],
[ 0., 0., 0., 1. ],
])
T_cam_marker2 = np.array([
[ 1., 0., 0., 0.09360527],
[ 0., 1., 0., -0.01229168],
[ 0., 0., 1., 0.36470099],
[ 0., 0., 0., 1. ],
])
T_marker2_point2 = np.array([
[ 1., 0., 0., 0.005],
[ 0., 1., 0., 0.1 ],
[ 0., 0., 1., 0. ],
[ 0., 0., 0., 1. ],
])
#Process finished with exit code 1
The think i don't understand is this part:
T_point1_point2 = T_point1_marker1 # T_marker1_cam # T_cam_marker2 # T_marker2_point2
How do i bring these four matrixes together so i get T_point1_point2?
Thanks again :)
Since your graphic contains measurements of physical distance, rather than pixels, I'll assume you're asking about 3D, i.e. you want a 3D distance between those points...
You just need to define the poses of those points, relative to their markers. That is T_marker1_point1 and T_marker2_point2. Make those be pure translation, probably with Z=0 if these points are in each respective marker's plane. Literally make a 4x4 identity matrix, then stick your nominal (constructed) dimensions into the last column.
Then you need the marker poses relative to the camera, T_cam_marker1 and T_cam_marker2.
Finally you calculate
T_point1_point2 = T_point1_marker1 # T_marker1_cam # T_cam_marker2 # T_marker2_point2
# where
# T_marker1_cam = np.linalg.inv(T_cam_marker1)
# and so on
The translation part of that pose matrix gives you the distance between those points. You can ignore the rotation component. That'd only give you the rotation between those markers, because your points were defined as poses of the same orientation as their respective markers. Yes, orientation is silly for points but eh...
All of that is 4x4 matrices. Compose from tvec, put in third column, and rvec, turned into a 3x3 rotation matrix using cv.Rodrigues. Decompose 4x4 matrix into rvec and tvec accordingly (Rodrigues goes both ways).

Replace values in ndarray with condirion

I need to change values in ndarray: if > 0.5 then 1, less - then 0. Example:
array([ 0.11865984, 0.49666225, 0.134077 , 0.09502114, 0.70667432,
0.1648032 , 0.6356094 , 0.36054945, 0.68379407, 0.09297716])
You can try something like
import numpy as np
arr = np.array([ 0.11865984, 0.49666225, 0.134077 , 0.09502114, 0.70667432,
0.1648032 , 0.6356094 , 0.36054945, 0.68379407, 0.09297716])
bool_condition_array = arr > 0.5
binary_array = bool_condition_array.astype(int)
Evenly round to the given number of decimals. np.around
If you have an np.array you can use np.around function:
import numpy as np
arr = np.array([ 0.11865984, 0.49666225, 0.134077 , 0.09502114, 0.70667432,
0.1648032 , 0.6356094 , 0.36054945, 0.68379407, 0.09297716])
result = np.around(arr)
print(result)
# array([0., 0., 0., 0., 1., 0., 1., 0., 1., 0.])

Numpy largest singular value larger than greatest eigenvalue

Let
import numpy as np
M = np.array([[ 1., -0.5301332 , 0.80512845],
[ 0., 0., 0.],
[ 0., 0., 0.]])
M is rank one, its only non zero eigenvalue is 1 (its trace). However np.linalg.norm(M, ord=2) returns 1.39 which is strictly greater than 1. Why?
The eigenvalues of M, returned by np.linalg.eigvals are 1, 0, 0, but the singular values of M are 1.39, 0, 0, which is a surprise to me. What did I miss?
In this particular case the 2-norm of M coincides with the Frobenius norm, which is given by the formula (np.sum(np.abs(M**2)))**(1/2), therefore we can see that:
import numpy as np
M = np.array([[ 1., -0.5301332 , 0.80512845],
[ 0., 0., 0.],
[ 0., 0., 0.]])
np.sqrt(np.sum(np.abs(M**2)))
1.388982732341062
np.sqrt(np.sum(np.abs(M**2))) == np.linalg.norm(M,ord=2) == np.linalg.norm(M, ord='fro')
True
In particular one can prove that the 2-norm is the square root of the largest eigenvalue of M.T#M i.e.
np.sqrt(np.linalg.eigvals(M.T#M)[0])
1.388982732341062
And this is its relation with eigenvalues of a matrix. Now recall that the singular values are the square root of the eigenvalues of M.T#M and we unpack the mistery.
Using a characterization of the Frobenius norm (square root of the sum of the trace of M.T#M):
np.sqrt(np.sum(np.diag(M.T#M)))
1.388982732341062
Confronting the results:
np.sqrt(np.linalg.eigvals(M.T#M)[0]) == np.sqrt(np.sum(np.diag(M.T#M))) == np.linalg.svd(M)[1][0]
True
second norm of a matrix the square root of the sum of all elements squared
norm(M, ord=2) = (1.**2 + 0.5301332**2 + 0.80512845**2)**0.5 = 1.39
to get the relation between the eigen values and singular values you need to calculate the eigen values of M^H.M and square root it
eigV = np.linalg.eigvals(M.T.dot(M))
array([1.92927303, 0. , 0. ])
eigV**0.5
array([1.38898273, 0. , 0. ])
This is perfectly normal. In the general case, the singular values are not equals to the eigen values. This is true only for positive Hermitian matrices.
For squared matrices, you have the following relationship:
M = np.matrix([[ 1., -0.5301332 , 0.80512845],
[ 0., 0., 0.],
[ 0., 0., 0.]])
u, v= np.linalg.eig(M.H # M) # M.H # M is Hermitian
print(np.sqrt(u)) # [1.38898273 0. 0. ]
u,s,v = lin.svd(M)
print(s) # [1.38898273 0. 0. ]

scikit learn LDA giving unexpected results

I am attempting to classify some data with the scikit learn LDA classifier. I'm not entirely sure what to "expect" from it, but what I am getting is weird. Seems like a good opportunity to learn about either a shortcoming of the technique, or a way in which I am applying it wrong. I understand that no line could completely separate this data, but it seems that there are much "better" lines than the one it is finding. I'm just using the default options. Any thoughts on how to do this better? I'm using LDA because it is linear in the size of my dataset. Although I think a linear SVM has a similar complexity. Perhaps it would be better for such data? I will update when I have tested other possibilities.
The picture: (light blue is what my LDA classifier predicts will be dark blue)
The code:
import numpy as np
from numpy import array
import matplotlib.pyplot as plt
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
import itertools
X = array([[ 0.23125754, 0.79170351],
[ 0.78021491, -0.24999486],
[ 0.00856446, 0.41452734],
[ 0.66381753, -0.09872504],
[-0.03178685, 0.04876317],
[ 0.65574645, -0.68214948],
[ 0.14290684, 0.38256002],
[ 0.05156987, 0.11094875],
[ 0.06843403, 0.19110019],
[ 0.24070898, -0.07403764],
[ 0.03184353, 0.4411446 ],
[ 0.58708124, -0.38838008],
[-0.00700369, 0.07540799],
[-0.01907816, 0.07641038],
[ 0.30778608, 0.30317186],
[ 0.55774143, -0.38017325],
[-0.00957214, -0.03303287],
[ 0.8410637 , 0.158594 ],
[-0.00294113, -0.00380608],
[ 0.26577841, 0.07833684],
[-0.32249375, 0.49290502],
[ 0.11313078, 0.35697211],
[ 0.41153679, -0.4471876 ],
[-0.00313315, 0.30065913],
[ 0.14344143, -0.19127107],
[ 0.04857767, 0.01339191],
[ 0.5865007 , 0.71209886],
[ 0.08157439, 0.40909955],
[ 0.72495202, 0.29583866],
[-0.09391461, 0.17976605],
[ 0.06149141, 0.79323099],
[ 0.52208024, -0.2877661 ],
[ 0.01992141, -0.00435266],
[ 0.68492617, -0.46981335],
[-0.00641231, 0.29699622],
[ 0.2369677 , 0.140319 ],
[ 0.6602586 , 0.11200433],
[ 0.25311836, -0.03085372],
[-0.0895014 , 0.45147252],
[-0.18485667, 0.43744524],
[ 0.94636701, 0.16534406],
[ 0.01887734, -0.07702135],
[ 0.91586801, 0.17693792],
[-0.18834833, 0.31944796],
[ 0.20468328, 0.07099982],
[-0.15506378, 0.94527383],
[-0.14560083, 0.72027034],
[-0.31037647, 0.81962815],
[ 0.01719756, -0.01802322],
[-0.08495304, 0.28148978],
[ 0.01487427, 0.07632112],
[ 0.65414479, 0.17391618],
[ 0.00626276, 0.01200355],
[ 0.43328095, -0.34016614],
[ 0.05728525, -0.05233956],
[ 0.61218382, 0.20922571],
[-0.69803697, 2.16018536],
[ 1.38616732, -1.86041621],
[-1.21724616, 2.72682759],
[-1.26584365, 1.80585403],
[ 1.67900048, -2.36561699],
[ 1.35537903, -1.60023078],
[-0.77289615, 2.67040114],
[ 1.62928969, -1.20851808],
[-0.95174264, 2.51515935],
[-1.61953649, 2.34420531],
[ 1.38580104, -1.9908369 ],
[ 1.53224512, -1.96537012]])
y = array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
1., 1., 1.])
classifier = LDA()
classifier.fit(X,y)
xx = np.array(list(itertools.product(np.linspace(-4,4,300), np.linspace(-4,4,300))))
yy = classifier.predict(xx)
b_colors = ['salmon' if yyy==0 else 'deepskyblue' for yyy in yy]
p_colors = ['r' if yyy==0 else 'b' for yyy in y]
plt.scatter(xx[:,0],xx[:,1],s=1,marker='o',edgecolor=b_colors,c=b_colors)
plt.scatter(X[:,0], X[:,1], marker='o', s=5, c=p_colors, edgecolor=p_colors)
plt.show()
UPDATE: Changing from using sklearn.discriminant_analysis.LinearDiscriminantAnalysis to sklearn.svm.LinearSVC also using the default options gives the following picture:
I think using the zero-one loss instead of the hinge loss would help, but sklearn.svm.LinearSVC doesn't seem to allow custom loss functions.
UPDATE: The loss function to sklearn.svm.LinearSVC approaches the zero-one loss as the parameter C goes to infinity. Setting C = 1000 gives me what I was originally hoping for. Not posting this as an answer, because the original question was about LDA.
picture:
LDA models each class as a Gaussian, so the model for each class is determined by the class' estimated mean vector and covariance matrix.
Judging by the eye only, your blue and red classes have approximately the same mean and same covariance, which means the 2 Gaussians will 'sit' on top of each other, and the discrimination will be poor. Actually it also means that the separator (the blue-pink border) will be noisy, that is it will change a lot between random samples of your data.
Btw your data is clearly not linearly-separable, so every linear model will have a hard time discriminating the data.
If you must use a linear model, try using LDA with 3 components, such that the top-left blue blob is classified as '0', the bottom-right blue blob as '1', and the red as '2'. This way you will get a much better linear model. You can do it by preprocessing the blue class with a clustering algorithm with K=2 classes.

Matrix function in conjugate gradient module

I am solving simply linear problem A*x=b by using conjugate gradient method. I want to find x unknown.
Note that conjGrad calls the function Av that returns the product Av
The code is given below:
Inputs:
A - sparse matrix. 2D array;
b - right hand-side vector. 1D array;
x - initial guess. Here, it is just 1D array with zero values.
Code:
import numpy as np
import math
A = np.array([[ 0.56244579, 0. , 0. , 0. , 0.52936075,
0.59553084, 0. , 0. , 0. , 1.1248915 ,
0. , 0. , 0. , 0.46319065, 0.43672262,
0. ],
[ 0.5 , 1. , 1. , 0.5 , 0. ,
0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. ,
0. ],
[ 0. , 0. , 0. , 0.58009067, 0. ,
0. , 0.75411788, 0.40606347, 0. , 0. ,
0.23203627, 0. , 0. , 0. , 0. ,
0. ]])
x = np.array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0.])
b = np.array([ 3.99464617, 1.81663614, 1.86413003])
def Av(v):
return np.dot(A,v)
def conjGrad(Av, x, b, tol=1.0e-9):
n = len(b)
r = b - Av(x)
s = r.copy()
for i in range(n):
u = Av(s)
alpha = np.dot(s,r)/np.dot(s,u)
x = x + aplha*s
r = b - Av(x)
if(math.sqrt(np.dot(r,r))) < tol:
break
else:
beta = - np.dot(r,u)/np.dot(s,u)
s = r + beta * s
return x,i
if __name__ == '__main__':
x, iter_number = conjGrad(Av, x, b)
Traceback (most recent call last):
File "C:\Python27\Conjugate_Gradient.py", line 59, in <module>
x, iter_number = conjGrad(Av, x, b)
File "C:\Python27\Conjugate_Gradient.py", line 47, in conjGrad
u = Av(s)
File "C:\Python27\Conjugate_Gradient.py", line 40, in Av
return np.dot(A,v)
ValueError: matrices are not aligned
Is there any simple solution to avoid this message? Any answers will be appreciated
You have implemented the CG method wrong. The error message shows you one of the lines where there is a problem.
In particular, your matrix is not square.
The conjugate gradients method solves for Ax=b when A is SPD.
If A is not SPD, like in your case, then you can still use conjugate gradients to find the least squares solution for your problem:
A^t A x = A^t b
The matrix A^t A is SPD and well suited for your method.

Categories