Hợp nhất Shapefile và dataframe

Sep 17 2020

Tôi đang làm việc Rvới dataframe thông thường ( df) và shapefile ( map2), cột chia sẻ chung được gọi là CD116FP. dfcó 103552 dòng trong khi có 444. map2Tôi đang tải tệp hình dạng theo cách sau:

map2 <- read_sf ("D: /Data/tl_2019_us_cd116.shp")

Mục tiêu cuối cùng của tôi là sử dụng chức năng mapview()để xem bản đồ được bao gồm trong map2"cường độ" được mô tả trong dfcột np_scores. Do đó tôi không muốn các quan sát về dfđiều đó không xuất hiện trên map2.

Đây là những suy nghĩ và thất bại của tôi:

  1. Nếu hai đối tượng này là khung dữ liệu thông thường, một ứng cử viên hợp lý sẽ là sử dụng merge()để kết hợp cả hai đối tượng, tuy nhiên nếu bạn áp dụng hàm đó trong trường hợp này, đối tượng kết quả sẽ mất các thuộc tính không gian và mapviewkhông biết cách đọc nó.

  2. Một cách tiếp cận khác mà tôi đã sử dụng là thử dòng mã này:

map2m <-data.frame (map2, df [match (map2$CD116FP, df$CD116FP),])

Nhưng kết quả có kích thước quá lớn (lớn hơn nhiều là 444 dòng) và do đó mapviewbị lỗi khi cố gắng vẽ bản đồ mong muốn.

  1. Cuối cùng, tôi đã sử dụng toàn bộ lực lượng vũ phu và chỉ tạo một vòng lặp để thêm cột npvào map2:
map2$np=10 for (i in c(1:nrow(map2))) { for (j in c(1:nrow(df))) { if (identical(map2$CD116FP[i],df$CD116FP[j])) {map2$np[i]=df$np_score[j]} else {map2$np[i]=0}  
}
}  

Tuy nhiên, cách tiếp cận này chỉ tốn quá nhiều thời gian so với kích thước của khung dữ liệu của tôi.

Bạn có đề nghị nào không?

Trả lời

3 AllanCameron Sep 19 2020 at 22:24

Tôi hơi khó hiểu với cấu trúc dữ liệu của bạn. Của bạn dfcó hơn 100.000 hàng, vì vậy tôi đoán rằng điều tương tự CD116FPxảy ra nhiều lần trong dfvà npscorecó lẽ sẽ khác nhau trong các trường hợp này. Nếu bạn muốn hợp nhất chúng với nhau, map2bạn sẽ cần phải tổng hợp chúng trước.

Hãy thử tạo lại một thiết lập tương tự:

library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

map2 <- read_sf("C:/users/administrator/documents/shape/tl_2019_us_cd116.shp")

set.seed(69)

df <- data.frame(CD116FP = sprintf("%02d", sample(0:99, 103552, TRUE)),
                 npscores = runif(103552))

head(df)
#>   CD116FP  npscores
#> 1      95 0.6927742
#> 2      80 0.8543845
#> 3      90 0.5220353
#> 4      01 0.1449647
#> 5      76 0.9876543
#> 6      38 0.5629950

Tôi đã thực hiện dfcó cùng số hàng mà dữ liệu của bạn có để hiển thị giải pháp này sẽ mở rộng cho vấn đề của bạn.

Hãy tổng hợp npscoresvới dplyr:

library(dplyr)
df_sum <- df %>% 
  filter(CD116FP %in% map2$CD116FP) %>% group_by(CD116FP) %>% summarise(npscores = mean(npscores)) map2$npscores <- df_sum$npscores[match(map2$CD116FP, df_sum$CD116FP)]

Bây giờ chúng ta có thể lập biểu đồ map2tổng hợp npscores- ví dụ: trong ggplot:

library(ggplot2)

ggplot(map2) + 
  geom_sf(aes(fill = npscores)) +
  coord_sf(xlim = c(-180, -60),
            ylim = c(15, 70)) +
  scale_fill_gradient(low = "red", high = "gold")

Hoặc trong mapview:

library(mapview)
mapView(map2, zcol = "npscores")

Được tạo vào 2020-09-19 bởi gói reprex (v0.3.0)

Alexa Sep 25 2020 at 17:24

Tôi đã gặp một số may mắn khi sử dụng phiên bản cũ mergetừ gói cơ sở. Đây là một đoạn trích từ tác phẩm của riêng tôi nếu điều này có giá trị đối với bạn :-)

my_data <- read_excel("TraderDataRaw.xlsx", 
      sheet = "fsa", 
      col_types= c("text","text","text","logical","numeric","numeric")) %>% 
      mutate(resp_rate=mailed/responses)

my_map <- st_read("lfsa000b16a_e.shp", stringsAsFactors = FALSE) 

my_merged_data <- merge(my_map, my_data, 
      by.x=c("CFSAUID","PRUID","PRNAME"), 
      by.y=c("CFSAUID","PRUID","PRNAME"))