2015-04-12 2 views
3

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

Я создал матрицу расстояний (называемую «kmnew») в километрах от трех типов зданий в Пекине: B (x2), D (х2) и 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 

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

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

я добавляю это к оригинальной dataframe называется 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.

Например, nn 1-го здания типа B (строка 1) является 1-м зданием типа L (строка 5). Очевидно, что я могу сделать эту линию Подменят указанные 2 строк в dataframe таким образом:

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 и ссылаться на него на длинные латинские данные n раз. Я вполне могу поверить, что я не использую самый эффективный метод, поэтому я открыт для альтернатив. Любая помощь очень ценится.

+0

Не могли бы вы объяснить, что вы имеете в виду, говоря «пп 1-го здания типа В (строка 1) является 1 здание типа L (строка 5)»? Я этого не понимаю. Как вы хотите нарисовать линии? Здесь у вас есть 5 баллов на вашей карте. Что бы вы хотели в конце? – jazzurro

+0

Столбец ближайшего соседа (nn) моего фрейма данных относится к тому, какая строка является ближайшим соседом. Таким образом, nn (ближайший сосед) строки 1 (B store 1) является строкой 5 (L store 1). Моя цель - соединить всех ближайших соседей по строке (geom_path), так как я подключил эти два вручную в минимальном примере, за исключением более автоматизированного способа, чем я достиг с использованием «подмножества». Большое спасибо! – RichS

+0

Это означает, что у вас есть одна строка, идущая куда-то из каждой точки данных. Это верно? – jazzurro

ответ

0

Вот моя попытка. Я использовал gcIntermediate() из пакета geosphere, чтобы настроить линии. Во-первых, мне нужно было изменить ваши данные. Когда вы используете gcIntermediate(), вам необходимо уехать и прибыть долго/лат. Вам нужно четыре столбца. Чтобы упорядочить ваши данные таким образом, я использовал пакет dplyr. mutate_each(colbj, funs(.[nn]), vars = long:lat) работает для вас, чтобы забрать желаемое прибытие долго/лат. . - для '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") 

enter image description here

EDIT

Если вы хотите, чтобы сделать все манипуляции с данными в одной последовательности, следующий один путь. 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 

DATA

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")) 
+0

Именно так я и искал. Большое спасибо за это, джаззурро. Я не знаком с gcIntermediate, но, похоже, должен быть. Потребуется некоторое время, чтобы разглядеть его, но снова это очень полезно и выше того, что я ожидал. Спасибо! – RichS

+0

@RichS Я рад слышать, что это то, что вы хотели. Могут быть другие способы выполнения одной и той же работы. Но это то, что я знаю, основываясь на моем опыте. Таким образом, я обычно обрабатываю задачи, рисуя линии между двумя точками. Взгляните на руководство CRAN по геосфере. Также можно искать другие пакеты. Вы можете найти более короткие решения. :) – jazzurro

Смежные вопросы