【发布时间】:2021-06-15 15:52:03
【问题描述】:
假设我有两组点 A 和 B。 A 是大小为 N×D 的矩阵,B 是大小为 M×D 的矩阵。两个集合的维度 D 相同,但可能由不同数量的样本组成 N,M > 1(假设样本数量足够大)。
我正在寻找一个有效的指标来确定集合 A 与集合 B 重叠的程度。该指标应具有以下属性:
- 当集合 A 包含在集合 B 中时,它应该返回一个较大的值
- 当集合 A 与集合 B 部分重叠时,它应该返回一个中间值
- 设置A和设置B不重叠时应该返回一个小值
我已经想到了一些方法来实现这一点,但没有一个能成功:
- 确定B的凸包,然后计算A在这个凸包内的百分比。这或多或少是可靠的(假设 B 足够凸),但计算凸包对于大 D 来说变得非常昂贵。
- 估计 A 和 B 的均值和协方差,并计算得到的两个多元高斯分布之间的 Kullback-Leibler 散度。这是相当有效的,但不能区分 A 完全嵌入 B 但传播明显较低的情况,以及当 A 和 B 具有相似的分布,但只是部分重叠。
您对我如何解决这个问题还有其他想法吗?下面我提供了一个示例代码来说明使用 Kullback-Leibler 散度的问题:
import numpy as np
import scipy.stats
N = 1000
M = 1000
D = 3
def metric_KLD(A,B):
# Get the dimension of A and B
D = A.shape[-1]
# Estimate mean and cov of A
A_mean = np.mean(A,axis=0)
A_cov = np.cov(A.T)
# Estimate mean and cov of B
B_mean = np.mean(B,axis=0)
B_cov = np.cov(B.T)
# Calculate the KLD
KLD = 0.5*(np.log(np.linalg.det(B_cov)/np.linalg.det(A_cov)) - \
D + np.trace(np.dot(np.linalg.inv(B_cov),A_cov)) + \
np.linalg.multi_dot((
(B_mean - A_mean)[np.newaxis,:],
np.linalg.inv(B_cov),
(B_mean - A_mean)[:,np.newaxis])))
return KLD
# Case 1: Both distributions overlap perfectly
A1 = scipy.stats.multivariate_normal.rvs(
mean = np.zeros(D),
cov = np.identity(D)*10**2,
size = N)
B1 = scipy.stats.multivariate_normal.rvs(
mean = np.zeros(D),
cov = np.identity(D)*10**2,
size = M)
print('KLD case 1: '+str(metric_KLD(A1,B1)))
# Case 2: Both distributions overlap partially
A2 = scipy.stats.multivariate_normal.rvs(
mean = np.asarray([0,0,0]),
cov = np.identity(D)*10**2,
size = N)
B2 = scipy.stats.multivariate_normal.rvs(
mean = np.asarray([10,0,0]),
cov = np.identity(D)*10**2,
size = M)
print('KLD case 2: '+str(metric_KLD(A2,B2)))
# Case 3: Both distributions don't overlap at all
A3 = scipy.stats.multivariate_normal.rvs(
mean = np.asarray([0,0,0]),
cov = np.identity(D)*10**2,
size = N)
B3 = scipy.stats.multivariate_normal.rvs(
mean = np.asarray([30,30,30]),
cov = np.identity(D)*10**2,
size = M)
print('KLD case 3: '+str(metric_KLD(A3,B3)))
# Case 4: A is included in B, but A has significantly smaller spread
A4 = scipy.stats.multivariate_normal.rvs(
mean = np.asarray([0,0,0]),
cov = np.identity(D)*1**2,
size = N)
B4 = scipy.stats.multivariate_normal.rvs(
mean = np.asarray([0,0,0]),
cov = np.identity(D)*10**2,
size = M)
# This is problematic: Should be better than case 2 but isn't
print('KLD case 4: '+str(metric_KLD(A4,B4)))
【问题讨论】:
标签: python distance metrics overlap