I am trying to perform operations on specific elements within a 3d array in python. Here is an example of the array:
[[[ 0.5 0.5 50. ]
[ 50.5 50.5 100. ]
[ 0.5 100.5 50. ]
[ 135. 90. 45. ]]
[[ 50.5 50.5 100. ]
[ 100.5 0.5 50. ]
[ 100.5 100.5 50. ]
[ 45. 90. 45. ]]
[[ 100.5 100.5 50. ]
[ 100.5 100.5 0. ]
[ 0.5 100.5 50. ]
[ 90. 0. 90. ]]
An example of what I need to to is take the three values seen in the array i.e. 0.5, 0.5, 50. and take the first element from the 4th row i.e. 135. and send those four elements into a function. the function then returns new values for the 3 elements which need to be put into the array.
I am quite new to python so I'm having trouble getting it to work. Should I be making a loop? or something else?
Thanks
Nick
An attempt at a solution:
b = shape(a)
triangles = b[0]
for k in range(0,triangles):
for i in range(0,2):
a[k,i,:] = VectMath.rotate_x(a[k,i,0],a[k,i,1],a[k,i,2],a[k,3,2])
You can make your VectMath.rotate_x function to rotate an array of vector, then by using slice to get & put data in a:
a = np.array(
[[[ 0.5, 0.5, 50., ],
[ 50.5, 50.5, 100., ],
[ 0.5, 100.5, 50., ],
[ 135. , 90. , 45., ]],
[[ 50.5, 50.5, 100., ],
[ 100.5, 0.5, 50., ],
[ 100.5, 100.5, 50., ],
[ 45. , 90. , 45., ]],
[[ 100.5, 100.5, 50., ],
[ 100.5, 100.5, 0., ],
[ 0.5, 100.5, 50., ],
[ 90. , 0. , 90., ]]])
def rotate_x(v, deg):
r = np.deg2rad(deg)
c = np.cos(r)
s = np.sin(r)
m = np.array([[1, 0, 0],
[0, c,-s],
[0, s, c]])
return np.dot(m, v)
vectors = a[:, :-1, :]
angles = a[:, -1, 0]
for i, (vec, angle) in enumerate(zip(vectors, angles)):
vec_rx = rotate_x(vec.T, angle).T
a[i, :-1, :] = vec_rx
print a
output:
[[[ 5.00000000e-01 -3.57088924e+01 -3.50017857e+01]
[ 5.05000000e+01 -1.06419571e+02 -3.50017857e+01]
[ 5.00000000e-01 -1.06419571e+02 3.57088924e+01]
[ 1.35000000e+02 9.00000000e+01 4.50000000e+01]]
[[ 5.05000000e+01 -3.50017857e+01 1.06419571e+02]
[ 1.00500000e+02 -3.50017857e+01 3.57088924e+01]
[ 1.00500000e+02 3.57088924e+01 1.06419571e+02]
[ 4.50000000e+01 9.00000000e+01 4.50000000e+01]]
[[ 1.00500000e+02 -5.00000000e+01 1.00500000e+02]
[ 1.00500000e+02 6.15385017e-15 1.00500000e+02]
[ 5.00000000e-01 -5.00000000e+01 1.00500000e+02]
[ 9.00000000e+01 0.00000000e+00 9.00000000e+01]]]
If there are many triangle, it maybe faster if we can rotate all the vectors without python for loop.
Here I do the rotate calculation by expand the matrix product:
x' = x
y' = cos(t)*y - sin(t)*z
z' = sin(t)*y + cos(t)*z
So we can vectorize these formulas:
a2 = np.array(
[[[ 0.5, 0.5, 50., ],
[ 50.5, 50.5, 100., ],
[ 0.5, 100.5, 50., ],
[ 135. , 90. , 45., ]],
[[ 50.5, 50.5, 100., ],
[ 100.5, 0.5, 50., ],
[ 100.5, 100.5, 50., ],
[ 45. , 90. , 45., ]],
[[ 100.5, 100.5, 50., ],
[ 100.5, 100.5, 0., ],
[ 0.5, 100.5, 50., ],
[ 90. , 0. , 90., ]]])
vectors = a2[:, :-1, :]
angles = a2[:, -1:, 0]
def rotate_x_batch(vectors, angles):
rad = np.deg2rad(angles)
c = np.cos(rad)
s = np.sin(rad)
x = vectors[:, :, 0]
y = vectors[:, :, 1]
z = vectors[:, :, 2]
yr = c*y - s*z
zr = s*y + c*z
vectors[:, :, 1] = yr
vectors[:, :, 2] = zr
rotate_x_batch(vectors, angles)
print np.allclose(a, a2)
Related
I have a multiple .npy files and want to have them in one n-dimentional np.array
np.load(file) has shape (n, 3). There are m files, so result shape should be (m, n, 3)
Now i have this:
np.array([np.load(file) for file in h_files])
output:
array([array([[ 3.40040e+00, -1.48372e-02, -6.52934e-01],
[ 3.37660e+00, -1.53226e-02, -5.28748e-01],
[ 3.36828e+00, -1.58727e-02, -4.08290e-01],
...,
[ 3.35563e+00, -2.34267e-03, 2.89650e-01],
[ 3.35869e+00, -2.93101e-03, 1.74017e-01],
[ 3.36274e+00, -3.52146e-03, 5.80292e-02]], dtype=float32),
array([[ 3.40534 , -0.00772648, -0.653887 ],
[ 3.37169 , -0.0082386 , -0.527966 ],
[ 3.36334 , -0.00880522, -0.407682 ],
...,
What result i would like to have:
array( [[[ 3.40040e+00, -1.48372e-02, -6.52934e-01],
[ 3.37660e+00, -1.53226e-02, -5.28748e-01],
[ 3.36828e+00, -1.58727e-02, -4.08290e-01],
...,
[ 3.35563e+00, -2.34267e-03, 2.89650e-01],
[ 3.35869e+00, -2.93101e-03, 1.74017e-01],
[ 3.36274e+00, -3.52146e-03, 5.80292e-02]],
[[ 3.40534 , -0.00772648, -0.653887 ],
[ 3.37169 , -0.0082386 , -0.527966 ],
[ 3.36334 , -0.00880522, -0.407682 ],
...,
I have not checked it, but you could try the following:
np.array([np.load(file).tolist() for file in h_files])
I have point_coords ndarray:
point_coord_x = np.array([np.random.randint(low=-100, high=100) for i in range(40)])
point_coord_y = np.array([np.random.randint(low=-100, high=100) for i in range(40)])
point_coords = np.array([point_coord_x, point_coord_y]).transpose()
It looks like:
point_coords
array([[ 62, -31],
[ 49, 33],
[ -2, -86],
[ -29, 49],
...
I want to get a square matrix with distance between points.
How am I supposed to do it?
>>> from scipy.spatial import distance_matrix
>>> distance_matrix(point_coords, point_coords)
array([[ 0. , 149.21461054, 88.64536085, ..., 44.94441011, 24.73863375, 60.5309838 ],
[149.21461054, 0. , 122.64175472, ..., 136.47344064, 163.60012225, 201.07958623],
[ 88.64536085, 122.64175472, 0. , ..., 45.01110974, 113.35784049, 147.2752525 ],
...,
[ 44.94441011, 136.47344064, 45.01110974, ..., 0. , 69.57010852, 102.3132445 ],
[ 24.73863375, 163.60012225, 113.35784049, ..., 69.57010852, 0. , 38.62641583],
[ 60.5309838 , 201.07958623, 147.2752525 , ..., 102.3132445 , 38.62641583, 0. ]])
If only numpy is to be used:
np.linalg.norm(point_coords[:, None, :] - point_coords[None, :, :], axis=-1)
You can do it using solely Numpy:
Compute deltas by each coordinate (square matrices):
dx = point_coord_x[:, np.newaxis] - point_coord_x[np.newaxis, :]
dy = point_coord_y[:, np.newaxis] - point_coord_y[np.newaxis, :]
Then compute the distance array from these deltas:
result = np.sqrt(dx ** 2 + dy ** 2)
I have a 2D array and I want to delete a point out of it but suppose it's so big meaning I can't specify an index and just grab it and the values of the array are float
How can I delete this point? With a LOOP and WITHOUT LOOP?? the following is 2D array and I want to delete [ 32.9, 23.]
[[ 1. , -1.4],
[ -2.9, -1.5],
[ -3.6, -2. ],
[ 1.5, 1. ],
[ 24. , 11. ],
[ -1. , 1.4],
[ 2.9, 1.5],
[ 3.6, 2. ],
[ -1.5, -1. ],
[ -24. , -11. ],
[ 32.9, 23. ],
[-440. , 310. ]]
I tried this but doesn't work:
this_point = np.asarray([ 32.9, 23.])
[x for x in y if x == point]
del datapoints[this_point]
np.delete(datapoints,len(datapoints), axis=0)
for this_point in datapoints:
del this_point
when I do this, the this_point stays in after printing all points, what should I do?
Python can remove a list element by content, but numpy does only by index. So, use "where" to find the coordinates of the matching row:
import numpy as np
a = np.array([[ 1. , -1.4],
[ -2.9, -1.5],
[ -3.6, -2. ],
[ 1.5, 1. ],
[ 24. , 11. ],
[ -1. , 1.4],
[ 2.9, 1.5],
[ 3.6, 2. ],
[ -1.5, -1. ],
[ -24. , -11. ],
[ 32.9, 23. ],
[-440. , 310. ]])
find = np.array([32.9,23.])
row = np.where( (a == find).all(axis=1))
print( row )
print(np.delete( a, row, axis=0 ) )
Output:
(array([10], dtype=int64),)
[[ 1. -1.4]
[ -2.9 -1.5]
[ -3.6 -2. ]
[ 1.5 1. ]
[ 24. 11. ]
[ -1. 1.4]
[ 2.9 1.5]
[ 3.6 2. ]
[ -1.5 -1. ]
[ -24. -11. ]
[-440. 310. ]]
C:\tmp>
I am wondering why np.dot(U,SV) != np.dot(A,B) when I believe A=U and B=SV, even though I manually key in the entries of A and B while using SVD to recover the matrices U and SV. The code below reproduces the oddity.
import numpy
from numpy.linalg import svd
In [121]: fullSet = np.array([[100,50,50],[50,100,100],[20,130,130],[50,100,100]])
In [122]: print fullSet
[[100 50 50]
[ 50 100 100]
[ 20 130 130]
[ 50 100 100]]
In [123]:
In [123]: U,s,V = svd(fullSet,full_matrices=True)
In [124]: print 'U'
U
In [125]: print U.round()
[[ 0. 1. -0. -0.]
[ 1. 0. 1. -0.]
[ 1. -0. -1. -0.]
[ 1. 0. 0. 1.]]
In [126]:
In [126]: S = np.zeros((U.shape[1],V.shape[0]))
In [127]: S[:s.shape[0],:s.shape[0]] = np.diag(s)
In [128]: print 'S'
S
In [129]: print S.round()
[[ 296. 0. 0.]
[ 0. 82. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
In [130]:
In [130]: print 'V'
V
In [131]: print V.round()
[[ 0. 1. 1.]
[ 1. -0. -0.]
[-0. 1. -1.]]
In [132]:
In [132]: print 'SV'
SV
In [133]: print np.dot(S,V).round()
[[ 97. 198. 198.]
[ 78. -19. -19.]
[ 0. 0. -0.]
[ 0. 0. 0.]]
In [134]: print 'SV'
SV
In [135]: print np.dot(S,V).round()
[[ 97. 198. 198.]
[ 78. -19. -19.]
[ 0. 0. -0.]
[ 0. 0. 0.]]
In [136]: print 'USV'
USV
In [137]: SV=np.dot(S,V)
In [138]: print np.dot(U,SV)
[[ 100. 50. 50.]
[ 50. 100. 100.]
[ 20. 130. 130.]
[ 50. 100. 100.]]
In [139]:
In [139]:
In [139]: A = np.array([[0,1,0,0],[1,0,-1,0],[1,0,1,0],[1,0,0,1]])
In [140]: B = np.array([[97,198,198],[78,-19,-19],[0,0,0],[0,0,0]])
In [141]: print "A"
A
In [142]: print A
[[ 0 1 0 0]
[ 1 0 -1 0]
[ 1 0 1 0]
[ 1 0 0 1]]
In [143]: print "B"
B
In [144]: print B
[[ 97 198 198]
[ 78 -19 -19]
[ 0 0 0]
[ 0 0 0]]
In [145]: print "AdotB"
AdotB
In [146]: print np.dot(A,B)
[[ 78 -19 -19]
[ 97 198 198]
[ 97 198 198]
[ 97 198 198]]
In [147]: print np.allclose(A,U.round())
False
In [148]: print np.allclose(B,SV.round())
True
In [149]: print A[0,0]
0
In [150]: print U[0,0]
0.33656051104
Recreating your U and SV:
In [627]: U
Out[627]:
array([[ -3.36560511e-01, 8.66235179e-01, -3.69274473e-01,
-4.61618492e-16],
[ -5.07358551e-01, 1.27694290e-02, 4.92365964e-01,
-7.07106781e-01],
[ -6.09837375e-01, -4.99310021e-01, -6.15457455e-01,
-1.06278764e-15],
[ -5.07358551e-01, 1.27694290e-02, 4.92365964e-01,
7.07106781e-01]])
In [628]: SV
Out[628]:
array([[ -9.65886537e+01, -1.97578594e+02, -1.97578594e+02],
[ 7.79142604e+01, -1.90446580e+01, -1.90446580e+01],
[ 0.00000000e+00, 4.63542263e-15, -4.63542263e-15],
[ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00]])
In [629]: np.dot(U,SV)
Out[629]:
array([[ 100., 50., 50.],
[ 50., 100., 100.],
[ 20., 130., 130.],
[ 50., 100., 100.]])
The dot with the rounded values does not produce the same result:
In [630]: np.dot(U.round(),SV.round())
Out[630]:
array([[ 78., -19., -19.],
[ 97., 198., 198.],
[ 97., 198., 198.],
[ 97., 198., 198.]])
The full float values of U and SV make a significant difference. Remember a dot is the sum of products - and these are
I have a two column numpy array. I want to go through each row of the 2nd column, and take the difference between each set of 2 numbers (9.6-0, 19.13-9.6, etc). If the difference is > 15, I want to insert a row of 0s for both columns. I really only need to end up with values in the first column (I only need the second to determine where to put 0s), so if it's easier to split them up that would be fine.
This is my input array:
[[0.00 0.00]
[1.85 9.60]
[2.73 19.13]
[0.30 28.70]
[2.64 38.25]
[2.29 47.77]
[2.01 57.28]
[2.61 66.82]
[2.20 76.33]
[2.49 85.85]
[2.55 104.90]
[2.65 114.47]
[1.79 123.98]
[2.86 133.55]]
and it should turn into:
[[0.00 0.00]
[1.85 9.60]
[2.73 19.13]
[0.30 28.70]
[2.64 38.25]
[2.29 47.77]
[2.01 57.28]
[2.61 66.82]
[2.20 76.33]
[2.49 85.85]
[0.00 0.00]
[2.55 104.90]
[2.65 114.47]
[1.79 123.98]
[2.86 133.55]]
You can do in a one liner using ediff1d , argmax and insert from numpy:
np.insert(arr, np.argmax(np.append(False, np.ediff1d(arr[:,1])>15)), 0, axis=0)
#array([[ 0. , 0. ],
# [ 1.85, 9.6 ],
# [ 2.73, 19.13],
# [ 0.3 , 28.7 ],
# [ 2.64, 38.25],
# [ 2.29, 47.77],
# [ 2.01, 57.28],
# [ 2.61, 66.82],
# [ 2.2 , 76.33],
# [ 2.49, 85.85],
# [ 0. , 0. ],
# [ 2.55, 104.9 ],
# [ 2.65, 114.47],
# [ 1.79, 123.98],
# [ 2.86, 133.55]])
Assuming A as the input array, here's a vectorized approach based on initialization with zeros -
# Get indices at which such diff>15 occur
cut_idx = np.where(np.diff(A[:,1]) > 15)[0]
# Initiaize output array
out = np.zeros((A.shape[0]+len(cut_idx),2),dtype=A.dtype)
# Get row indices in the output array at which rows from A are to be inserted.
# In other words, avoid rows to be kept as zeros. Finally, insert rows from A.
idx = ~np.in1d(np.arange(out.shape[0]),cut_idx + np.arange(1,len(cut_idx)+1))
out[idx] = A
Sample input, output -
In [50]: A # Different from the one posted in question to show variety
Out[50]:
array([[ 0. , 0. ],
[ 1.85, 0.6 ],
[ 2.73, 19.13],
[ 2.2 , 76.33],
[ 2.49, 85.85],
[ 2.55, 104.9 ],
[ 2.65, 114.47],
[ 1.79, 163.98],
[ 2.86, 169.55]])
In [51]: out
Out[51]:
array([[ 0. , 0. ],
[ 1.85, 0.6 ],
[ 0. , 0. ],
[ 2.73, 19.13],
[ 0. , 0. ],
[ 2.2 , 76.33],
[ 2.49, 85.85],
[ 0. , 0. ],
[ 2.55, 104.9 ],
[ 2.65, 114.47],
[ 0. , 0. ],
[ 1.79, 163.98],
[ 2.86, 169.55]])
a=[[0.00, 0.00],
[1.85, 9.60],
[2.73, 19.13],
[0.30, 28.70],
[2.64, 38.25],
[2.29, 47.77],
[2.01, 57.28],
[2.61, 66.82],
[2.20, 76.33],
[2.49, 85.85],
[2.55, 104.90],
[2.65, 114.47],
[1.79, 123.98],
[2.86, 133.55]]
i=0
while i <len(a)-1:
if (a[i+1][1]-a[i][1])>15:
a.insert(i+1,[0,0])
i=i+1
i=i+1
for line in a :
print line
output:
[0.0, 0.0]
[1.85, 9.6]
[2.73, 19.13]
[0.3, 28.7]
[2.64, 38.25]
[2.29, 47.77]
[2.01, 57.28]
[2.61, 66.82]
[2.2, 76.33]
[2.49, 85.85]
[0, 0]
[2.55, 104.9]
[2.65, 114.47]
[1.79, 123.98]
[2.86, 133.55]
Here's right algorithm:
arr = [ ... ]
result = []
result.append(arr[0])
for i in range(1, len(arr)):
if arr[i][1] - arr[i-1][1] > 15:
result.append([0.0,0.0])
result.append(arr[i])
print(result)
A one liner that can handle more than one fill slot. Here I'm testing it on the OP example, with one modified value.
In [70]: np.insert(a, np.where(np.diff(a[:,1])>15)[0]+2,0, axis=0)
In [71]: Out[70]:
array([[ 0. , 0. ],
[ 1.85, 9.6 ],
[ 2.73, 19.13],
[ 0.3 , 28.7 ],
[ 2.64, 38.25],
[ 2.29, 140. ], # modified
[ 0. , 0. ],
[ 2.01, 57.28],
[ 2.61, 66.82],
[ 2.2 , 76.33],
[ 2.49, 85.85],
[ 2.55, 104.9 ],
[ 0. , 0. ],
[ 2.65, 114.47],
[ 1.79, 123.98],
[ 2.86, 133.55]])
The use of where instead of argmax (Colonel's answer) handles more than one slot. The +2 is required because diff is one short, and we are inserting after. ediff1d has more options for handling the end points.
np.insert has various strategies for filling. In this case it probably is doing something similar to Divakar's answer - create an out, and copy values to the correct slots.
Another answer uses np.abs(). That might be needed, but in my example that would add another 0 row, after the 140 drops back to 57.
I'd be surprised if numpy didn't have some native methods for doing this sort of thing but I think this will work too:
i = 1
while i < len(lst):
if abs(lst[i][1] - lst[i-1][1]) > 15:
lst[i] = [0.0, 0.0]
# uncomment to change only the second column
# lst[i][1] = 0.0
i += 1
i += 1
Output:
>>> lst
array([[ 0. , 0. ],
[ 1.85, 9.6 ],
[ 2.73, 19.13],
[ 0.3 , 28.7 ],
[ 2.64, 38.25],
[ 2.29, 47.77],
[ 2.01, 57.28],
[ 2.61, 66.82],
[ 2.2 , 76.33],
[ 2.49, 85.85],
[ 2.55, 104.9 ],
[ 2.65, 114.47],
[ 1.79, 123.98],
[ 2.86, 133.55]])
>>>
>>> i = 1
>>> while i < len(lst):
... if abs(lst[i][1] - lst[i-1][1]) > 15:
... lst[i] = [0.0, 0.0]
... i += 1
... i += 1
...
>>> lst
array([[ 0. , 0. ],
[ 1.85, 9.6 ],
[ 2.73, 19.13],
[ 0.3 , 28.7 ],
[ 2.64, 38.25],
[ 2.29, 47.77],
[ 2.01, 57.28],
[ 2.61, 66.82],
[ 2.2 , 76.33],
[ 2.49, 85.85],
[ 0. , 0. ],
[ 2.65, 114.47],
[ 1.79, 123.98],
[ 2.86, 133.55]])
>>>