Fusion d'un Shapefile et d'un dataframe
Je travaille Ravec un dataframe régulier ( df) et un shapefile ( map2), le partage une colonne commune appelée CD116FP. dfa 103552 lignes tandis qu'en map2a 444 .Je charge le fichier de formes de la manière suivante:
map2 <- read_sf ("D: /Data/tl_2019_us_cd116.shp")
Mon objectif final est d'utiliser la fonction mapview()pour afficher la carte incluse dans map2avec "l'intensité" qui est décrite dans dfsous la colonne np_scores. Je ne veux donc pas que des observations à dfce sujet n'apparaissent pas map2.
Voici mes pensées et mes échecs:
Si ces deux objets étaient des dataframes régulières, un candidat raisonnable serait d'utiliser
merge()pour combiner les deux objets, mais si vous appliquez cette fonction dans ce cas, l'objet résultant perd les propriétés spatiales etmapviewne sait pas comment les lire.Une autre approche que j'ai utilisée a été d'essayer cette ligne de code:
map2m <-data.frame (map2, df [match (map2$CD116FP, df$CD116FP),])
Mais le résultat a des dimensions trop grandes (beaucoup plus grandes que 444 lignes) et se mapviewbloque donc lorsque vous essayez de tracer la carte souhaitée.
- Enfin, je suis allé à fond sur la force brute et j'ai juste construit une boucle pour ajouter la colonne
npà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}
}
}
Cependant, cette approche prend trop de temps compte tenu des dimensions de mon dataframe.
Avez-vous des suggestions?
Réponses
Je suis un peu perplexe face à la structure de vos données. Votre dfa plus de 100 000 lignes, donc je suppose que la même chose CD116FPse produit plusieurs fois dans df, et le npscorevariera vraisemblablement entre ces instances. Si vous souhaitez les fusionner, map2vous devrez d'abord les agréger.
Essayons de recréer une configuration similaire:
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
J'ai fait dfavoir le même nombre de lignes que vos données doivent montrer que cette solution s'adaptera à votre problème.
Agrégons le npscoresavec 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)]
A maintenant map2l'agrégé, npscoresnous pouvons tracer - par exemple, dans 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")
Ou dans mapview:
library(mapview)
mapView(map2, zcol = "npscores")
J'ai eu un peu de chance avec l'utilisation de l'ancien mergedu package de base. Voici un extrait de mon propre travail si cela vous est utile :-)
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"))