brunch

You can make anything
by writing

C.S.Lewis

by 지은 x NULL Oct 12. 2019

[뉴스 속 데이터분석] 인구통계 뉴스는 정말 사실일까?

뭔가 좀 이상한데?

일전에 국회 특수활동비를 확인했던 것처럼 어제(10월 11일)자 저녁 뉴스 [사실은] '갈라진 광장' 들여다보니…둘 다 외면한 '20대' 에서 출발하는 이야기다.



20대가 왜?


짧은 리포트에서 분석과정을 설명할 순 없었겠지만 20대 수치가 광화문 0.9%, 서초동 5.7%라는 건 무슨 말인가 싶었다. 정치적 이슈는 논외로, 숫자의 의미를 살펴보고자 했다.

뉴스에서 알려준대로 서울시 생활인구 통계 데이터를 받아봤다. 일(日)별 80MB 내외, 데이터 수량으로는 45~46만줄 정도 되는 걸 알 수 있다. 전년도, 전전년도까지 찾아서 사용한 데이터는 다음과 같다.

 [1] "LOCAL_PEOPLE_20170929.csv" "LOCAL_PEOPLE_20170930.csv" "LOCAL_PEOPLE_20171001.csv" "LOCAL_PEOPLE_20171002.csv"
 [5] "LOCAL_PEOPLE_20171003.csv" "LOCAL_PEOPLE_20171004.csv" "LOCAL_PEOPLE_20171005.csv" "LOCAL_PEOPLE_20171006.csv"
 [9] "LOCAL_PEOPLE_20171007.csv" "LOCAL_PEOPLE_20171008.csv" "LOCAL_PEOPLE_20181001.csv" "LOCAL_PEOPLE_20181002.csv"
[13] "LOCAL_PEOPLE_20181003.csv" "LOCAL_PEOPLE_20181004.csv" "LOCAL_PEOPLE_20181005.csv" "LOCAL_PEOPLE_20181006.csv"
[17] "LOCAL_PEOPLE_20181007.csv" "LOCAL_PEOPLE_20181008.csv" "LOCAL_PEOPLE_20190930.csv" "LOCAL_PEOPLE_20191001.csv"
[21] "LOCAL_PEOPLE_20191002.csv" "LOCAL_PEOPLE_20191003.csv" "LOCAL_PEOPLE_20191004.csv" "LOCAL_PEOPLE_20191005.csv"
[25] "LOCAL_PEOPLE_20191006.csv"


집계구는 뉴스에서 자세한 설명이 없었는데, 다른 기사에 그림이 있어 똑같이 설정했다. shp파일을 열어보겠다고 GIS 프로그램도 처음 접해가면서 광화문 11개, 서초 21개의 코드를 확인했다. 기사 본문에는 24개를 확인했다고 하는데, 캡쳐시점 이후 분석과정에서 달라진 듯하다. 실제 지도와 겹쳐서 확인해봤으나 임의로 3개를 추가하는 게 적절치 않아 보여서 21개만 이용했다. 행정동보다 세분화된 집계구 코드가 궁금하다면 아래 캡쳐를 참고 바란다.


광화문과 서초동 일대


library(dplyr)
library(readr)
집계구 <- read_csv("집계구.csv", col_types = cols(TOT_REG_CD = col_double()),
                locale = locale(encoding = "CP949"))
LOCAL_PEOPLE <- read_csv('파일경로') %>% filter(집계구코드 %in% `집계구`$TOT_REG_CD)


하얀 건 글자요, 까만 건 바탕이로다.

가벼운 마음으로 열어보려고 한 건데 시작부터 엄청난 난관이다. 쫙 펼쳐져 있는 숫자를 보고 혹자는 깔끔하게 정리된 데이터라고 생각하겠지만 재가공하는 데는 영 적절치 않다. 이미 LOCAL_PEOPLE에는 필요한 집계구만 뽑아왔으므로 또 한번 필요한 컬럼만 선별하여 데이터를 합산 + 행을 축소한다. 11개 집계구 중 어느 곳에 더 사람이 몰리는지, 분포가 어떻게 되는지는 중요치 않다는 얘기다.


data_wide <- LOCAL_PEOPLE %>% group_by(기준일ID, 시간대구분) %>%
    summarise_at(.vars = (colnames(x)[6:33]), .funs = c(n="sum"))


필요한 데이터를 필요한 형태(long)로 바꿔서 컬럼을 적절히 추가해준다. 컬럼명(텍스트)으로 돼있는 성별과 연령대를 쓸 수 있는 변수로 나눠줬다. 방법은 여러 가지겠지만 여기선 맨 앞 두 글자를 보고 1과 2로 구분하고, 세 번째 숫자 단자리를 뽑아서 10을 곱해 연령대를 적었다.(원 데이터는 5개년씩 구분돼있다.)


library(tidyr)
data_long <- gather(data_wide, age_gender, n, `남자0세부터9세생활인구수_n`:`여자70세이상생활인구수_n`)
data_long$gender <- ifelse(substr(data_long$age_gender, 1, 2)=="남자", 1, 2)
data_long$age <- as.integer(substr(data_long$age_gender, 3, 3)) * 10

refine_data <- data_long %>% group_by(기준일ID, 시간대구분, age, gender) %>% tally(n)


전처리를 마치면 대략 이런 형태가 된다. 필요하다면 성별로도 확인할 수 있게 해뒀다.

# A tibble: 9,600 x 5
# Groups:   기준일ID, 시간대구분, age [4,800]
   기준일ID 시간대구분   age gender     n
      <dbl>      <dbl> <dbl>  <dbl> <dbl>
 1 20170929          0     0      1   457
 2 20170929          0     0      2   481
 3 20170929          0    10      1   457
 4 20170929          0    10      2   997
 5 20170929          0    20      1  4209
 6 20170929          0    20      2  2940
 7 20170929          0    30      1  5579
 8 20170929          0    30      2  3165
 9 20170929          0    40      1  5325
10 20170929          0    40      2  2665
# … with 9,590 more rows




10월 3일 광화문


이제 쓸 만한 데이터가 된 것 같으니 그림을 그려보자. 먼저 광화문 데이터다. 10월 3일자 데이터만 subset하고 연도별로 차트를 나눴다.

library(ggplot2)
y <- subset(x, subset = (day=="03"))
ggplot(y, mapping = aes(x = time, fill = age, color = age)) +
  geom_bar(mapping = (aes(y = n)), stat = "identity") +
  facet_wrap(facets = y$year)


왼쪽부터 재작년, 작년, 올해. 낮시간대 증가폭이 어마어마하게 두드러진다.


기사에 나온대로 오후 2시에 가장 사람들이 몰렸고 전후시간도 비슷한 형태를 따른다. 기준 시간대가 충분히 대표성을 가진다고 볼 수 있겠다. 이 그림을 보고 든 생각은 광화문 일대가 1년만에 괄목할 만한 변화가 있어서 유동인구가 급격히 늘어난 건 아닌가 싶어...-그럴 리 없다는 건 이미 알지만- 다른 데이터도 확인해봤다.


각 연도별 개천절 전날(좌)과 다음날(우) 시간대 인구 통계


놀랍도록 유사하다. 참고로 2017년은 개천절부터 한글날까지 추석을 포함한 장기간의 황금연휴였다. 전후 날짜로 10월 3일의 데이터가 평소 추세와 달랐음을 확인했다. 그럼 다시 개천절 당일의 차이가 얼마나 되는 걸까. 뉴스에서는 평시 상주인구(집회와 무관한 인원)를 제외하고자 축제, 연휴, 집회와 같은 행사가 없는 일자를 선정해서 계산했다고 한다. 9월 7일 토요일과 9월 29일 일요일이었는데, 계절/날씨 같은 변수도 많아서 완전히 적합한지는 다소 의문이다.

그래서, 기준일자±1일 * 데이터를 확보할 수 있는 3개년도('17, '18, '19) = 총 9일 중 해당 날짜(target)를 제외한 8일을 기준으로 삼아서 '예측'해봤다.

데이터가 8개 뿐이지만 연령별로 구분된 데이터를 펼쳐서 시계열로 간주하고, ARIMA 모형을 사용해서 예측(Prediction)한 수치다. 모델링이 충분하지 않았기에 파라미터를 이리저리 바꿔가며 plot 결과가 직관적으로 타당해'보이는' 값을 선정했다.

auto.arima(ts_data)
fit <- arima(ts_data, c(2,0,1), seasonal = list(order = c(2,1,1), period = 8))
pred <- predict(fit, n.ahead = 8)
ts.plot(ts_data, pred$pred, lty = c(1,3))
어느 쪽이 잘 예측한 것일까? 본 글에선 우측의 모형을 선택했다.


이제 결론에 거의 다다랐다. 예측이라고 했지만 사실 우린 이미 답을 알고 있다. 그 예측치와 실제 인원과의 차이가 (아마도) 집회와 관련된 증감 인구라고 할 수 있을 것이다. 아래 차트에서 빨간색이 평소와 다른 행동 패턴을 보인 인구다. 20대까지는 여느 때와 비슷한 인원이 인구통계 데이터로 집계됐고, 30대부터 70대까지, 연령이 올라갈수록 급증하는 모습이다.

단, Y축 값이 100만이나 된다고 해서 너무 놀라진 말라. 뉴스 기사와는 다르게 하루 전체를 집계했으므로 연(延)인원이라고 보면 된다. 쉽게 말해 10시간 동안 해당 장소에 머물렀다면 10(명)으로 카운트된 것이다. 따라서 아래 차트를 해석할 때 50대보다 70세 이상이 3배나 많이 모였거나 아니면 동일한 인원 수로 3배쯤 오래 머물렀을 수도 있다.

그래서 중복카운트가 없도록 다시 기준 시간의 데이터만 분리해봤다.

기사의 숫자와 거의 흡사하다.(비교 날짜와 방법이 다르기 때문에 정확히 들어맞진 않는다.) 어떤 방법을 쓰더라도 집계구라든지 여러 가지 문제로 집회 참석 인구를 정확히 가려낼 수는 없다. 하지만 이정도의 시각화만으로 연령대별 분포는 확연히 드러났다. 그럼 동일한 방식으로 서초동의 데이터도 확인해봐야겠다.




10월 5일 서초동


전년도와 그래프 모양이 확연히 다른 건 광화문 데이터와 비슷하지만, 왠지 빨간색(장년층)이 눈에 덜 띄는 것 같기도.



공휴일이 아니므로 날짜가 아닌 요일로 비교했다. 역시 위 차트에 비하면 아주 평범하다.


다시, 알고 싶은 건 평년 대비 gap이 얼마나 되는가다. 아래 차트에서 빨간색 부분이다. 보통날이었다면 초록색 만큼 인구가 있었을 텐데 빨간색 만큼 추가로 몰린 것이다.


와우. 데이터의 해석은 여러분에게 맡긴다.


끝으로 연인원을 걸러서 보기 위한 기준시간대의 스냅샷이다.(척도가 다 다르다.)





"서초동은 40~50대가, 광화문은 60세 이상이 이끌었다."

-라는, 해당 기사의 서브 타이틀이, 팩트를 기반으로 했음을 확인했다.

다만 둘 다 외면한 '20대'라는 헤드라인에는 의문이 남는다.


아래 캡쳐는 2018년 지방선거 기준이긴 하지만 최신의 데이터라고 보면, 절대적인 수로도 60세 이상은 26.1%인 반면 20대는 15.9%다. 게다가 절반(남자)X복무기간 2년으로 어림잡아보면 1/10(1/2*2/10)은 여러 가지 제약이 있다. 즉, 활동 가능한 20대 인구는 15.9*9/10=14.3%란 말이고, 40~50대는 합치면 무려 40%다.

마지막 차트까지 그려보고선 정치 참여의 한 가지 지표인 투표율이 떠올랐다. 최근 들어 갑작스레 생긴 현상이 아니라 으레 낮았던 투표율이 집회 참여율과 궤를 같이 하는 건 아닐까. 원인에 대한 분석은 여러 전문가들의, 여러 의견이 있을 수 있지만 현상 자체를 놓고도 정말로 현 실태가 그러한지 한 번쯤 생각해볼 일이다. 절대적인 숫자가 중요한 건지 아니면 비중이 중요한 건지에 대해서도 고민해보고. 데이터는 거짓말을 하지 않지만 그림을 그리는 사람은 거짓말을 할 수 있다.(고의가 아닐지라도)


출처 : 중앙선거관리위원회



오늘 확인해본 건 여기까지다.

데이터 분석에서 가장 중요한 건 '어떤 데이터를 이용하여', '무엇을, 어떻게 볼 것인가'하는 착수 부분이라고 생각한다. 가설을 세우고 데이터를 입수해서 정리하고 검증하는 일련의 작업들이다.

시각화와 분석은 그보다 한참 다음이다.

그 중요한 부분이 이미 정의돼 있던 터라 꽤 수월했는데, 앞으로도 좋은 후속기사를 기대해본다.

SBS 보도, 분석기사, 그리고 본 글이 자신만의 관점으로 자료를 해석하는 데 요긴한 재료가 됐으면 한다.


-.NULL





최종 ggplot 코드 스니펫


매거진의 이전글 [생활 속 데이터분석] 주차장에 자리 있나요?(2/3)
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari