Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

numpy, taking array difference of their intersection

I have multiple numpy arrays and I want to create new arrays doing something that is like an XOR ... but not quite.

My input is two arrays, array1 and array2. My output is a modified (or new array, I don't really care) version of array1.

The modification is elementwise, by doing the following:

1.) If either array has 0 for the given index, then the index is left unchanged. 2.) If array1 and array2 are nonzero, then the modified array is assigned the value of array1's index subtracted by array2's index, down to a minimum of zero.

Examples:

array1:  [0, 3, 8, 0]
array2:  [1, 1, 1, 1]
output:  [0, 2, 7, 0]


array1:  [1, 1, 1, 1]
array2:  [0, 3, 8, 0]
output:  [1, 0, 0, 1]

array1:  [10, 10, 10, 10]
array2:  [8, 12, 8, 12]
output:  [2, 0, 2, 0]

I would like to be able to do this with say, a single numpy.copyto statement, but I don't know how. Thank you.

edit:

it just hit me. could I do:

new_array = np.zeros(size_of_array1)
numpy.copyto(new_array, array1-array2, where=array1>array2)

Edit 2: Since I have received several answers very quickly I am going to time the different answers against each other to see how they do. Be back with results in a few minutes.

Okay, results are in:

array of random ints 0 to 5, size = 10,000, 10 loops

1.)using my np.copyto method

2.)using clip

3.)using maximum

0.000768184661865
0.000391960144043
0.000403165817261

Kasramvd also provided some useful timings below

like image 884
Travis Black Avatar asked Dec 20 '25 12:12

Travis Black


2 Answers

You can use a simple subtraction and clipping the result with zero as the min:

(arr1 - arr2).clip(min=0)

Demo:

In [43]: arr1 = np.array([0,3,8,0]); arr2 = np.array([1,1,1,1])

In [44]: (arr1 - arr2).clip(min=0)
Out[44]: array([0, 2, 7, 0])

On large arrays it's also faster than maximum approach:

In [51]: arr1 = np.arange(10000); arr2 = np.arange(10000)

In [52]:  %timeit np.maximum(0, arr1 - arr2)
22.3 µs ± 1.77 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [53]: %timeit (arr1 - arr2).clip(min=0)
20.9 µs ± 167 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [54]: arr1 = np.arange(100000); arr2 = np.arange(100000)

In [55]:  %timeit np.maximum(0, arr1 - arr2)
671 µs ± 5.69 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [56]: %timeit (arr1 - arr2).clip(min=0)
648 µs ± 4.43 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Note that if it's possible for arr2 to have negative values you should consider using an abs function on arr2 to get the expected result:

(arr1 - abs(arr2)).clip(min=0)
like image 124
Mazdak Avatar answered Dec 22 '25 01:12

Mazdak


In [73]: np.maximum(0,np.array([0,3,8,0])-np.array([1,1,1,1]))
Out[73]: array([0, 2, 7, 0])

This doesn't explicitly address

If either array has 0 for the given index, then the index is left unchanged.

but the results match for all examples:

In [74]: np.maximum(0,np.array([1,1,1,1])-np.array([0,3,8,0]))
Out[74]: array([1, 0, 0, 1])
In [75]: np.maximum(0,np.array([10,10,10,10])-np.array([8,12,8,12]))
Out[75]: array([2, 0, 2, 0])
like image 21
hpaulj Avatar answered Dec 22 '25 03:12

hpaulj



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!