공공데이터 분석 및 시각화 실습

뉴스보도 활용을 중심으로

신종화(한국R사용자회/공공의창)

신종화 소개:

  • 고려대 사회학과 졸업, 영국 워릭대 사회학박사

  • 헬싱키경제대학(현, Aalto대학교) E-MBA (ITBiz)

  • 전) 고려대학교 연구교수, 서울과학종합대학원 조교수

  • 현) 한국R사용자회 사무총장, 조원씨앤아이 CRO, 공공의창 공동대표

    • 빅데이터분석도구 R인액션(번역), 데이터자동화도구 챗GPT와 유닉스쉘(공저)

    • R Commander 및 Limesurvey 한글화 책임, R 관련 다수 패키지, 대쉬보드 제작

    • 여론조사 데이터, 텍스트마이닝, 텍스트데이터 시각화

챗GPT시대의 데이터분석

  • 대화형 LLM 도구 사용: chatGPT, Gemini, Claude, …

    • 추천: claude.ai (무료버전의 안정성 높음)
  • 스크립트형 통계언어(R, Python 등) 사용 도전

    • 추천: R (통계학기반)
  • 통합 개발 환경(Integrated Development Environment, IDE) 사용 도전

    • 추천: Posit Rstudio (대시보드 제작용이)

“어려운 코딩 문법에 눌리지않고, 창의력과 논리구조의 흐름 이해 중요”

API

데이터 분석에서 API(Application Programming Interface)는 다음과 같은 이유로 필요:

  1. 데이터 수집: API를 통해 다양한 외부 데이터 소스(미디어, 금융 데이터, 날씨 등)에서 데이터를 수집

  2. 자동화: API를 활용하면 데이터 수집, 처리, 분석 과정을 자동화할 수 있어 효율성이 향상

  3. 실시간 분석: API를 통해 실시간으로 데이터를 받아와 분석

  4. 확장성: API를 사용하면 다양한 애플리케이션, 서비스, 데이터베이스 등과 연동하는 확장성

  5. 표준화: API는 데이터 교환을 위한 표준화된 방법을 제공하여 다른 시스템과의 통합을 용이

XML, JSON

API는 주로 XML, JSON 형식을 사용하여 데이터를 주고받음

CSV, XLSX, SAV 등의 파일 형식과 직접적으로 연결되진 않음

  • XML과 JSON은 구조화된 데이터 형식으로, API를 통해 전송되기에 적합
예를 들어:
  • API로 받은 JSON 데이터를 파싱하여 데이터프레임으로 변환한 후, CSV나 XLSX 파일로 저장

  • CSV, XLSX, SAV 파일에서 데이터를 읽어와 JSON 형식으로 변환한 후, API를 통해 전송

사례: NEIS (공공데이터 포탈)

# 교육부나이스(NEIS) 교육정보 개방 포털_특수학교 시간표

Sheet vs API

# A tibble: 100 × 14
   ATPT_OFCDC_SC_CODE ATPT_OFCDC_SC_NM     SD_SCHUL_CODE SCHUL_NM    AY    SEM  
   <chr>              <chr>                <chr>         <chr>       <chr> <chr>
 1 T10                제주특별자치도교육청 9290083       제주영지학… 2023  1    
 2 T10                제주특별자치도교육청 9290083       제주영지학… 2023  1    
 3 T10                제주특별자치도교육청 9290083       제주영지학… 2023  1    
 4 T10                제주특별자치도교육청 9290083       제주영지학… 2023  1    
 5 T10                제주특별자치도교육청 9290083       제주영지학… 2023  1    
 6 T10                제주특별자치도교육청 9290083       제주영지학… 2023  1    
 7 T10                제주특별자치도교육청 9290083       제주영지학… 2023  1    
 8 T10                제주특별자치도교육청 9290083       제주영지학… 2023  1    
 9 T10                제주특별자치도교육청 9290083       제주영지학… 2023  1    
10 T10                제주특별자치도교육청 9290083       제주영지학… 2023  1    
# ℹ 90 more rows
# ℹ 8 more variables: ALL_TI_YMD <chr>, SCHUL_CRSE_SC_NM <chr>, GRADE <chr>,
#   CLRM_NM <chr>, CLASS_NM <chr>, PERIO <chr>, ITRT_CNTNT <chr>,
#   LOAD_DTM <chr>
[1] "테스트입니다"
[1] "필수신청인자 시도교육청코드, 표준학교코드 특수학교시간표 https://open.neis.go.kr/hub/spsTimetable?ATPT_OFCDC_SC_CODE=T10&SD_SCHUL_CODE=9290083"

R 코드보기

library(httr)
library(xml2)
library(purrr)

# API 엔드포인트 URL
url <- "https://open.neis.go.kr/hub/spsTimetable"

# 요청 파라미터
params <- list(
  KEY = "6a1df1dece1c4abbba17597eb5ce5ae1",
  ATPT_OFCDC_SC_CODE = "T10",  # 시도교육청코드 (예: 제주특별자치도교육청)
  SD_SCHUL_CODE = "9290083"  # 표준학교코드 (예: 제주영지학교)
)

# API 호출
response <- GET(url, query = params)

# 응답 확인
if (status_code(response) == 200) {
  # 응답 데이터 파싱
  data <- content(response, "text")

  # XML 파싱
  xml_data <- read_xml(data)

  # XML 데이터를 데이터프레임으로 변환
  df <- xml_find_all(xml_data, "//row") %>%
    map_dfr(~ xml_children(.x) %>%
              map(xml_text) %>%
              as.list() %>%
              setNames(xml_name(xml_children(.x))))

  # 데이터프레임 출력
  print(df)

  # 테스트 출력
  print("테스트입니다")
  print(paste("필수신청인자 시도교육청코드, 표준학교코드 특수학교시간표",
              "https://open.neis.go.kr/hub/spsTimetable?ATPT_OFCDC_SC_CODE=T10&SD_SCHUL_CODE=9290083"))
} else {
  print(paste("API request failed with status code:", status_code(response)))
  print(http_status(response)$message)  # 상태 메시지 출력
}

XML 파일 불러오기

# A tibble: 10,001 × 14
   ATPT_OFCDC_SC_CODE ATPT_OFCDC_SC_NM SD_SCHUL_CODE SCHUL_NM AY     SEM  
   <chr>              <chr>            <chr>         <chr>    <chr>  <chr>
 1 시도교육청코드     시도교육청명     행정표준코드  학교명   학년도 학기 
 2 B10                서울특별시교육청 7010575       교남학교 2024   1    
 3 B10                서울특별시교육청 7010575       교남학교 2024   1    
 4 B10                서울특별시교육청 7010575       교남학교 2024   1    
 5 B10                서울특별시교육청 7010575       교남학교 2024   1    
 6 B10                서울특별시교육청 7010575       교남학교 2024   1    
 7 B10                서울특별시교육청 7010575       교남학교 2024   1    
 8 B10                서울특별시교육청 7010575       교남학교 2024   1    
 9 B10                서울특별시교육청 7010575       교남학교 2024   1    
10 B10                서울특별시교육청 7010575       교남학교 2024   1    
# ℹ 9,991 more rows
# ℹ 8 more variables: ALL_TI_YMD <chr>, SCHUL_CRSE_SC_NM <chr>, GRADE <chr>,
#   CLRM_NM <chr>, CLASS_NM <chr>, PERIO <chr>, ITRT_CNTNT <chr>,
#   LOAD_DTM <chr>

R 코드보기

library(xml2)
library(dplyr)

# XML 파일 읽기
setwd("~/문서/Business/data.go.kr")  # XML 파일 경로로 대체
xml_data <- read_xml("특수학교시간표.xml")

# XML 데이터를 데이터프레임으로 변환
df <- xml_find_all(xml_data, "//row") %>%
  map_dfr(~ xml_children(.x) %>%
            map(xml_text) %>%
            as.list() %>%
            setNames(xml_name(xml_children(.x))))

# 데이터프레임 출력
print(df)

# install.packages("httr")
library(httr)
library(jsonlite)

client_id = "3q6zCNYi53BPlRh3cjIF" # 여러분의 클라이언트 ID
client_secret = "OFYZtuyWw3" # 여러분의 클라이언트 시크릿

# API 요청 URL 및 헤더
url <- "https://openapi.naver.com/v1/search/news.json"
headers <- add_headers(
  "X-Naver-Client-Id" = client_id,
  "X-Naver-Client-Secret" = client_secret
)

# 요청 파라미터
params <- list(query = "\"특수학교\"", display = 100, sort = "date")

# API 요청
response <- GET(url, query = params, config = headers)

# 응답 확인
content <- content(response, as = "text", encoding = "UTF-8")
json_content <- jsonlite::fromJSON(content)

# JSON을 데이터프레임으로 변환
df <- as.data.frame(json_content$items)

# 데이터프레임 확인
print(df)

# CSV 파일로 저장
setwd("~/문서/Business/naver")
write.csv(df, "naver_news.csv", row.names = FALSE)

사례: Jowncni 언론보도 관리

언론데이터 vs 데이터 저널리즘

  • 기사를 분석할 것인가? [텍스트데이터 분석]

    • 기사 분석 사례: 일간, 분야, 주간

    • 워드클라우드 제작 사례: 조원씨앤아이

    • 핵심 기사(군) 이슈 찾기: AI기반? 비AI 기반 요약?

  • 기사를 위한 데이터 분석을 할 것인가?

    • 데이터 구조, 유형 파악

    • data visualization vs. infographics - 재활용의 난이도

    • 데이터 관리(통합, 가공, 편집) 역량 강화

데이터프레임 이해

  • 행(row), 열(column) 결합의 테이블형 데이트 구조 + 변수(필드) 이름

  • 각 변수(필드)는 동일유형의 사례 목록 보유

  • 규칙성에 기반한 사례 위치 (indexing), 자료 병합/나누기

  • 변수의 이해

    • 셀수있는가?(counting)

    • 사칙연산이 가능한가?

    • 쪼개기-붙이기: 음절,단어, 문장, 문단, 글 등

  • ‘분석’의 기저에는 ’비교’(차이, 변화발견)의 문제의식

집단비교(차이유무)

  • 성별(남녀), 연령대(성인, 10세), 지역(광역시도, 권역)

  • 이념성향(진보, 보수, 중도), 혼인(싱글, 기혼)

  • 소득(개인, 가구) 구간

예: 성별 * 연령대 * 지역 = 2*7*17 (238개 집단)

시간의 흐름(추이, 추세, 트렌드)

  • 일, 요일, 주5일, 주, 격주, 달, 분기, 반기, 년

  • 4년(지방선거, 총선), 5년(대통령선거), 보궐선거

막대그래프: 정책질문1 + 집단비교

막대그래프: (정책질문1 + 집단)시간비교1

선 그래프: 정책질문1(+ 추세/추이)

  • 동일 질문의 오랜 기간 반복조사, 누적 자료 활용, 추세 경향 파악

히트맵: 정책1+정책2/집단1

  • 특이성 관련 징후적 정보 제공, 통찰력 고취 효과

산점도: 정책1 + 정책2 (+집단1)

  • 질문들(답변흐름)간의 상관관계 여부 문제의식

텍스트 데이터 시각화: ‘대세’ 파악/요약

  • 워드 클라우드

    1. 주제어의 비중의 차이: 단어의 등장/반복쓰임의 크기

    2. 핵심 주제어 확인이라는 문제의식에 집중

  • 텍스트 네트워크

    • 주제어들의 비중의 차이: 주로 연속적 두 단어의 등장/반복쓰임의 빈도

    • 주제어들의 ‘지형’ 파악이라는 상황적 이해에 집중

    [오늘을 요약할 수 있는가? (분야별)] <오늘 언론 동향>

  • 주제어 추세

    • 주제어 사용(등장/쓰임)의 흐름 파악

    • 주제어/주제의 등장, 강세/약세, 소멸 파악 <주간 언론 동향>

자료 공유(업데이트)

사이트 접속 ➡️RPubs - 공공데이터 분석과 시각화실습