对两种不同类型的信息(位置和评级)进行聚类的棘手部分是确定它们应如何相互关联。当它只是一个域并且您正在比较相同的单位时,询问很简单。我的方法是研究如何关联域内的行,然后确定域之间的某些交互。这可以使用提到的 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)
我们所做的是按位置进行聚类,并针对评分差异添加惩罚。使该惩罚直接且可控,可以进行优化以找到最佳聚类。
Testing
我发现的问题是(至少在我的测试数据中)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_