29  데이터프레임 분석

OpenAI에서 플러그인으로 출시한 코드 인터프리터(code interpreter)는 자연어 질문이나 요청을 받아 코드를 작성하고 실행하는 데 초점을 맞춘 도구다. 파이썬으로 프로그래밍 관련 문제를 해결하거나, 특정 알고리즘을 구현하는 데 유용하다. 사용자는 자연어로 복잡한 코드를 작성하거나 디버깅하는 과정 없이도 원하는 코드를 작성할 수 있고 결과도 직접 실행시켜 확인할 수 있다.

반면, OpenAI에서 코드 인터프리터를 고급 데이터 분석(advanced data analytics)으로 명칭을 변경한 후에 출시한 도구는 더 복잡한 데이터 분석과 시각화 기능을 제공한다. 코드 인터프리터가 실시간 코드 실행과 테스트에 초점을 맞춘 반면, 고급 데이터 분석은 복잡한 데이터 분석과 시각화에 초점을 두어 인사이트와 의사결정 지원에 기능이 특화되어 있다.

OpenAI에서 챗GPT에 플러그인 형태로 제공되던 코드 인터프리터와 고급 데이터 분석 기능은 챗 인터페이스에 하나로 통합되어 입력 데이터 유형에 따라 자동으로 코드 인터프리터와 고급 데이터 분석 기능이 활성화되어 실행되는 것으로 변경되었다.

29.1 광명시 인구현황 분석

29.1.1 데이터 수집

행정안전부 주민등록 인구 및 세대현황 웹사이트에서 광명시 2023년 7월 기준 인구현황 데이터를 가져온다.

library(tidyverse)
library(readxl)

raw_data <- read_excel("data/202307_202307_연령별인구현황_월간.xlsx", skip =3) 

raw_data |> 
  janitor::clean_names(ascii = FALSE) |> 
  select(1:5) |> 
  head() |> 
  gt::gt()
행정기관코드 행정기관 총_인구수 연령구간인구수_4 x0세_5
4121000000 경기도 경기도 광명시 280,986 280,986 1,373
4121051000 경기도 광명시 광명1동 56 56 0
4121052000 경기도 광명시 광명2동 2,953 2,953 9
4121054000 경기도 광명시 광명3동 9,869 9,869 29
4121055000 경기도 광명시 광명4동 8,114 8,114 35
4121056000 경기도 광명시 광명5동 12,206 12,206 41
표 29.1: 광명시 인구현황 원데이터

29.1.2 가공 데이터

행정안전부 주민등록 인구 및 세대현황 원데이터는 분석에 적합한 형태가 아니다. wide 형 데이터는 기계가 처리하기에는 적절하지 못한 형태이므로, long 형 데이터로 변환하여 후속 작업에 활용한다.

library(tidyverse)

pop_tbl <- 
  read_rds("data/kwangmyung_pop.rds")

pop_tbl |> 
  head() |> 
  gt::gt()
시점 행정동 성별 나이 인구수
2023-07-15 광명1동 남자 0 0
2023-07-15 광명1동 남자 1 0
2023-07-15 광명1동 남자 2 0
2023-07-15 광명1동 남자 3 0
2023-07-15 광명1동 남자 4 0
2023-07-15 광명1동 남자 5 0
표 29.2: 광명시 인구현황 가공데이터

29.1.3 챗GPT 데이터 변환

데이터를 가공한 후 챗GPT Code Interpreter 분석용으로 변환하여 데이터를 전송한다. .rds는 바이너리 파일형태로 챗GPT 코드 인터프리터, 고급 데이터 분석 서비스에 적합하지 않은 형태라서 .csv 파일로 변환하여 전송한다.

pop_tbl |> 
  write_csv("data/kwangmyung_pop.csv")
그림 29.1: 코드 인터프리터 광명시 인구분석 작업흐름

29.2 챗GPT Code Interpreter

현재는 사라진 챗GPT 코드 인터프리터 플러그인을 통해, 광명시 인구 데이터를 다루기 위해 파이썬 코드를 직접 작성하고 실행하는 대신, 자연어로 질문하거나 요청을 하면 챗GPT가 자동으로 코드를 작성하고 실행한다. 이렇게 생성된 코드의 실행 결과는 다음에 나와 있다.

29.3 마무리 작업

챗GPT 플러그인이 자연어를 파이썬 코드로 변경하고 실행한 결과를 출력하지만 한글 글꼴이 없기 때문에 한글이 깨져서 출력되는 것은 물론 시각화를 위한 프롬프트 의도를 제대로 이해하지 못하고 고급 시각화 기능을 구현하는데는 한계가 있다. 하지만, 자연어를 통해 빠르게 데이터 분석결과를 확인하고 대략적인 방향을 잡는 것에는 분명 큰 도움이 된다.

29.3.1 연도별 인구수

연도별 인구수를 시각화하는 마무리 작업은 파이썬 코드를 R로 챗GPT가 번역한 초벌 R 코드를 바탕으로 수정하여 시각화 작업을 마무리한다.

library(tidyverse)

pop_tbl <- 
  read_rds("data/kwangmyung_pop.rds")

pop_tbl |> 
  mutate(시점 = ymd(시점)) |> 
  mutate(연도 = year(시점)) |> 
  group_by(연도) |> 
  summarise(인구수 = sum(인구수)) |> 
  ggplot(aes(x=연도, y=인구수)) +
    geom_line(color="skyblue", size=1.5) +
    geom_point(color="blue", size=3) +
    labs(title="광명시 인구수 변화", x="", y="인구수(명)",
         caption = "데이터 출처: 행정안전부 주민등록 인구 및 세대현황") +
    theme_minimal() +
    scale_y_continuous(labels = scales::comma)
그림 29.2: 광명시 인구수 연도별 변화

29.3.2 동별 인구수

동별 인구수도 한글이 깨지는 문제가 챗GPT에서는 있었지만 R 코드로 번역된 결과를 수정하여 시각화 작업을 수행하면 깔끔하게 마무리할 수 있다.

pop_tbl |> 
  mutate(시점 = ymd(시점)) |> 
  mutate(연도 = year(시점)) |> 
  group_by(연도, 행정동) |> 
  summarise(인구수 = sum(인구수)) |> 
  ggplot(aes(x=연도, y=인구수, color = 행정동, group=행정동)) +
    geom_line(size=1.5) +
    geom_point(color="blue", size=3) +
    labs(title="광명시 동별 인구수 변화", x="", y="인구수(명)",
         caption = "데이터 출처: 행정안전부 주민등록 인구 및 세대현황") +
    theme_minimal() +
    scale_y_continuous(labels = scales::comma)
그림 29.3: 광명시 동별 인구수 변화

29.3.3 유권자 비율

유권자 비율에 대한 원그래프 작성도 챗GPT가 번역한 R 코드를 수정하여 시각화 작업을 마무리한다.

pop_tbl |> 
  mutate(시점 = ymd(시점)) |> 
  mutate(연도 = year(시점)) |> 
  mutate(유권자 = ifelse(나이 >=18, "유권자", "비유권자"),
         유권자 = factor(유권자, levels = c("비유권자", '유권자'))) |> 
  group_by(유권자) |> 
  summarise(인구수 = sum(인구수)) |> 
  ggplot(aes(x="", y=인구수, fill = 유권자)) +
    geom_bar(width = 1, stat = "identity") +
    coord_polar("y")  +
    labs(title="광명시 유권자 비율",
         caption = "데이터 출처: 행정안전부 주민등록 인구 및 세대현황",
         fill = "구분") +
    theme_minimal() +
    scale_y_continuous(labels = scales::comma) +
    scale_fill_manual(values = c(유권자 = "blue", 비유권자="red"))
그림 29.4: 광명시 유권자수

29.3.4 내림차순 유권자수

동별로 내림차순으로 유권자수를 정렬하여 시각화하는 작업은 챗GPT를 통해 구현하기 까다로운 작업이다. 하지만 대략적인 데이터 분석 결과를 챗GPT를 통해 확인하고 마무리는 번역된 R 코드를 기반으로 작업하면 새로운 방식으로 시각화 작업을 수행할 수 있다.

pop_tbl |> 
  mutate(시점 = ymd(시점)) |> 
  mutate(연도 = year(시점)) |> 
  filter(연도 == max(연도)) |> 
  mutate(유권자 = ifelse(나이 >=18, "유권자", "비유권자"),
         유권자 = factor(유권자, levels = c("비유권자", '유권자'))) |> 
  group_by(행정동, 유권자) |> 
  summarise(인구수 = sum(인구수)) |> 
  mutate(유권자비율 = 인구수/sum(인구수)) |> 
  ungroup() |> 
    
  # pivot_wider(names_from = 유권자, values_from = 인구수) |> 
  # mutate(유권자비율 = 유권자/(비유권자+유권자)) |> 
  # arrange(desc(유권자비율))

  # 시각화 -----------------
  ggplot(aes(x=fct_reorder2(행정동, 유권자, 유권자비율), y=유권자비율, fill = 유권자)) +
    geom_col() +
    coord_flip() +
    labs(title="광명시 동별 유권자 비율",
         caption = "데이터 출처: 행정안전부 주민등록 인구 및 세대현황",
         fill = "구분",
         x = "") +
    theme_minimal() +
    scale_y_continuous(labels = scales::percent) +
    scale_fill_manual(values = c(유권자 = "blue", 비유권자="red")) +
    theme(legend.position = "top")
그림 29.5: 광명시 동별 유권자수

29.4 요약

OpenAI의 코드 인터프리터(Code Interpreter)와 고급 데이터 분석(advanced data analytics) 플러그인은 자연어 질문을 통해 코드 작성과 데이터 분석을 보다 편리하게 수행할 수 있도록 한다. 광명시 인구현황 데이터를 수집하고 가공한 후 데이터 분석과 시각화를 수행해 보았다.

실습을 통해 광명시 연도별 인구 추이, 동별 인구 분포, 유권자 비율 등을 분석하고 시각화함으로써 광명시 인구 현황에 대한 전반적인 이해를 높일 수 있었다. 특히 챗GPT 코드 인터프리터를 활용하면 복잡한 코드 작성 과정 없이도 원하는 분석 결과를 빠르게 얻을 수 있어 데이터 분석 작업의 효율성을 크게 높일 수 있다.

또한 고급 데이터 분석 기능을 통해 다양한 시각화 옵션을 제공받을 수 있어 인사이트 도출에도 큰 도움이 된다. 앞으로도 새로운 데이터와 분석 주제에 챗GPT를 적극 활용해 보시길 추천하며, AI와 함께 데이터 분석 역량을 한층 더 높이고 보다 가치 있는 인사이트를 발견할 수 있을 것이다.