1 석탄 발전소

1.1 데이터

미세먼지 주범 석탄화력발전소, 대선 후보 입장은? 한겨례 신문 2017년 기사를 보면 석탄화력발전소에 대한 구체적인 정보가 담겨있다. World Resources Institute Global Power Plant Database 에서 전세계 화력발전소 중 한국만 추려 본다.

library(tidyverse)
library(reactable)

plant_df <- read_csv("data/globalpowerplantdatabasev120/global_power_plant_database.csv")

plant_tbl <- plant_df %>% 
  filter(country == "KOR") %>% 
  select("name", "capacity_mw", "latitude", "longitude", fuel = "primary_fuel", year = "commissioning_year", "owner", "url", 
generation_gwh = "estimated_generation_gwh")

plant_tbl %>% 
  reactable::reactable()

2 석탄 발전소 위치

석탄 발전소만 추려 지도에 시각화 시켜보자.

library(glue)
library(leaflet)

plant_tbl %>% 
  filter(fuel == "Coal") %>% 
  leaflet() %>% 
    addProviderTiles(provider = providers$OpenStreetMap) %>% 
    addMarkers(lng=~longitude, lat = ~latitude, clusterOptions = markerClusterOptions(),
               popup = ~ as.character(glue("<strong> {name} </strong> <br>
                                           &middot; 회사: {owner}<br>
                                           &middot; 용량: {scales::comma(capacity_mw, accuracy = 1) } MW<br>
                                           &middot; 발전: {scales::comma(generation_gwh, accuracy = 1)} GWh<br>
                                           &middot; 연료: {fuel}")))

2.1 석탄 발전소 용량

석탄 발전소 용량을 기준으로 시도 경계를 추가하여 가시성을 높여보자.

library(sf)

korea_sf <- st_read("data/map/HangJeongDong_ver20201001.geojson")
Reading layer `1' from data source `C:\docs\esg\data\map\HangJeongDong_ver20201001.geojson' using driver `GeoJSON'
Simple feature collection with 3492 features and 8 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 124.6097 ymin: 33.11187 xmax: 131.8713 ymax: 38.61695
Geodetic CRS:  WGS 84
sido_sf <- korea_sf %>% 
  group_by(sido, sidonm) %>% 
  summarise(cnt = n()) %>% 
  ungroup() %>% 
  select(-cnt)

plant_tbl %>% 
  filter(fuel == "Coal") %>% 
  leaflet() %>% 
    ## 석탄 화력 발전소 위치 --------------------------------------
    addProviderTiles(provider = providers$OpenStreetMap) %>% 
    addMarkers(lng=~longitude, lat = ~latitude, clusterOptions = markerClusterOptions(),
               popup = ~ as.character(glue("<strong> {name} </strong> <br>
                                           &middot; 회사: {owner}<br>
                                           &middot; 용량: {scales::comma(capacity_mw, accuracy = 1) } MW<br>
                                           &middot; 발전: {scales::comma(generation_gwh, accuracy = 1)} GWh<br>
                                           &middot; 연료: {fuel}"))) %>% 
    addCircleMarkers( radius = ~ (capacity_mw)^(1/2),
                      stroke = FALSE, fillOpacity = 0.5) %>% 
    ## 시도 경계 shapefile --------------------------------------
    addPolygons(data = sido_sf, opacity = 1.0, fillOpacity = 0.1,
            weight = 1,
            highlightOptions = highlightOptions(color = "black", weight = 3,  bringToFront = TRUE),
            labelOptions = labelOptions(
            style = list("font-weight" = "normal", padding = "3px 8px"),
            textsize = "15px",
            direction = "auto"))

2.2 석탄 발전소 발전량

추정 발전량을 기준으로 시도 경계를 포함시켜 지도 위에 시각화를 해 보자.

plant_tbl %>% 
  filter(fuel == "Coal") %>% 
  leaflet() %>% 
    ## 석탄 화력 발전소 위치 --------------------------------------
    addProviderTiles(provider = providers$OpenStreetMap) %>% 
    addMarkers(lng=~longitude, lat = ~latitude, clusterOptions = markerClusterOptions(),
               popup = ~ as.character(glue("<strong> {name} </strong> <br>
                                           &middot; 회사: {owner}<br>
                                           &middot; 용량: {scales::comma(capacity_mw, accuracy = 1) } MW<br>
                                           &middot; 발전: {scales::comma(generation_gwh, accuracy = 1)} GWh<br>
                                           &middot; 연료: {fuel}"))) %>% 
    addCircleMarkers( radius = ~ (generation_gwh)^(1/3),
                      stroke = FALSE, fillOpacity = 0.5) %>% 
    ## 시도 경계 shapefile --------------------------------------
    addPolygons(data = sido_sf, opacity = 1.0, fillOpacity = 0.1,
            weight = 1,
            highlightOptions = highlightOptions(color = "black", weight = 3,  bringToFront = TRUE),
            labelOptions = labelOptions(
            style = list("font-weight" = "normal", padding = "3px 8px"),
            textsize = "15px",
            direction = "auto"))

3 폐암

3.1 폐암 데이터셋

건강보험심사평가원 암질환 평가 정보에서 데이터를 다운로드 받아 준비한다.

  • 평가수행항목: 간암, 대장암, 위암, 유방암, 폐암
  • 평가결과는 5개 등급으로 나누어 공개(간암은 수술사망률에 대해 평가)
  • 간암 평가결과는 홈페이지에서 확인(www.hira.or.kr)
  • 평가항목별 대상 진료분 상이
  • 대장암·폐암: 2016년 진료분 대상
  • 위암·유방암: 2017년 진료분 대상
  • 2019.10월 요양기관 현황 기준
library(jsonlite)

cancer_meta <- fromJSON("data/cancer_meta.json") %>% as.data.frame

cancer_meta %>% 
  pivot_longer(cols = everything(), names_to = "항목", values_to = "상세정보")
# A tibble: 15 x 2
   항목                    상세정보                                             
   <chr>                   <chr>                                                
 1 name                    건강보험심사평가원_암질환 평가 정보                  
 2 description             평가수행항목: 간암, 대장암, 위암, 유방암, 폐암 / 평가결과는 5개 등급으로 나누어 공개(~
 3 url                     https://www.data.go.kr/data/15052118/fileData.do     
 4 keywords                병원평가,암질환,건강보험                             
 5 license                 https://data.go.kr/ugs/selectPortalPolicyView.do     
 6 creator.name            건강보험심사평가원                                   
 7 creator.contactPoint.c~ 빅데이터실 빅데이터전략부                            
 8 creator.contactPoint.t~ +82-0337391047                                       
 9 creator.contactPoint..~ ContactPoint                                         
10 creator..type           Organization                                         
11 distribution.encodingF~ CSV                                                  
12 distribution.contentUrl https://www.data.go.kr/cmm/cmm/fileDownload.do?atchF~
13 distribution..type      DataDownload                                         
14 X.context               https://schema.org                                   
15 X.type                  Dataset                                              

데이터를 다운로드 받아 대략적인 제공 데이터 형태를 살펴본다.

cancer_df <- read_csv("data/건강보험심사평가원_암질환 평가 정보_20191031.csv", locale=locale('ko', encoding='euc-kr'))

cancer_df %>% 
  reactable(columns = list(
    병원명          = colDef(name = "병원명",   minWidth = 120),
    평가항목        = colDef(name = "평가항목", minWidth = 50),
    평가등급        = colDef(name = "평가등급", minWidth = 50),
    소재지          = colDef(name = "소재지",   minWidth = 210)
  ))

3.2 폐암 일반현황

환자별 암질환 정보를 살펴보자.

cancer_df %>% 
  count(평가항목, name = "환자수", sort = TRUE) %>% 
  mutate(비율 = 환자수 / sum(환자수) * 100)
# A tibble: 4 x 3
  평가항목 환자수  비율
  <chr>     <int> <dbl>
1 대장암      230  31.2
2 위암        204  27.7
3 유방암      183  24.9
4 폐암        119  16.2

3.3 병원별 환자

hospital_tbl <- cancer_df %>% 
  filter(평가항목 == "폐암") %>% 
  mutate(병원명칭 = case_when(
    str_detect(병원명, "가톨릭") ~ "가톨릭",
    str_detect(병원명, "고려대")  ~ "고려대",
    str_detect(병원명, "순천향")  ~ "순천향",
    str_detect(병원명, "효신")  ~ "효신",
    str_detect(병원명, "경희")  ~ "경희",
    str_detect(병원명, "삼성")  ~ "삼성",
    str_detect(병원명, "서울대")  ~ "서울대",
    str_detect(병원명, "연세")  ~ "연세",
    str_detect(병원명, "인제")  ~ "인제",
    str_detect(병원명, "한림")  ~ "한림",
    str_detect(병원명, "한양")  ~ "한양",
    str_detect(병원명, "국립")  ~ "국립암",
                TRUE             ~  병원명)) %>% 
  count(병원명칭, sort = TRUE)  

hospital_tbl 
# A tibble: 89 x 2
   병원명칭     n
   <chr>    <int>
 1 가톨릭      10
 2 인제         5
 3 한림         5
 4 순천향       4
 5 고려대       3
 6 삼성         3
 7 연세         3
 8 경희         2
 9 국립암       2
10 서울대       2
# ... with 79 more rows

4 Geocoding

4.1 카카오 API

다음 카카오 API를 사용해서 주소정보를 제공하고 위경도를 받아온다.

library(httr)

# geocoding 함수 --------------------------------------
get_lonlat <- function(query_address) {

  daum_resp <- GET(url = 'https://dapi.kakao.com/v2/local/search/address.json',
                   query = list(query = query_address),
                   add_headers(Authorization = paste0("KakaoAK ", Sys.getenv("DAUM_MAP_API_KEY"))))
  
  daum_list <- daum_resp %>% 
  content(as = 'text') %>% 
  fromJSON()
  
  lon_lat <- daum_list$documents$road_address %>% 
    select(lng = x, lat = y)
  
  return(lon_lat)
}

safely_get_lonlat <- safely(get_lonlat, otherwise = NA_real_)


lung_df <- cancer_df %>% 
  filter(평가항목 == "폐암")

geocoding_list <- map(lung_df$소재지, safely_get_lonlat)

geocoding_list %>% 
  write_rds("data/geocoding_list.rds")
geocoding_list <- 
  read_rds("data/geocoding_list.rds")

# 지오코딩 결과 저장 --------------------------------------
listviewer::jsonedit(geocoding_list)

4.2 데이터 추출

중간에 결측값이 있어 이에 대한 보정 및 수정 작업을 수행한다.

lnglat_tbl <- tibble( lng = map(geocoding_list, "result") %>% map_chr(., "lng", .default = NA) %>% as.numeric,
                      lat = map(geocoding_list, "result") %>% map_chr(., "lat", .default = NA) %>% as.numeric)

lnglat_tbl
# A tibble: 119 x 2
     lng   lat
   <dbl> <dbl>
 1  127.  37.5
 2  127.  37.3
 3  127.  37.5
 4  127.  37.6
 5  127.  37.5
 6  127.  37.8
 7  127.  37.5
 8  127.  37.6
 9  129.  37.8
10  127.  37.6
# ... with 109 more rows

4.3 데이터 결합

폐암환자와 폐암환자 소재지 정보를 지오코딩한 결과를 결합시킨다.

lung_df <- cancer_df %>% 
  filter(평가항목 == "폐암")

lung_tbl <- lung_df %>% 
  bind_cols(lnglat_tbl)

5 시각화

5.1 폐암환자

library(glue)
library(leaflet)

lung_tbl %>% 
  leaflet() %>% 
    addProviderTiles(provider = providers$OpenStreetMap) %>% 
    addMarkers(lng=~lng, lat = ~lat, clusterOptions = markerClusterOptions(),
               popup = ~ as.character(glue("<strong> {병원명} </strong> <br>
                                           &middot; 평가항목: {평가항목}<br>
                                           &middot; 평가등급: {평가등급} <br>
                                           &middot; 소재지: {소재지 }")))

5.2 석탄 발전소 + 폐암환자

석탄 발전소 위치와 폐암 환자 위치를 함께 지도위에 시각화 시킨다.

library(sf)

korea_sf <- st_read("data/map/HangJeongDong_ver20201001.geojson")
Reading layer `1' from data source `C:\docs\esg\data\map\HangJeongDong_ver20201001.geojson' using driver `GeoJSON'
Simple feature collection with 3492 features and 8 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 124.6097 ymin: 33.11187 xmax: 131.8713 ymax: 38.61695
Geodetic CRS:  WGS 84
powerplant <- makeIcon("Factory", "fig/noun_Factory_3373027.png", 37, 37)
patient    <- makeIcon("Patient", "fig/noun_Patient_2071003.png", 37, 37)


plant_tbl %>% 
  filter(fuel == "Coal") %>% 
  leaflet() %>% 
    ## 석탄 화력 발전소 위치 --------------------------------------
    addProviderTiles(provider = providers$OpenStreetMap) %>% 
    addMarkers(lng=~longitude, lat = ~latitude, clusterOptions = markerClusterOptions(),
                      icon=powerplant,
               popup = ~ as.character(glue("<strong> {name} </strong> <br>
                                           &middot; 회사: {owner}<br>
                                           &middot; 용량: {scales::comma(capacity_mw, accuracy = 1) } MW<br>
                                           &middot; 발전: {scales::comma(generation_gwh, accuracy = 1)} GWh<br>
                                           &middot; 연료: {fuel}"))) %>% 
    addCircleMarkers( radius = ~ (capacity_mw)^(1/2),
                      stroke = FALSE, fillOpacity = 0.5) %>% 
    ## 시도 경계 shapefile --------------------------------------
    addPolygons( data = sido_sf, opacity = 1.0, fillOpacity = 0.1,
            weight = 1,
            highlightOptions = highlightOptions(color = "black", weight = 3,  bringToFront = TRUE),
            labelOptions = labelOptions(
            style = list("font-weight" = "normal", padding = "3px 8px"),
            textsize = "15px",
            direction = "auto")) %>% 
    addMarkers( data = lung_tbl, lng=~lng, lat = ~lat, icon = patient,
               popup = ~ as.character(glue("<strong> {병원명} </strong> <br>
                                           &middot; 평가항목: {평가항목}<br>
                                           &middot; 평가등급: {평가등급} <br>
                                           &middot; 소재지: {소재지 }")))
 

데이터 과학자 이광춘 저작

kwangchun.lee.7@gmail.com