Prepending 1d array onto each 2d array of a 3d array - python

Say I have the size (2,3,2) array a and the size (2) array b below.
import numpy as np
a = np.array([[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]]])
b = np.array([0.2, 0.8])
Array a looks like this:
I'd like to use numpy routines to concatenate b to the first row of each 2d arrray in a to make the array
I can't seem to make concatenate, vstack, append, etc. work.

Try this:
np.concatenate(([[b]]*2,a),axis=1)
# Result:
array([[[ 0.2, 0.8],
[ 1. , 2. ],
[ 3. , 4. ],
[ 5. , 6. ]],
[[ 0.2, 0.8],
[ 7. , 8. ],
[ 9. , 10. ],
[ 11. , 12. ]]])

This works:
np.insert(a.astype(float), 0, b, 1)
Output:
array([[[ 0.2, 0.8],
[ 1. , 2. ],
[ 3. , 4. ],
[ 5. , 6. ]],
[[ 0.2, 0.8],
[ 7. , 8. ],
[ 9. , 10. ],
[ 11. , 12. ]]])
If you don't cast with astype() first, you just end up prepending [0, 0]
Note, this is slower than the concatenate():
$ python test.py
m1: 8.20246601105 sec
m2: 43.8010189533 sec
Code:
#!/usr/bin/python
import numpy as np
import timeit
a = np.array([[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]]])
b = np.array([0.2, 0.8])
def m1():
np.concatenate(([[b]]*2,a),axis=1)
def m2():
np.insert(a.astype(float), 0, b, 1)
print "m1: %s sec" % timeit.timeit(m1)
print "m2: %s sec" % timeit.timeit(m2)

Related

Python3: Remove array elements with same coordinate (x,y)

I have this array (x,y,f(x,y)):
a=np.array([[ 1, 5, 3],
[ 4, 5, 6],
[ 4, 5, 6.1],
[ 1, 3, 42]])
I want to remove the duplicates with same x,y. In my array I have (4,5,6) and (4,5,6.1) and I want to remove one of them (no criterion).
If I had 2 columns (x,y) I could use
np.unique(a[:,:2], axis = 0)
But my array has 3 columns and I don't see how to do this in a simple way.
I can do a loop but my arrays can be very large.
Is there a way to do this more efficiently?
If I understand correctly, you need this:
a[np.unique(a[:,:2],axis=0,return_index=True)[1]]
output:
[[ 1. 3. 42.]
[ 1. 5. 3.]
[ 4. 5. 6.]]
Please be mindful that it does not keep the original order of rows in a. If you want to keep the order, simply sort the indices:
a[np.sort(np.unique(a[:,:2],axis=0,return_index=True)[1])]
output:
[[ 1. 5. 3.]
[ 4. 5. 6.]
[ 1. 3. 42.]]
I think you want to do this?
np.rint will round your numbers to an integer
import numpy as np
a = np.array([
[ 1, 5, 3],
[ 4, 5, 6],
[ 4, 5, 6.1],
[ 1, 3, 42]
])
a = np.unique(np.rint(a), axis = 0)
print(a)
//result :
[[ 1. 3. 42.]
[ 1. 5. 3.]
[ 4. 5. 6.]]

How to divide an n-dimensional array by the first value from a dimension

Given an array of dimension N how do I divide all values in the array by the first value from a selected dimension?
Example code:
import numpy as np
A = np.random.randint(1, 10, size=(3,3,3))
B = A[:,:,0]
C = np.divide(A,B)
A
print()
B
print()
C
print()
C[:,:,0]
Output:
array([[[1, 8, 5],
[3, 6, 5],
[5, 4, 2]],
[[6, 2, 9],
[4, 2, 2],
[5, 6, 8]],
[[3, 3, 1],
[2, 7, 7],
[6, 4, 6]]])
array([[1, 3, 5],
[6, 4, 5],
[3, 2, 6]])
array([[[1. , 2.66666667, 1. ],
[0.5 , 1.5 , 1. ],
[1.66666667, 2. , 0.33333333]],
[[6. , 0.66666667, 1.8 ],
[0.66666667, 0.5 , 0.4 ],
[1.66666667, 3. , 1.33333333]],
[[3. , 1. , 0.2 ],
[0.33333333, 1.75 , 1.4 ],
[2. , 2. , 1. ]]])
array([[1. , 0.5 , 1.66666667],
[6. , 0.66666667, 1.66666667],
[3. , 0.33333333, 2. ]])
I was expecting the final output from C[:,:,0] to be all 1's. I guess it has to do with the broadcasting of B but I don't think I understand why it isn't broadcasting B into a shape (3,3,3) where it is replicated along dimension 2.
To get your expected results you could reshape your B array to:
B = A[:,:,0].reshape(3,-1, 1)
Then when you divide you will get a result like:
array([[[1. , 0.11111111, 0.11111111],
[1. , 0.25 , 0.5 ],
[1. , 0.88888889, 0.44444444]],
[[1. , 0.88888889, 1. ],
[1. , 1.8 , 1.6 ],
[1. , 4.5 , 0.5 ]],
[[1. , 0.66666667, 0.5 ],
[1. , 1.125 , 0.75 ],
[1. , 0.5 , 2.25 ]]])
You could also maintain the proper dimension for broadcasting by taking B as:
B = A[:,:,0:1]
You need to reshape B such that it aligns with A[:,:,0]:
>>> A
array([[[1, 8, 5],
[3, 6, 5],
[5, 4, 2]],
[[6, 2, 9],
[4, 2, 2],
[5, 6, 8]],
[[3, 3, 1],
[2, 7, 7],
[6, 4, 6]]])
>>> B = A[:, :, 0]
>>> B
array([[1, 3, 5],
[6, 4, 5],
[3, 2, 6]])
# And you need to reorient B as:
>>> B.T[None,:].T
array([[[1],
[3],
[5]],
[[6],
[4],
[5]],
[[3],
[2],
[6]]])
>>> A / B.T[None,:].T
array([[[1. , 8. , 5. ],
[1. , 2. , 1.66666667],
[1. , 0.8 , 0.4 ]],
[[1. , 0.33333333, 1.5 ],
[1. , 0.5 , 0.5 ],
[1. , 1.2 , 1.6 ]],
[[1. , 1. , 0.33333333],
[1. , 3.5 , 3.5 ],
[1. , 0.66666667, 1. ]]])

Divide Numpy array by Scalar where Array-Element is below a certain value

I have a numpy array like
[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
Now I want divide every Element which is less than 5 by 2. The Result should be
[[0.5, 1, 1.5],
[2, 5, 6],
[7, 8, 9]]
How can I do that?
Use numpy.where:
np.where(arr<5, arr/2, arr)
Output:
array([[0.5, 1. , 1.5],
[2. , 5. , 6. ],
[7. , 8. , 9. ]])
You can do this by logical indexing:
>>> import numpy as np
>>> x = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], dtype = float)
>>> x[x<5] = x[x<5]/2
>>> x
array([[0.5, 1. , 1.5],
[2. , 5. , 6. ],
[7. , 8. , 9. ]])
Here's what you could do
x[x<5] = x[x<5]/2
numpy.where
For example, if your array is named np_array
numpy.where(np_array >=5, np_array, np_array/2)
See the documentation here

Concatenate and sort data in python

I have a few numpy arrays like so:
import numpy as np
a = np.array([[1, 2, 3, 4, 5], [14, 16, 17, 27, 38]])
b = np.array([[1, 2, 3, 4, 5], [.4, .2, .5, .1, .6]])
I'd like to be able to 1.Copy these arrays into a new single array and 2. Sort the data so that the result is as follows:
data = [[1, 1, 2, 2, 3, 3, 4, 4, 5, 5], [14, .4, 16, .2, 17, .5, 27, .1, 38, .6]]
Or, in other words, I need all columns from the original array to be the same, just in an ascending order. I tried this:
data = np.hstack((a,b))
Which gave me the appended data, but I'm not sure how to sort it. I tried np.sort() but it didn't keep the columns the same. Thanks!
Stack those horizontally (as you already did), then get argsort indices for sorting first row and use those to sort all columns in the stacked array.
Thus, we need to add one more step, like so -
ab = np.hstack((a,b))
out = ab[:,ab[0].argsort()]
Sample run -
In [370]: a
Out[370]:
array([[ 1, 2, 3, 4, 5],
[14, 16, 17, 27, 38]])
In [371]: b
Out[371]:
array([[ 1. , 2. , 3. , 4. , 5. ],
[ 0.4, 0.2, 0.5, 0.1, 0.6]])
In [372]: ab = np.hstack((a,b))
In [373]: print ab[:,ab[0].argsort()]
[[ 1. 1. 2. 2. 3. 3. 4. 4. 5. 5. ]
[ 14. 0.4 16. 0.2 17. 0.5 27. 0.1 38. 0.6]]
Please note that to keep the order for identical elements, we need to use to use kind='mergesort' with argsort as described in the docs.
If you like something short.
np.array(zip(*sorted(zip(*np.hstack((a,b))))))
>>> array([[ 1. , 1. , 2. , 2. , 3. , 3. , 4. , 4. , 5. , 5. ],
[ 0.4, 14. , 0.2, 16. , 0.5, 17. , 0.1, 27. , 0.6, 38. ]])
Version that preserve second element order:
np.array(zip(*sorted(zip(*np.hstack((a,b))),key=lambda x:x[0])))
>>>array([[ 1. , 1. , 2. , 2. , 3. , 3. , 4. , 4. , 5. , 5. ],
[ 14. , 0.4, 16. , 0.2, 17. , 0.5, 27. , 0.1, 38. ,0.6]])

Get more than one dimension with numpy take function

I've got a one dimensional array (n) called edges and want to insert the values by the index from the vertices array (n,3)
vertices = [[ 1.25, 4.321, -4], [2, -5, 3.32], [23.3, 43, 12], [32, 4, -23]]
edges = [1, 3, 2, 0]
result = [[2, -5, 3.32], [32, 4, -23], [23.3, 43, 12], [ 1.25, 4.321, -4]]
I tried np.take(vertices, edges) but It doesn't work for multi dimensional arrays.
take with axis parameter works
In [313]: vertices=np.array(vertices)
In [314]: edges=[1,3,2,0]
In [315]: np.take(vertices, edges,0)
Out[315]:
array([[ 2. , -5. , 3.32 ],
[ 32. , 4. , -23. ],
[ 23.3 , 43. , 12. ],
[ 1.25 , 4.321, -4. ]])
In [316]: vertices[edges,:]
Out[316]:
array([[ 2. , -5. , 3.32 ],
[ 32. , 4. , -23. ],
[ 23.3 , 43. , 12. ],
[ 1.25 , 4.321, -4. ]])
You can simply use indexing here:
vertices[edges]
# ^ ^ indexing
If you index with a list, then numpy will reshuffle the original matrix such that the highest dimension here follows the indices as specified by edges.
like:
>>> vertices = np.array([[ 1.25, 4.321, -4], [2, -5, 3.32], [23.3, 43, 12], [32, 4, -23]])
>>> edges = [1, 3, 2, 0]
>>> vertices[edges]
array([[ 2. , -5. , 3.32 ],
[ 32. , 4. , -23. ],
[ 23.3 , 43. , 12. ],
[ 1.25 , 4.321, -4. ]])
>>> vertices[edges].base is None
True
The fact that base is None means that this does not generate a view, it makes a copy of the matrix (with filtered/reordered rows). Changes you thus later make to the elements of vertices will not change the elements of the result of vertices[edges] (given you make the copy before altering vertices of course).

Categories