将空间数据可视化有利于更好的观察数据分布,但是,如果样本量过大,难免存在一些冗余信息,不利于观察,也很难发现其中的规律。此时,可以利用基于密度的聚类算法对原始数据进行压缩,从中发现一些具有代表性的特征。
给定一批经纬度样本点,我们可以利用DBSCAN算法对它们进行聚类,进而可以发现样本中潜在的规律。下面是一些示例样本点。
首先读入数据,数据示例如下
其中第一列是维度,第二列是经度,第三列是时间,第四列是城市,第五列是国家。
import
pandas as pd, numpy as np, matplotlib.pyplot as plt
from
sklearn.cluster
import
DBSCAN
from
geopy.distance
import
great_circle
from
shapely.geometry
import
MultiPoint
df
=
pd.read_csv(
'summer-travel-gps-full.csv'
)
coords
=
df.as_matrix(columns
=
[
'lat'
,
'lon'
])
在DBSCAN算法中,有两个非常重要的参数,一个参数是epsilon,该参数是最大距离,该距离用于判断两个样本点是否处于同一个聚类,min_samples 参数是聚类的最小样本数。
kms_per_radian
=
6371.0088
epsilon
=
1.5
/
kms_per_radian
db
=
DBSCAN(eps
=
epsilon, min_samples
=
1
, algorithm
=
'ball_tree'
, metric
=
'haversine'
).fit(np.radians(coords))
cluster_labels
=
db.labels_
num_clusters
=
len
(
set
(cluster_labels))
clusters
=
pd.Series([coords[cluster_labels
=
=
n]
for
n
in
range
(num_clusters)])
print
(
'Number of clusters: {}'
.
format
(num_clusters))
跟k-Means不同,DBSCAN不需要事先给定聚类的个数,而是通过epsilon和min_samples 自动确定。
下面的函数可以从一个聚类中的样本点,返回最中心的样本点,该样本点即为该聚类的质心。
def
get_centermost_point(cluster):
centroid
=
(MultiPoint(cluster).centroid.x, MultiPoint(cluster).centroid.y)
centermost_point
=
min
(cluster, key
=
lambda
point: great_circle(point, centroid).m)
return
tuple
(centermost_point)
centermost_points
=
clusters.
map
(get_centermost_point)
上面的函数首先计算质心的坐标,然后寻找聚类中离质心距离最近的样本点。
下面代码用于返回可以代表原样本集的中心点。
lats, lons
=
zip
(
*
centermost_points)
rep_points
=
pd.DataFrame({
'lon'
:lons,
'lat'
:lats})
下面的代码用于匹配原样本集中的时间 城市 国家等字段。
rs = rep_points . apply ( lambda row : df [( df [ ’ lat ’ ]== row [ ’ lat ’ ]) & ( df [ ’ lon ’ ]== row [ ’ lon ’]) ]. iloc [0] , axis =1)