I'm struggling to find an efficient way to implement this interpolated convex hull data treatment.
I have a 2D ndarray, call it arr, with shape (2000000,19), containing floats.I have a 1D ndarray, call it w, with shape (19,), also containing floats.
What I achieved (and works perfectly except that it's excruciatingly slow) is the following:
import numpy as npfrom scipy.interpolate import interp1d# Sample dataarr = np.array([[49.38639913, 49.76769437, 49.66370476, 49.49905455, 49.15242251, 48.0518658 , 45.998071 , 45.31347273, 45.29614113, 45.25281212, 45.0448329 , 44.61154286, 43.72763117, 42.38443203, 41.17121991, 40.48662165, 40.35663463, 39.88001558, 39.55938095], [47.97387359, 47.86121818, 47.69656797, 47.18528571, 46.70000087, 45.39146494, 43.50232035, 43.18168571, 43.82295498, 43.62364156, 43.31167273, 42.88704848, 42.37576623, 41.0585645 , 40.37396623, 39.09142771, 38.79679048, 38.51948485, 38.52815065]])w = np.array([2.1017, 2.1197, 2.1374, 2.1548, 2.172 , 2.1893, 2.2068, 2.2254, 2.2417, 2.2592, 2.2756, 2.2928, 2.3097, 2.326 , 2.3421, 2.3588, 2.3745, 2.3903, 2.4064])def upper_andrews_hull(points: np.ndarray):""" Computes the upper half of the convex hull of a set of 2D points. :param points: an iterable sequence of (x, y) pairs representing the points.""" # 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product. # Returns a positive value, if OAB makes a counter-clockwise turn, # negative for clockwise turn, and zero if the points are collinear. def cross(o, a, b): return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]) # Reverse the points so that we can pop from the end points = np.flip(points, axis=0) # Build upper hull upper = [] for p in points: while len(upper) >= 2 and cross(upper[-2], upper[-1], p) <= 0: upper.pop() upper.append(p) # Reverse the upper hull upper = np.flip(np.array(upper), axis=0) return upperresult = np.array(arr.shape)for i in range(arr.shape[0]): # Create points, using w as x values, and arr as y values points = np.stack((w, arr[i,:]), axis=1) # Calculate the convex hull around the points hull = upper_andrews_hull(points) # Interpolate the hull interp_function = interp1d(*hull.T) # Store interpolation's result to have the same x references as original points result[i,:] = interp_function(w)I'm pretty sure that there's a way to forego the loop and only use vectorial calculations, but I can't find it (plus, there's the issue that hull doesn't always have the same number of points, so all of the hulls would not be storable in an ndarray.