Calculate distance between arrays that contain NaN
考虑
1 2 3 4 | array1 = [a1 a2 NaN ... an] array2 = [[NaN b2 b3 ... bn], [b21 NaN b23 ... b2n], ...] |
两个数组都是 numpy 数组。有一种简单的方法可以计算
1 | EuclideanDistance = np.sqrt(((array1 - array2)**2).sum(axis=1)) |
扰乱这个计算的是 NaN 值。当然,我可以轻松地用某个数字替换 NaN。但相反,我想做以下事情:
当我将
现在,我想不出一种快速有效的方法来做到这一点。有人可以帮助我吗?
以下是我的一些想法:
1 2 3 4 5 6 7 8 9 | minus = 1000 dist = np.zeros(shape=(array1.shape[0])) # this array will store the distance of array1 to each row of array2 array1 = np.repeat(array1, array2.shape[0], axis=0) # now array1 has the same dimensions as array2 for i in range(0, array1.shape[0]): boolarray = np.logical_or(np.isnan(array1[i]), np.isnan(array2[i])) count = boolarray.sum() deleteIdxs = boolarray.nonzero() # this should give the indices where boolarray is True dist[i] = np.sqrt(((np.delete(array1[i], deleteIdxs, axis=0) - np.delete(array2[i], deleteIdxs, axis=0))**2).sum(axis=0)) dist[i] = dist[i] + count*minus |
然而,这些线条对我来说并不难看。此外,我不断收到索引错误:显然 deleteIdxs 包含超出 array1 范围的索引。不知道怎么会这样。
您可以使用以下命令找到值为 nan 的所有索引:
1 2 | indices_1 = np.isnan(array1) indices_2 = np.isnan(array2) |
你可以组合成:
1 | indices_total = indices_1 + indices_2 |
并且您可以使用以下方法保留所有非 nan 值:
1 2 | array_1_not_nan = array1[~indices_total] array_2_not_nan = array2[~indices_total] |
您可以使用以下命令过滤掉包含
1 2 3 4 5 6 7 | mask1 = np.isnan(arr1) mask2 = np.isnan(arr2).any(0) mask = ~(mask1 | mask2) # the two filtered arrays arr1[mask], arr2[mask] |
我会写一个函数来处理距离计算。我确信有一种更快、更有效的方法来写这个(列表理解、聚合等),但可读性很重要,对吧? :)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import numpy as np def calculate_distance(fixed_arr, var_arr, penalty): s_sum = 0.0 counter = 0 for num_1, num_2 in zip(fixed_arr, var_arr): if np.isnan(num_1) or np.isnan(num_2): counter += 1 else: s_sum += (num_1 - num_2) ** 2 return np.sqrt(s_sum) + penalty * counter, counter array1 = np.array([1, 2, 3, np.NaN, 5, 6]) array2 = np.array( [ [3, 4, 9, 3, 4, 8], [3, 4, np.NaN, 3, 4, 8], [np.NaN, 9, np.NaN, 3, 4, 8], [np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN], ] ) dist = np.zeros(len(array2)) minus = 10 for index, arr in enumerate(array2): dist[index], _ = calculate_distance(array1, arr, minus) print(dist) |
您必须非常仔细地考虑减号变量的值。添加随机值真的有用吗?
正如@Nathan 所建议的那样,可以轻松实现更高效的资源。
1 2 3 4 5 6 7 8 9 10 11 12 | fixed_arr = array1 penalty = minus dist = [ ( lambda indices=(np.isnan(fixed_arr) + np.isnan(var_arr)): np.linalg.norm( fixed_arr[~indices] - var_arr[~indices] ) + (indices == True).sum() * penalty )() for var_arr in array2 ] print(dist) |
但是,如果我绝对需要(如果这是瓶颈),我只会尝试实现这样的东西。对于所有其他时间,我很乐意牺牲一些资源以获得一些可读性和可扩展性。