在 R 中复制聚类过程

Replicating a Clustering Procedure in R

我正在尝试使用 R 复制类似于以下 paper 中描述的聚类过程。第 7 页和第 8 页详细讨论了聚类过程.我有一系列货件的始发地和目的地坐标,我想将货件集中到地理区域中。但是,在应用 R 中的 k-means 过程之前,我不完全确定我需要以何种形式构建我的空间数据。

我最初的想法是论文的输入数据看起来像这样:

Olat    Olong    Dlat    Dlong   Dist.Vol

34.271  -86.217  34.838 -81.686  226.6021
30.889  -87.776  30.689 -88.049  400
33.524  -86.805  34.167 -84.789  674.07
33.524  -86.805 34.779  -82.311  1100.66
33.524  -86.805 36.159  -86.791  800
34.201  -86.166 40.019  -82.878  2350
31.158  -88.016 45.524  -122.675 6711.44
.         .       .      .       .       
.         .       .      .       .       
.         .       .      .       .       
31.158  -88.016 32.084  -81.1   1301.85

在那种情况下,在 R 中执行我的 k-means 聚类会像下面这样简单:

input <- cbind( data$Olat, data$Olong, data$Dlat, data$Dlong, data$Dist.Vol)
results <- kmeans( data, 20)   # 20 determined optimal in paper

我一直很难想象这个过程的结果。我能够找到的大多数空间 k 均值聚类示例仅包含一组纬度和经度坐标。

我不确定我是否应该或如何在我的聚类过程中考虑源目的地关系。如果能得到任何帮助,我将不胜感激。谢谢。

编辑

我很清楚如何使用 Haversine 函数计算非欧几里得距离。我无法理解这段话的确切含义:

"With k-means, each coordinate is first weighted proportionally to its frequency at both the origin and destination. Then according to a predetermined number, clusters are formed by minimizing the weighted distance between coordinates."

对于每个不同的始发地和目的地(纬度、经度)组合,我可以计算它同时作为目的地和始发地出现的频率,然后将其乘以平均装运距离吗?在考虑起点和终点之间的关系的同时,我不确定如何在二维中执行 k-means 算法。

lat    long        Dist*Vol

34.271  -86.217     226.6021
30.889  -87.776     400
.         .            .
.         .            .
.         .            .
31.158  -88.016     1301.85

看起来您基于 5 个不同的特征进行聚类 - Olong、Olat、Dlong、Dlat 和 Dist.Vol。

如果你想创建空间集群,你只需要有两个特征。如果我理解正确,你应该将 Olong 与 Dlong 和 Olat 与 Dlat rbind。

 data <- data.frame(lat = c(data$Olat,data$Dlat), lon = c(data$Olong,data$Dlong)

然后你可以在这个二维上应用 k-means space。

 results <- kmeans(data, 20)

请注意,使用欧几里德距离(k-means 的默认值)不是此处度量的正确选择。你应该使用 Haversine or project your points to a Cartesian space.

关于可视化——设置 k-means 后,您可以绘制质心 + a Voronoi diagram. Looks like this is the case in the paper. See this question 以获得更多详细信息:

更新

我决定只关注大量出境装运区域,从而在某种程度上简化了我的问题。现在,我的输入数据带有 5,000 个不同的城市,并附有平均统计数据 CPM= 每英里成本和 Volume= 出境货运数量。

Oid    Long      Lat    CPM    Volume
203   -85.251   31.579  1.661   97
 .      .         .       .     .

我想根据地理距离和每英里平均出境成本进行聚类。为了考虑到数量,我根据出货量 Volume 在我的输入矩阵中复制了每个 Oid(始发城市)。为此,我使用了以下代码:

Distinct.Origins <- read.csv(".... file path... ")

by_origin <- group_by(Distinct.Origins, Oid)
o.expand  <- by_origin[rep(seq(nrow(by_origin)), by_origin$Volume), 1:9]  # 9 columns in data.frame

input <- as.data.frame(cbind(o.expand$Olong, o.expand$Olat, o.expand$CPM))
colnames(input) <- c("long", "lat", "CPM")

# To get a sense of what this looks like Oid = 203 now has 97 rows

head(input)
     long    lat      CPM
 -85.251 31.579 1.661815
 -85.251 31.579 1.661815
 -85.251 31.579 1.661815
 -85.251 31.579 1.661815
 -85.251 31.579 1.661815
 -85.251 31.579 1.661815

接下来我 运行 我实际的 kmeans 聚类程序。

set.seed(123)
km <- kmeans(input, 12)
cent <- as.data.frame(km$centers)

然后我创建了一个 Voronoi Plot 来可视化我的数据,如下所示

# Voronoi Plot
V <- deldir(cent$long, cent$lat)
states <- map_data("state")
Statemap <- ggplot() + geom_polygon(data = states, aes(x = long, y = lat, group = group), fill = "light green", col="black")

clust.state <- Statemap + geom_point(data = input, aes(x = long, y = lat), col = factor(km$cluster))
clust.state <- clust.state + geom_label(data = cent, aes(x = long, y = lat), label = row.names(cent))     

clust.state <- clust.state + geom_segment(data = V$dirsgs, aes(x=x1, y = y1, xend = x2, yend = y2), size = 2)

总结

这并不能完全解决我原来的问题,但我选择 post 希望

  1. 收到额外的反馈,以便我可以进行进一步的改进(特别是在我的 kmeans 输入矩阵或 Voronoi 图上)
  2. 希望它能帮助其他人在他们自己的地理聚类问题上取得进展