【问题标题】:Efficient metric for to measure whether two clouds of points overlap?衡量两个点云是否重叠的有效指标?
【发布时间】:2021-06-15 15:52:03
【问题描述】:

假设我有两组点 AB。 A 是大小为 N×D 的矩阵,B 是大小为 M×D 的矩阵。两个集合的维度 D 相同,但可能由不同数量的样本组成 N,M > 1(假设样本数量足够大)。

我正在寻找一个有效的指标来确定集合 A 与集合 B 重叠的程度。该指标应具有以下属性:

  1. 当集合 A 包含在集合 B 中时,它应该返回一个较大的值
  2. 当集合 A 与集合 B 部分重叠时,它应该返回一个中间值
  3. 设置A和设置B不重叠时应该返回一个小值

我已经想到了一些方法来实现这一点,但没有一个能成功:

  • 确定B的凸包,然后计算A在这个凸包内的百分比。这或多或少是可靠的(假设 B 足够凸),但计算凸包对于大 D 来说变得非常昂贵。
  • 估计 AB 的均值和协方差,并计算得到的两个多元高斯分布之间的 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


    【解决方案1】:

    另一个想法是将每个集合内的标准偏差与池集中的整体标准偏差进行比较。集合重叠的越多,这些数字就越相似。

    要处理一组在另一组中分布较小的情况,您可以使用较大的单个标准差与合并的一组进行比较。

    这可以针对每个维度进行,最终指标将是所有维度的平均值:

    def metric_std(A, B):
            
        # standard deviations 
        A_std  = np.std(A, axis=0)
        B_std  = np.std(B, axis=0)
        pooled_std = np.std(np.vstack([A, B]), axis=0)
        
        # metric: ratio of higher individual to pooled std    
        std_ratio = np.max([A_std, B_std], axis=0) / pooled_std
            
        return np.mean(std_ratio)
    
    
    print('case 1: '+str(metric_std(A1, B1)))
    print('case 2: '+str(metric_std(A2, B2)))
    print('case 3: '+str(metric_std(A3, B3)))
    print('case 4: '+str(metric_std(A4, B4)))
    
    case 1: 1.012685295955191
    case 2: 0.973728554241719
    case 3: 0.5569612281519413
    case 4: 1.4071848466046386
    

    【讨论】:

    • 一个有趣的想法,谢谢你的建议!
    猜你喜欢
    • 1970-01-01
    • 2011-03-17
    • 1970-01-01
    • 2017-12-20
    • 1970-01-01
    • 2012-12-10
    • 2017-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多