Mesclando um Shapefile e um dataframe

Sep 17 2020

Estou trabalhando Rcom um dataframe regular ( df) e um shapefile ( map2), o compartilhamento de uma coluna comum chamada CD116FP. dftem 103552 linhas enquanto map2tem 444. Estou carregando o shapefile da seguinte maneira:

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

Meu objetivo final é usar a função mapview()para visualizar o mapa incluído map2com a "intensidade" descrita na dfcoluna np_scores. Portanto, não quero observações de dfque não apareçam map2.

Aqui estão meus pensamentos e falhas:

  1. Se esses dois objetos fossem dataframes regulares, um candidato razoável seria usar merge()para combinar os dois objetos; no entanto, se você aplicar essa função neste caso, o objeto resultante perde as propriedades espaciais e mapviewnão sabe como lê-lo.

  2. Outra abordagem que usei foi tentar esta linha de código:

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

Mas o resultado tem dimensões muito grandes (muito maiores que 444 linhas) e, portanto, mapviewfalha ao tentar plotar o mapa desejado.

  1. Por fim, usei força bruta total e acabei de construir um loop para adicionar a coluna npa 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}  
}
}  

No entanto, essa abordagem leva muito tempo, dadas as dimensões do meu dataframe.

Você tem alguma sugestão?

Respostas

3 AllanCameron Sep 19 2020 at 22:24

Estou um pouco intrigado com a estrutura dos seus dados. Seu dftem mais de 100.000 linhas, então estou supondo que o mesmo CD116FPocorre várias vezes em df, e npscoreprovavelmente irá variar entre essas instâncias. Se você quiser mesclá- map2los, precisará agregá-los primeiro.

Vamos tentar recriar uma configuração semelhante:

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

Eu criei dfo mesmo número de linhas que seus dados têm para mostrar que essa solução será dimensionada para seu problema.

Vamos agregar npscorescom 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)]

Agora map2tem o agregado npscoresque podemos plotar - por exemplo, no 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 no mapview:

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

Criado em 19-09-2020 pelo pacote reprex (v0.3.0)

Alexa Sep 25 2020 at 17:24

Tive sorte com o uso mergedo pacote básico. Aqui está um trecho do meu próprio trabalho, se isso for valioso para você :-)

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