考虑array1和array2,其中:
array1 = [a1 a2 NaN ... an]
array2 = [[NaN b2 b3 ... bn],
[b21 NaN b23 ... b2n],
...]
Run Code Online (Sandbox Code Playgroud)
两个数组都是 numpy 数组。有一种简单的方法可以计算array1和 的每一行之间的欧几里得距离array2:
EuclideanDistance = np.sqrt(((array1 - array2)**2).sum(axis=1))
Run Code Online (Sandbox Code Playgroud)
搞乱这个计算的是 NaN 值。当然,我可以很容易地用一些数字替换 NaN。但相反,我想做以下事情:
当我array1与row_xof进行比较时array2,我计算其中一个数组有 NaN 而另一个没有的列。让我们假设count是 3。然后我将从两个数组中删除这些列并计算两者之间的欧几里德距离。最后,我将 a 添加minus_value * count到计算的距离。
现在,我想不出一种快速有效的方法来做到这一点。有人可以帮助我吗?
以下是我的一些想法:
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
Run Code Online (Sandbox Code Playgroud)
然而,这些线条对我来说并不难看。此外,我不断收到索引错误:显然 deleteIdxs 包含超出 array1 范围的索引。不知道这怎么可能。
我会编写一个函数来处理距离计算。我确信有一种更快、更有效的方法来编写这个(列表理解、聚合等),但可读性很重要,对吗?:)
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)
Run Code Online (Sandbox Code Playgroud)
您必须非常仔细地考虑负变量的值。添加随机值真的有用吗?
正如@Nathan 所建议的,可以轻松实现更高效的资源。
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)
Run Code Online (Sandbox Code Playgroud)
然而,如果我绝对需要(如果这是瓶颈),我只会尝试实现这样的东西。对于所有其他时间,我很乐意牺牲一些资源以获得一些可读性和可扩展性。