Scalanie Shapefile i Dataframe

Sep 17 2020

Pracuję Rze zwykłą ramką danych ( df) i plikiem shapefile ( map2), udział wspólną kolumną o nazwie CD116FP. dfma 103552 linie, podczas gdy map2ma 444. Ładuję plik shapefile w następujący sposób:

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

Moim celem końcowym jest użycie funkcji, mapview()aby wyświetlić mapę zawartą w programie map2z „intensywnością” opisaną w dfkolumnie np_scores. Dlatego nie chcę, aby obserwacje dftego się nie pojawiały map2.

Oto moje myśli i porażki:

  1. Gdyby te dwa obiekty były zwykłymi ramkami danych, rozsądnym kandydatem byłoby merge()połączenie obu obiektów, jednak jeśli zastosujesz tę funkcję w tym przypadku, wynikowy obiekt straci właściwości przestrzenne i mapviewnie będzie wiedział, jak go odczytać.

  2. Innym podejściem, które zastosowałem, było wypróbowanie tego wiersza kodu:

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

Ale wynik ma zbyt duże wymiary (znacznie większe niż 444 linie) i dlatego mapviewulega awarii podczas próby wykreślenia żądanej mapy.

  1. W końcu zdecydowałem się na brutalną siłę i po prostu zbudowałem pętlę, aby dodać kolumnę npdo 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}  
}
}  

Jednak takie podejście zajmuje zbyt dużo czasu, biorąc pod uwagę wymiary mojej ramki danych.

Masz jakieś sugestie?

Odpowiedzi

3 AllanCameron Sep 19 2020 at 22:24

Trochę mnie dziwi struktura twoich danych. Twój dfma ponad 100 000 wierszy, więc domyślam się, że to samo CD116FPdzieje się wiele razy dfi npscoreprawdopodobnie będzie się różnić w tych przypadkach. Jeśli chcesz je scalić map2, musisz najpierw je zagregować.

Spróbujmy odtworzyć podobną konfigurację:

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

Zrobiłem, że dfma taką samą liczbę wierszy, że twoje dane muszą pokazać, że to rozwiązanie będzie skalowane do twojego problemu.

Zsumujmy to npscoresz 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)]

Teraz mamy map2zagregowane dane, npscoresktóre możemy wykreślić - na przykład w 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")

Lub w widoku mapy:

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

Utworzono 19.09.2020 r. Przez pakiet reprex (v0.3.0)

Alexa Sep 25 2020 at 17:24

Miałem trochę szczęścia, używając zwykłego starego mergez pakietu podstawowego. Oto fragment mojej własnej pracy, jeśli ma to dla Ciebie wartość :-)

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