【问题标题】:Clustering geospatial data on coordinates AND non spatial feature对坐标和非空间特征的地理空间数据进行聚类
【发布时间】:2021-05-30 00:37:03
【问题描述】:

假设我将以下数据框存储为一个名为坐标的变量,其中前几行如下所示:

   business_lat  business_lng  business_rating
0   19.111841     72.910729           5.
1   19.111342     72.908387           5.
2   19.111342     72.908387           4.
3   19.137815     72.914085           5.
4   19.119677     72.905081           2.
5   19.119677     72.905081           2.
        .             .               .
        .             .               .
        .             .               .

如您所见,此数据是地理空间数据(具有 lat 和 lng),并且每一行都有一个附加值 business_rating,它对应于该行中 latlng 处的企业评级。我想对数据进行聚类,将附近且具有相似评级的企业分配到同一个聚类中。本质上,我需要一个地理空间集群,并要求集群必须考虑评级列。

我在网上查了一下,并没有真正找到很多解决方法:只有严格的地理空间聚类(只有要聚类的特征是 latlng)或非空间聚类。

我在下面运行了一个简单的 DBSCAN,但是当我绘制聚类结果时,它似乎并没有正确地做我想要的。

from sklearn.cluster import DBSCAN
import numpy as np
db = DBSCAN(eps=2/6371., min_samples=5, algorithm='ball_tree', metric='haversine').fit(np.radians(coordinates))

尝试调整 DBSCAN 的参数、对数据进行一些额外的处理或同时使用不同的方法会更好吗?

【问题讨论】:

    标签: python scikit-learn cluster-analysis geospatial dbscan


    【解决方案1】:

    将两种不同类型的信息(位置和评级)聚集在一起的棘手部分是确定它们应该如何相互关联。当它只是一个域并且您正在比较相同的单位时,很容易询问。我的方法是查看如何关联域中的行,然后确定域之间的一些交互。这可以使用像 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_
    

    【讨论】:

      【解决方案2】:

      使用 DBSCAN 方法,我们可以计算点之间的距离(欧几里得距离或其他距离)并寻找远离其他点的点。您可能需要考虑使用 MinMaxScaler 来规范化值,这样一个特征就不会压倒其他特征。

      您的代码在哪里?您的最终结果是什么?没有实际的代码示例,我只能猜测您在做什么。

      我为您编写了一些示例代码。您可以在下面看到结果。

      import pandas as pd
      import numpy as np
      import matplotlib.pyplot as plt
      from sklearn.cluster import KMeans
      import seaborn as sns; sns.set()
      import csv
      
      df = pd.read_csv('C:\\your_path_here\\business.csv')
      
      X=df.loc[:,['review_count','latitude','longitude']]
      
      K_clusters = range(1,10)
      kmeans = [KMeans(n_clusters=i) for i in K_clusters]
      Y_axis = df[['latitude']]
      X_axis = df[['longitude']]
      score = [kmeans[i].fit(Y_axis).score(Y_axis) for i in range(len(kmeans))]# Visualize
      
      plt.plot(K_clusters, score)
      plt.xlabel('Number of Clusters')
      plt.ylabel('Score')
      plt.title('Elbow Curve')
      plt.show()
      
      kmeans = KMeans(n_clusters = 3, init ='k-means++')
      kmeans.fit(X[X.columns[0:2]]) # Compute k-means clustering.
      
      X['cluster_label'] = kmeans.fit_predict(X[X.columns[0:2]])
      centers = kmeans.cluster_centers_ # Coordinates of cluster centers.
      
      labels = kmeans.predict(X[X.columns[0:2]]) # Labels of each point
      X.head(10)
      
      X.plot.scatter(x = 'latitude', y = 'longitude', c=labels, s=50, cmap='viridis')
      plt.scatter(centers[:, 0], centers[:, 1], c='black', s=200, alpha=0.5)
      
      from scipy.stats import zscore
      df["zscore"] = zscore(df["review_count"])
      df["outlier"] = df["zscore"].apply(lambda x: x <= -2.5 or x >= 2.5)
      df[df["outlier"]]
      
      df_cord = df[["latitude", "longitude"]]
      df_cord.plot.scatter(x = "latitude", y = "latitude")
      
      from sklearn.preprocessing import MinMaxScaler
      scaler = MinMaxScaler()
      df_cord = scaler.fit_transform(df_cord)
      df_cord = pd.DataFrame(df_cord, columns = ["latitude", "longitude"])
      df_cord.plot.scatter(x = "latitude", y = "longitude")
      
      from sklearn.cluster import DBSCAN
      outlier_detection = DBSCAN(
        eps = 0.5,
        metric="euclidean",
        min_samples = 3,
        n_jobs = -1)
      clusters = outlier_detection.fit_predict(df_cord)
      
      clusters
      
      from matplotlib import cm
      cmap = cm.get_cmap('Accent')
      df_cord.plot.scatter(
        x = "latitude",
        y = "longitude",
        c = clusters,
        cmap = cmap,
        colorbar = False
      )
      

      说实话,最终结果看起来有点奇怪。请记住,并非所有内容都是可集群的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-04-26
        • 1970-01-01
        • 2017-03-31
        • 1970-01-01
        • 1970-01-01
        • 2022-10-07
        • 2015-02-22
        • 1970-01-01
        相关资源
        最近更新 更多