Отображение ближайших соседей набора данных длинной широты с использованием ggmap, geom_point и цикла

Моя конечная цель — соединить всех ближайших соседей набора зданий (на основе евклидова расстояния) на ggmap, используя geom_path из пакета ggplot2. Мне нужна помощь с циклом, который позволит мне максимально легко построить все соседи

Я создал матрицу расстояний (называемую «kmnew») в километрах между тремя типами зданий в Пекине: B (x2), D (x2) и L (x1):

   B        B        D        D        L
B NA 6.599014 5.758531 6.285787 3.770175
B NA       NA 7.141096 3.873296 5.092667
D NA       NA       NA 3.690725 2.563017
D NA       NA       NA       NA 2.832083
L NA       NA       NA       NA       NA

Я пытаюсь определить ближайших соседей каждого здания по строке, объявив матрицу и используя цикл для определения ближайшего соседнего здания:

nn <- matrix(NA,nrow=5,ncol=1)


for (i in 1:nrow(kmnew)){
  nn[i,] <- which.min(kmnew[i,]) 
}

Это возвращает следующую ошибку (не уверен, почему):

Error in nn[i, ] <- which.min(kmnew[i, ]) : replacement has length zero

но, кажется, возвращает правильный ответ на nn:

     [,1]
[1,]    5
[2,]    4
[3,]    5
[4,]    5
[5,]   NA

Я добавляю это к исходному кадру данных с именем newbjdata:

colbj <- cbind(newbjdata,nn)

который возвращает

  Name Store sqft     long      lat nn
1    B     1 1200 116.4579 39.93921  5
2    B     2  750 116.3811 39.93312  4
3    D     1  550 116.4417 39.88882  5
4    D     2  600 116.4022 39.90222  5
5    L     1 1000 116.4333 39.91100 NA

Затем я получаю свою карту через ggmap:

bjgmap <- get_map(location = c(lon = 116.407395,lat = 39.904211),
                  zoom = 13, scale = "auto",
                  maptype = "roadmap",
                  messaging = FALSE, urlonly = FALSE,
                  filename = "ggmaptemp", crop = TRUE,
                  color = "bw",
                  source = "google", api_key)

Моя конечная цель — сопоставить ближайших соседей вместе на графике, используя geom_path из пакета ggplot.

Например, номер 1-го корпуса типа Б (1-й ряд) — это 1-й корпус типа Л (5-й ряд). Очевидно, я могу нарисовать эту линию, подставив указанные 2 строки фрейма данных таким образом:

ggmap(bjgmap) +
geom_point(data = colbj, aes(x = long,y = lat, fill = factor(Name)),
           size =10, pch = 21, col = "white") +
geom_path(data = subset(colbj[c(1,5),]), aes(x = long,y = lat),col = "black")

Однако мне нужно решение, которое работает как цикл, и я не могу понять, как этого можно добиться, поскольку мне нужно ссылаться на столбец nn и возвращать его к длинным данным lat n раз. Я вполне могу поверить, что использую не самый эффективный метод, поэтому открыт для альтернатив. Любая помощь высоко ценится.


person RichS    schedule 12.04.2015    source источник
comment
Не могли бы вы объяснить, что вы имеете в виду, говоря, что nn 1-го здания типа B (ряд 1) является 1-м зданием типа L (ряд 5)? Я этого не понимаю. Как вы хотите рисовать линии? Вот у вас на карте 5 точек. Что бы вы хотели в итоге?   -  person jazzurro    schedule 12.04.2015
comment
Столбец ближайшего соседа (nn) моего фрейма данных относится к строке, к которой относится ближайший сосед. Таким образом, nn (ближайший сосед) строки 1 (B store 1) — это строка 5 (L store 1). Моя цель — соединить всех ближайших соседей линией (geom_path), так как я соединил эти два вручную в минимальном примере, за исключением более автоматизированного способа, чем я достиг с помощью «подмножества». Большое спасибо!   -  person RichS    schedule 12.04.2015
comment
Это означает, что у вас есть одна линия, идущая куда-то из каждой точки данных. Это правильно?   -  person jazzurro    schedule 12.04.2015
comment
Готово. Надеюсь, вам нужно следующее.   -  person jazzurro    schedule 12.04.2015


Ответы (1)


Вот моя попытка. Я использовал gcIntermediate() из пакета geosphere для настройки линий. Во-первых, мне нужно было изменить ваши данные. Когда вы используете gcIntermediate(), вам нужно долгота/широта отправления и прибытия. То есть вам нужно четыре столбца. Чтобы упорядочить ваши данные таким образом, я использовал пакет dplyr. mutate_each(colbj, funs(.[nn]), vars = long:lat) работает для вас, чтобы подобрать желаемую долготу/широту прибытия. . для «длинного» и «широтного». [nn] — индекс вектора для переменных. Затем я нанял gcIntermediate(). Это создает SpatialLines. Вам нужно сделать объект SpatialLinesDataFrame. Затем вам нужно преобразовать вывод в «обычный» data.frame. Этот шаг необходим, чтобы ggplot мог прочитать ваши данные. fortify() выполняет свою работу.

library(ggmap)
library(geosphere)
library(dplyr)
library(ggplot2)

### Arrange the data: set up departure and arrival long/lat

mutate_each(colbj, funs(.[nn]), vars = long:lat) %>%
rename(arr_long = vars1, arr_lat = vars2) %>%
filter(complete.cases(nn)) -> mydf

### Get line information

rts <- gcIntermediate(mydf[,c("long", "lat")],
                      mydf[,c("arr_long", "arr_lat")],
                      50,
                      breakAtDateLine = FALSE,
                      addStartEnd = TRUE,
                      sp = TRUE)

### Convert the routes to a data frame for ggplot use

rts <- as(rts, "SpatialLinesDataFrame")
rts.df <- fortify(rts)


### Get a map (borrowing the OP's code)                   
bjgmap <- get_map(location = c(lon = 116.407395,lat = 39.904211),
                  zoom = 13, scale = "auto",
                  maptype = "roadmap",
                  messaging = FALSE, urlonly = FALSE,
                  filename = "ggmaptemp", crop = TRUE,
                  color = "bw",
                  source = "google", api_key)

# Draw the map
ggmap(bjgmap) +
geom_point(data = colbj,aes(x = long, y = lat, fill = factor(Name)),
           size = 10,pch = 21, col = "white") +
geom_path(data = rts.df, aes(x = long, y = lat, group = group),
          col = "black")

введите здесь описание изображения

РЕДАКТИРОВАТЬ

Если вы хотите выполнить все манипуляции с данными в одной последовательности, следующий способ — один из способов. foo идентично rts.df выше.

mutate_each(colbj, funs(.[nn]), vars = long:lat) %>%
rename(arr_long = vars1, arr_lat = vars2) %>%
filter(complete.cases(nn)) %>%
do(fortify(as(gcIntermediate(.[,c("long", "lat")],
                          .[,c("arr_long", "arr_lat")],
                          50,
                          breakAtDateLine = FALSE,
                          addStartEnd = TRUE,
                          sp = TRUE), "SpatialLinesDataFrame"))) -> foo

identical(rts.df, foo)
#[1] TRUE

ДАННЫЕ

colbj <- structure(list(Name = structure(c(1L, 1L, 2L, 2L, 3L), .Label = c("B", 
"D", "L"), class = "factor"), Store = c(1L, 2L, 1L, 2L, 1L), 
sqft = c(1200L, 750L, 550L, 600L, 1000L), long = c(116.4579, 
116.3811, 116.4417, 116.4022, 116.4333), lat = c(39.93921, 
39.93312, 39.88882, 39.90222, 39.911), nn = c(5L, 4L, 5L, 
5L, NA)), .Names = c("Name", "Store", "sqft", "long", "lat", 
"nn"), class = "data.frame", row.names = c("1", "2", "3", "4", 
"5"))
person jazzurro    schedule 12.04.2015
comment
Это именно тот результат, который я искал. Большое спасибо за это, jazzurro. Я не знаком с gcIntermediate, но, похоже, должен. Мне понадобится некоторое время, чтобы понять это, но еще раз это чрезвычайно полезно и сверх того, что я ожидал. Благодарю вас! - person RichS; 12.04.2015
comment
@RichS Я рад слышать, что это то, что вы хотели. Возможно, есть и другие способы сделать ту же работу. Но это то, что я знаю, исходя из своего опыта. Обычно я так решаю задачи по рисованию линий между двумя точками. Посмотрите руководство CRAN по геосфере. В качестве альтернативы ищите другие пакеты. Вы можете найти более короткие решения. :) - person jazzurro; 13.04.2015