Scalanie Shapefile i Dataframe
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:
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 imapviewnie będzie wiedział, jak go odczytać.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.
- W końcu zdecydowałem się na brutalną siłę i po prostu zbudowałem pętlę, aby dodać kolumnę
npdomap2:
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
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")
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"))