New to Python, and have been learning about arrays. I am stuck with a simple enough problem and need a solution. I have two arrays:
a = [2.0, 5.1, 6.2, 7.9, 23.0] # always increasing
b = [5.1, 5.5, 5.7, 6.2, 00.0] # also always increasing
and I want the resultant array to be:
c = [0.0, 5.1, 6.2, 0.0, 0.0] # 5.5, 5.7, 00.0 from 'b' were dropped and rearranged such that position of equivalent elements as in 'a' are maintained
I have compared both 'a' & 'b' using Numpy as in:
y = np.isclose(a, b)
print y
# [False False False False False]
(Alternately,) I also tried something like this, which isn't the right way (I think):
c = np.zeros(len(a))
for i in range (len(a)):
for j in range (len(a)):
err = abs(a[i]-b[j])
if err == 0.0 or err < abs(1):
print (err, a[i], b[j], i, j)
else:
print (err, a[i], b[j], i, j)
How do I proceed from here towards obtaining 'c'?
These solutions work even when the arrays are of different size.
Simple version
c = []
for i in a:
if any(np.isclose(i, b)):
c.append(i)
else:
c.append(0.0)
Numpy version
aa = np.tile(a, (len(b), 1))
bb = np.tile(b, (len(a), 1))
cc = np.isclose(aa, bb.T)
np.any(cc, 0)
c = np.zeros(shape=a.shape)
result = np.where(np.any(cc, 0), a, c)
Explained:
I will be doing matrix comparison here. First you expand the arrays into matrices. Lengths are exchanged, which creates matrices having equal size of one dimension:
aa = np.tile(a, (len(b), 1))
bb = np.tile(b, (len(a), 1))
They look like this:
# aa
array([[ 2. , 5.1, 6.2, 7.9, 23. ],
[ 2. , 5.1, 6.2, 7.9, 23. ],
[ 2. , 5.1, 6.2, 7.9, 23. ],
[ 2. , 5.1, 6.2, 7.9, 23. ],
[ 2. , 5.1, 6.2, 7.9, 23. ]])
# bb
array([[ 5.1, 5.5, 5.7, 6.2, 0. ],
[ 5.1, 5.5, 5.7, 6.2, 0. ],
[ 5.1, 5.5, 5.7, 6.2, 0. ],
[ 5.1, 5.5, 5.7, 6.2, 0. ],
[ 5.1, 5.5, 5.7, 6.2, 0. ]])
Then compare them. Note that bb is transposed:
cc = np.isclose(aa, bb.T)
And you get:
array([[False, True, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
[False, False, True, False, False],
[False, False, False, False, False]], dtype=bool)
You can aggregate this by axis 0:
np.any(cc, 0)
which returns
array([False, True, True, False, False], dtype=bool)
Now create array c:
c = np.zeros(shape=a.shape)
And select appropriate value, either from a or c:
np.where(np.any(cc, 0), a, c)
And the result:
array([ 0. , 5.1, 6.2, 0. , 0. ])
With np.isclose you already create an array where the "closest" elements are True. So you can use this result to set all other elements to zero.
import numpy as np
a = np.array([2.0, 5.1, 6.2, 7.9, 23.0]) # always increasing
b = np.array([5.1, 5.5, 5.7, 6.2, 00.0]) # also always increasing
a[~np.isclose(a,b, atol=0.5)] = 0
a
this returns array([ 0. , 5.1, 6.2, 0. , 0. ]).
But notice you want to set all elements that are not close, so you need to invert (~) the result.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With