地址的亲和传播聚类

Posted

技术标签:

【中文标题】地址的亲和传播聚类【英文标题】:Affinity Propagation Clustering for Addresses 【发布时间】:2017-06-19 20:05:14 【问题描述】:

我有很多人的地址列表(每个人 1-8 个地址),我正在尝试确定每个人拥有的唯一地址的数量。

这是一个人的示例地址数据集

#df[df['ID'] =='12345'][['address','zip]].values
addresses = [['PULMONARY MED ASSOC MED GROUP INC 1485 RIVER PARK DR STE 200',
        '95815'],
       ['1485 RIVER PARK DRIVE SUITE 200', '95815'],
       ['1485 RIVER PARK DR SUITE 200', '95815'],
       ['3637 MISSION AVE SUITE 7', '95608']]

我有一个地址解析器,可以将地址的不同部分、“attn”、门牌号、街道名称、邮政信箱等分开,以便我可以单独比较它们(代码找到 here)

从上面的数据可以看出,地址1-3可能是一样的,地址4是不同的。

我写了以下相似度计算方法 - 权重没有魔法,我的直觉说应该是最重要的

def calcDistance(a1, a2,z1,z2, parser):

    z1 = str(z1)
    z2 = str(z2)
    add1 = parser.parse(a1)
    add2 = parser.parse(a2)

    zip_dist = 0 if z1 == z2 else distance.levenshtein(z1,z2)
    zip_weight = .4

    attn_dist = distance.levenshtein(add1['attn'],add2['attn']) if add1['attn'] and add2['attn'] else 0
    attn_weight = .1 if add1['attn'] and add2['attn'] else 0

    suite_dist = distance.levenshtein(add1['suite_num'],add2['suite_num']) if add1['suite_num'] and add2['suite_num'] else 0
    suite_weight = .1 if add1['suite_num'] and add2['suite_num'] else 0

    street_dist = distance.levenshtein(add1['street_name'],add2['street_name']) if add1['street_name'] and add2['street_name'] else 0
    street_weight = .3 if add1['street_name'] and add2['street_name'] else 0

    house_dist = distance.levenshtein(add1['house'],add2['house']) if add1['house'] and add2['house'] else 0
    house_weight = .1 if add1['house'] and add2['house'] else 0

    weight = (zip_dist * zip_weight + attn_dist * attn_weight + suite_dist * suite_weight + street_dist * street_weight
            + house_dist * house_weight ) / (zip_weight +attn_weight + suite_weight + street_weight + house_weight )

    return weight

将这个函数应用到我的每一个地址,你可以看到正确的地址1-3完全相似,地址4有点不同。

similarity = -1*np.array([[calcDistance(a1[0],a2[0],a1[1],a2[1],addr_parser) for a1 in addresses] for a2 in addresses])

print similarity 

array([[-0.        , -0.        , -0.        , -5.11111111],
       [-0.        , -0.        , -0.        , -5.11111111],
       [-0.        , -0.        , -0.        , -5.11111111],
       [-5.11111111, -5.11111111, -5.11111111, -0.        ]])

然后对这些进行聚类,我认为亲和力聚类可能是最好的方法 - 聚类计数是可变的,它适用于距离,并且可以识别一个原型示例,然后我可以使用“最佳”地址来表示集群。然而,我得到了一些奇怪的结果——affinityprop 聚类器正在为这些数据生成 3 个聚类,而不是 2 个。

affprop = sklearn.cluster.AffinityPropagation(affinity="precomputed", damping=.5)
affprop.fit(similarity)

print affprop.labels_
array([0, 0, 1, 2], dtype=int64)

相反,DBSCAN 正确地聚类成两个

dbscan = sklearn.cluster.DBSCAN(min_samples=1)
dbscan.fit(similarity)

print dbscan.labels_
array([0, 0, 0, 1], dtype=int64)

查看this question,似乎问题在于聚类器正在添加小的随机起点,并将完全相似的记录计算为退化。

有没有办法解决这个问题,还是我应该放弃亲和聚类并坚持使用 DBSCAN?

【问题讨论】:

【参考方案1】:

虽然我怀疑这个问题会随着不同组的更大样本而消失(参见下面的示例),但在您的情况下,您似乎需要增加 damping 因子以获得所需的结果。从 0.95 开始,您会得到正确的分组:

>>> affprop = sklearn.cluster.AffinityPropagation(affinity="precomputed", damping=.95)
>>> affprop.fit(similarity)
AffinityPropagation(affinity='precomputed', convergence_iter=15, copy=True,
          damping=0.95, max_iter=200, preference=None, verbose=False)
>>> print affprop.labels_
[0 0 0 1]

正如我最初提到的,随着您向集合中添加更多不同的数据,这个问题似乎消失了。查看您引用的问题中的示例,我们发现它们最初存在相同的问题:

>>> c = [[0], [0], [0], [0], [0], [0], [0], [0]]
>>> af = sklearn.cluster.AffinityPropagation (affinity = 'euclidean').fit (c)
>>> print (af.labels_)
[0 1 0 1 2 1 1 0]

这会随着更高的阻尼而消失:

>>> c = [[0], [0], [0], [0], [0], [0], [0], [0]]
>>> af = sklearn.cluster.AffinityPropagation (affinity = 'euclidean', damping=.99).fit (c)
>>> print (af.labels_)
[0 0 0 0 0 0 0 0]

或者当我们引入更多组时:

>>> c = [[0], [0], [0], [1], [2], [1], [2], [1]]
>>> af = sklearn.cluster.AffinityPropagation (affinity = 'euclidean', damping=.5).fit (c)
>>> print (af.labels_)
[0 0 0 2 1 2 1 2]

【讨论】:

谢谢!我会将聚类结果与更高的阻尼因子进行比较,看看它们是否更符合我的预期。不幸的是,我无法扩展组,数据就是这样。您能否简要解释一下阻尼因子是如何影响模型的? 这个article 是我找到的最好的,但它有助于“超调”解决方案。基于该页面,令人惊讶的是 sklearn 默认值为 0.5,因为作者建议使用 0.9。

以上是关于地址的亲和传播聚类的主要内容,如果未能解决你的问题,请参考以下文章

在 scikit-learn 中获取每个亲和传播集群的***术语

机器学习---聚类算法

在两个特征上聚类并绘制结果

使用聚类算法进行标签传播学习(Clustering for Semi-Supervised Learning)

第二节:半监督聚类之AP(Affinity Propagation)聚类(近邻传播聚类)

精彩文章推荐广西大学 覃华等:基于概率无向图模型的近邻传播聚类算法