If I understand your question correctly, this will work. Knowing numpy
is probably the best way, but it is at least pretty simple. I used some contrived coordinates to show that the calculation works as expected.
>>> arr1 array([[0, 3], [1, 4], [2, 5]]) >>> arr2 array([[ 3, 6, 5, 8], [ 5, 8, 13, 16], [ 2, 5, 2, 5]])
You can subtract arr1
from arr2
, making sure they are broadcast against each other correctly. The best way I could think of is to take a transpose and make some changes. They do not create copies - they create representations - so it is not so wasteful. ( dist
is a copy, though.)
>>> dist = (arr2.T.reshape((2, 2, 3)) - arr1.T).reshape((4, 3)) >>> dist array([[ 3, 4, 0], [ 3, 4, 0], [ 5, 12, 0], [ 5, 12, 0]])
Now all we need to do is apply numpy.linalg.norm
to axis 1. (You can choose one of several norms ).
>>> numpy.apply_along_axis(numpy.linalg.norm, 1, dist) array([ 5., 5., 13., 13.])
Assuming you want a simple Euclidean distance, you can also do this directly; not sure if this will be faster or slower, try both:
>>> (dist ** 2).sum(axis=1) ** 0.5 array([ 5., 5., 13., 13.])
Based on your editing, we should only make one small tweak. Since you want to test the columns in half, and not block by block, you need a window for riding. This can be done very simply with fairly simple indexing:
>>> arr2.T[numpy.array(zip(range(0, 3), range(1, 4)))] array([[[ 3, 5, 2], [ 6, 8, 5]], [[ 6, 8, 5], [ 5, 13, 2]], [[ 5, 13, 2], [ 8, 16, 5]]])
Combining this with other tricks:
>>> arr2_pairs = arr2.T[numpy.array(zip(range(0, 3), range(1, 4)))] >>> dist = arr2_pairs - arr1.T >>> (dist ** 2).sum(axis=2) ** 0.5 array([[ 5. , 5. ], [ 9.69535971, 9.69535971], [ 13. , 13. ]])
However, converting arrays from list contexts tends to be slow. It may be faster to use stride_tricks - here, see which one is best for your purposes:
>>> as_strided(arr2.T, strides=(8, 8, 32), shape=(3, 2, 3)) array([[[ 3, 5, 2], [ 6, 8, 5]], [[ 6, 8, 5], [ 5, 13, 2]], [[ 5, 13, 2], [ 8, 16, 5]]])
This actually manipulates how numpy
moves around the block of memory, allowing small arrays to emulate a larger array.
>>> arr2_pairs = as_strided(arr2.T, strides=(8, 8, 32), shape=(3, 2, 3)) >>> dist = arr2_pairs - arr1.T >>> (dist ** 2).sum(axis=2) ** 0.5 array([[ 5. , 5. ], [ 9.69535971, 9.69535971], [ 13. , 13. ]])
So now you have a simple 2nd array corresponding to the distance for each pair of columns. Now it's just a matter of getting mean
and calling argmin
.
>>> normed = (dist ** 2).sum(axis=2) ** 0.5 >>> normed.mean(axis=1) array([ 5. , 9.69535971, 13. ]) >>> min_window = normed.mean(axis=1).argmin() >>> arr2[:,[min_window, min_window + 1]] array([[3, 6], [5, 8], [2, 5]])