在聚类不同类型的信息(位置和评分)时,棘手的部分是确定它们之间的关系。当只有一个领域且比较的是相同单位时,这很简单。我的方法是先看一下如何将领域内的行相关联,然后确定一些领域之间的交互作用。可以使用像MinMaxScaler提到的缩放选项来完成这个过程,但我认为这有点过重,我们可以利用对领域的了解来更好地进行聚类。
处理位置信息
最好直接处理位置距离,因为这具有现实世界的意义,我们可以预计算距离。米的含义与我们所指的完全一样。
您可以使用上一个答案中提到的缩放选项,但这会使位置数据失真。例如,如果您有一组长而薄的位置数据,MinMaxScaling会给细长轴上的变化比长轴上的变化更多的重要性。如果要使用缩放,请在计算出的距离矩阵上进行,而不是在经纬度本身上进行。
import numpy as np
from sklearn.metrics.pairwise import haversine_distances
points_in_radians = df[['business_lat','business_lng']].apply(np.radians).values
distances_in_km = haversine_distances(points_in_radians) * 6371
添加评分
我们可以通过将评分与距离相关联来思考这个问题。我们可以问一些问题,如:在同一位置观察到的评分必须有多大差异才能区分?米数差异与评分差异比率是多少?有了比率的概念,我们可以计算出所有观测值的评分差异的另一个距离矩阵,并使用它来缩放或添加原始位置距离矩阵,或者我们可以增加每个评分间隙的距离。然后,我们可以对此位置和评分差异矩阵进行聚类。
from sklearn.metrics.pairwise import euclidean_distances
added_km_per_rating_gap = 1
rating_distances = euclidean_distances(df[['business_rating']].values) * added_km_per_rating_gap
我们可以将它们相加并在生成的矩阵上进行聚类。
from sklearn.cluster import DBSCAN
distance_matrix = rating_distances + distances_in_km
clustering = DBSCAN(metric='precomputed', eps=1, min_samples=2)
clustering.fit(distance_matrix)
我们所做的是按地点进行聚类,并对评分差异添加惩罚。使这种惩罚直接而可控,可以优化以找到最佳聚类。
测试
我发现的问题是(至少对于我的测试数据),DBSCAN有一种倾向,即从观测到观测“漫步”,形成要么将评级混合在一起,因为惩罚不够高,要么分离成单个评级组的聚类。也许DBSCAN不适用于此类型的聚类。如果我有更多时间,我会寻找一些开放数据来测试,并尝试其他聚类方法。
以下是我用于测试的代码。我使用了评分距离的平方来强调较大的差距。
import random
from sklearn.datasets import make_blobs
X, y = make_blobs(n_samples=300, centers=6, cluster_std=0.60, random_state=0)
ratings = np.array([random.randint(1,4) for _ in range(len(X)//2)] \
+[random.randint(2,5) for _ in range(len(X)//2)]).reshape(-1, 1)
distances_in_km = euclidean_distances(X)
rating_distances = euclidean_distances(ratings)
def build_clusters(multiplier, eps):
rating_addition = (rating_distances ** 2) * multiplier
distance_matrix = rating_addition + distances_in_km
clustering = DBSCAN(metric='precomputed', eps=eps, min_samples=10)
clustering.fit(distance_matrix)
return clustering.labels_