关于你提到的第一个问题:由于数据是经度/纬度,一种方法是在包fossil
使用earth.dist(...)
(计算大圆DIST):
library(fossil)
d = earth.dist(df) # distance object
另一种方法在geosphere
包使用distHaversine(...)
:
geo.dist = function(df) {
require(geosphere)
d <- function(i,z){ # z[1:2] contain long, lat
dist <- rep(0,nrow(z))
dist[i:nrow(z)] <- distHaversine(z[i:nrow(z),1:2],z[i,1:2])
return(dist)
}
dm <- do.call(cbind,lapply(1:nrow(df),d,df))
return(as.dist(dm))
}
这里的好处是,你可以使用任何的其他距离算法geosphere
,或者你可以定义你自己的距离函数并用它代替distHaversine(...)
。然后应用任何的基础R聚类技术(例如,k均值,hclust):
km <- kmeans(geo.dist(df),centers=3) # k-means, 3 clusters
hc <- hclust(geo.dist(df)) # hierarchical clustering, dendrogram
clust <- cutree(hc, k=3) # cut the dendrogram to generate 3 clusters
最后,一个真实的例子:
setwd("<directory with all files...>")
cities <- read.csv("GeoLiteCity-Location.csv",header=T,skip=1)
set.seed(123)
CA <- cities[cities$country=="US" & cities$region=="CA",]
CA <- CA[sample(1:nrow(CA),100),] # 100 random cities in California
df <- data.frame(long=CA$long, lat=CA$lat, city=CA$city)
d <- geo.dist(df) # distance matrix
hc <- hclust(d) # hierarchical clustering
plot(hc) # dendrogram suggests 4 clusters
df$clust <- cutree(hc,k=4)
library(ggplot2)
library(rgdal)
map.US <- readOGR(dsn=".", layer="tl_2013_us_state")
map.CA <- map.US[map.US$NAME=="California",]
map.df <- fortify(map.CA)
ggplot(map.df)+
geom_path(aes(x=long, y=lat, group=group))+
geom_point(data=df, aes(x=long, y=lat, color=factor(clust)), size=4)+
scale_color_discrete("Cluster")+
coord_fixed()
城市数据是从GeoLite。美国国家shapefile来自Census Bureau。
编辑响应@ Anony-慕斯评论:
它可能看起来奇怪,“LA”是两个集群之间的分歧,但是,扩大地图显示,对于城市的这种随机选择,有是第3组和第4组之间的差距。第4组基本上是圣莫尼卡和伯班克;第3组是帕萨迪纳,南洛杉矶,长滩以及南部的所有地方。
K-means聚类(4簇)确实将LA/Santa Monica/Burbank/Long Beach周围的区域保存在一个簇中(见下文)。这只是归结于kmeans(...)
和hclust(...)
所使用的不同算法。
km <- kmeans(d, centers=4)
df$clust <- km$cluster
值得一提的是,这些方法都需要所有的点都必须进入一些集群。如果你只是问哪些点靠得很近,并且允许一些城市没有进入任何聚类,你会得到非常不同的结果。
嗯......洛杉矶分为两个聚类算法?看起来有什么问题。 –
如果您运行的数据大小超过200万条记录,这不会造成问题 –