地址的亲和传播聚类

我有一份许多人的地址列表(每人1到8个地址),我想确定每个人拥有的唯一地址数量。

这里是一个人的地址数据样本

#df[df['ID'] =='12345'][['address','zip]].valuesaddresses = [['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”、门牌号、街道名称、邮政信箱等,以便我可以单独比较它们(代码见这里

从上面的数据可以看出,地址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.        ]])

为了对这些地址进行聚类,我认为亲和聚类可能是最好的方法——聚类数量是可变的,它可以处理距离,并且可以识别出典型的例子,我可以使用“最佳”地址来代表聚类。然而,我得到了一些奇怪的结果——亲和聚类器对这些数据产生了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)

查看这个问题,看起来问题是聚类器添加了小的随机起始点,并将完全相似的记录视为退化情况。

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


回答:

虽然我认为随着不同组的样本增多(见下面的例子),这个问题会消失,但在你的情况下,看起来你需要增加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]

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注