2024-1학기 빅데이터분석개론 기말고사
201635917 김다인
전국 작은 도서관 현황-지역별 독서량에 유의미한 영향을 끼치는가?
1. 서론
빅데이터분석이라는 말이 거창해 보일 수 있다. 나도 빅데이터분석개론 수업을 듣기 전까지는 그랬다. 코딩을 잘 다루고, 분석 모델을 많이 외우고, 수학적 지식이 있어야 한다고 생각했다. 이제는 너무나 당연하게 우리 일상에 빅데이터 분석이 들어가 있다. 우리가 경험적으로, 직관적으로 생각하고 판단하는 것들이 이제는 논리적이고 빅데이터를 활용하여 근거가 있는 결과물들이 흔하게 있다. 스포츠, 사업, 학교, 직장, 금융, 의료 등 모든 분야에서 사용되고 있다. 모든 분야에서 다루어지고 있는 만큼 일반인이 더 접근하기 쉬워지고 있는 상황이다. 배운 지식으로 과연 내 상황과 환경에 맞추어서 어떻게 활용할 수 있겠는가 생각해 보았다.
현재 경기도 구리시에서 어머니가 사립 작은 도서관을 20년 넘게 운영 중이다. 내가 어렸을 적에는 책이 흔했으며, 시립도서관에는 사람이 북적였고, 사립 작은 도서관의 활성화가 되던 시기였다. 현재는 체감상 느끼기에 독서량은 절대적으로 줄어들었으며 도서업계 자체가 작아지고 일부 웹소설계로 쏠리고 있다. 그러나 여전히 전국에는 많은 도서관과 작은 도서관이 존재하고 있다. 이제는 도서관들이 단순 도서 대여의 역할만 하는 공간이 아니다. 하나의 복합문화시설로 작용하고 있으며 많은 돌봄 교실의 현장이 되고 있고 어른들의 모임장소로도 이용되고 있다. 전국에 있는 많은 도서관과 작은 도서관들의 역할이 독서량과의 정비례 역할을 하고 있는지 조사해보고자 한다.
2. 본론
1) 오픈 데이터 설명
활용한 오픈 데이터는 공공데이터포탈에 있는 '문화체육관광부_국가도서관통계_전국작은도서관통계'이다. 2022년 기준으로 전국도서관 통계가 이루어져 있으며, 데이터의 개수는 6900건이다. 국민들에게 전국 작은 도서관 정보에 대한 통계정보를 구체적으로 제공하여 통계 데이터 활성화와 도서관 이용 장려를 유도하는 데이터이다. 데이터의 컬럼은 평가 연도, 도서관 구분, 도서관명, 행정구역, 시군구, 장서수, 사서수, 방문자수, 도서예산 순으로 이루어져 있다.

2) 데이터 보기
import os
import pandas as pd
file_path = r'C:\KDI\문화체육관광부_국가도서관통계_전국작은도서관통계_20221231 (1).csv'
#데이터 불러오기
if os.path.isfile(file_path):
df1 = pd.read_csv(file_path, encoding='CP949')
else:
print("File not found. Please check the path.")
#사용할 샘플 데이터 만들기
df1.to_csv('C:\KDI\library_sample.csv')
file_path = r'C:\KDI\library_sample.csv'
if os.path.isfile(file_path):
lib_info = pd.read_csv(file_path, encoding='UTF-8')
else:
print("File not found. Please check the path.")
lib_info.head(30)
| 0 | 2022 | LIBTYPE000002003 | 경희궁자이3단지 작은도서관 | 서울 | 종로구 | 2671 | 0 | 3650 | 0 |
| 1 | 2022 | LIBTYPE000002003 | 꿈꾸는 평창동 작은도서관 | 서울 | 종로구 | 5390 | 0 | 4446 | 5478000 |
| 2 | 2022 | LIBTYPE000002003 | 나무와 열매 어린이 도서관 | 서울 | 종로구 | 6825 | 0 | 3130 | 1500000 |
| 3 | 2022 | LIBTYPE000002003 | 도담도담한옥도서관 | 서울 | 종로구 | 6390 | 0 | 9390 | 6301200 |
| 4 | 2022 | LIBTYPE000002003 | 두산아파트문고 | 서울 | 종로구 | 3200 | 0 | 371 | 0 |
| 5 | 2022 | LIBTYPE000002003 | 무악다솜방 | 서울 | 종로구 | 5625 | 0 | 4437 | 5336200 |
| 6 | 2022 | LIBTYPE000002003 | 삼청공원 숲속도서관 | 서울 | 종로구 | 9501 | 1 | 28170 | 4080000 |
| 7 | 2022 | LIBTYPE000002003 | 석천문화관 | 서울 | 종로구 | 16908 | 1 | 252 | 5000000 |
| 8 | 2022 | LIBTYPE000002003 | 숭인마루 작은도서관 | 서울 | 종로구 | 7353 | 0 | 6525 | 5007700 |
| 9 | 2022 | LIBTYPE000002003 | 어린이도서관 꿈과쉼 | 서울 | 종로구 | 11729 | 0 | 1252 | 1849930 |
| 10 | 2022 | LIBTYPE000002003 | 영실도서관 | 서울 | 종로구 | 2870 | 0 | 1305 | 0 |
| 11 | 2022 | LIBTYPE000002003 | 우리소리도서관 | 서울 | 종로구 | 5902 | 1 | 12768 | 10979420 |
| 12 | 2022 | LIBTYPE000002003 | 이화마을 작은도서관 | 서울 | 종로구 | 7879 | 0 | 15794 | 5608100 |
| 13 | 2022 | LIBTYPE000002003 | 작은도서관 뜰 | 서울 | 종로구 | 1500 | 0 | 783 | 0 |
| 14 | 2022 | LIBTYPE000002003 | 종로수어영상도서관 | 서울 | 종로구 | 2577 | 0 | 955 | 820000 |
| 15 | 2022 | LIBTYPE000002003 | 지혜만들기 작은도서관 | 서울 | 종로구 | 6403 | 0 | 4698 | 5646700 |
| 16 | 2022 | LIBTYPE000002003 | 창이 작은도서관 | 서울 | 종로구 | 5047 | 0 | 5220 | 4936300 |
| 17 | 2022 | LIBTYPE000002003 | 청운효자동 북카페 | 서울 | 종로구 | 8367 | 1 | 4176 | 5396000 |
| 18 | 2022 | LIBTYPE000002003 | 청파도서관 | 서울 | 종로구 | 12425 | 0 | 3443 | 3524782 |
| 19 | 2022 | LIBTYPE000002003 | 통인 어린이 작은도서관 | 서울 | 종로구 | 16662 | 2 | 4212 | 8995180 |
| 20 | 2022 | LIBTYPE000002003 | 혜윰뜰 작은도서관 | 서울 | 종로구 | 2800 | 0 | 2190 | 500000 |
| 21 | 2022 | LIBTYPE000002003 | 혜화마을 북카페 | 서울 | 종로구 | 6921 | 0 | 5220 | 5647700 |
| 22 | 2022 | LIBTYPE000002003 | 홍파랑 북카페 | 서울 | 종로구 | 7888 | 0 | 1305 | 4564800 |
| 23 | 2022 | LIBTYPE000002003 | 광희동 작은도서관 | 서울 | 중구 | 4051 | 0 | 4720 | 4500000 |
| 24 | 2022 | LIBTYPE000002003 | 다산동작은도서관 | 서울 | 중구 | 10658 | 0 | 7350 | 5250000 |
| 25 | 2022 | LIBTYPE000002003 | 덕수궁 롯데캐슬아파트 작은도서관 | 서울 | 중구 | 2800 | 0 | 3650 | 0 |
| 26 | 2022 | LIBTYPE000002003 | 동화동 새마을작은도서관 | 서울 | 중구 | 15589 | 0 | 6831 | 12000000 |
| 27 | 2022 | LIBTYPE000002003 | 북소리 | 서울 | 중구 | 1200 | 0 | 3650 | 0 |
| 28 | 2022 | LIBTYPE000002003 | 서울역센트럴자이아파트 작은도서관 | 서울 | 중구 | 1000 | 0 | 3650 | 0 |
| 29 | 2022 | LIBTYPE000002003 | 신당5동작은도서관 | 서울 | 중구 | 5031 | 0 | 6574 | 5250000 |

추가 비교 분석 자료로, 문화체육관광부에서 진행한
ㅇ 조사 대상 : (성인) 전국 19세 이상 남녀, (학생) 초등학교(46학년), 중학교, 고등학교 재학생 ㅇ 조사 기간
- 2019.10.011. 0시 기준
- 조사 대상 기간 : 2018. 10. 1. 2019. 9. 30. (1년간)
- 조사 실시 기간 : 2019. 12. 16. 2020. 1. 23.
ㅇ 조사 지역 : 전국 17개 시도(제주도 및 세종시 포함) ㅇ 표본 규모 : (성인) 총 6,000명, (학생) 3,126명 ㅇ 표본 오차 : (성인) 95% 신뢰 수준에서 1.7%p, (학생) 95% 신뢰 수준에서 1.8%p ㅇ 자료수집방법
- 성인 : 조사원에 의한 1:1 개별면접조사(타계식 조사)
- 학생 : 조사원(또는 교사) 통제에 의한 자기기입식
의 통계 자료로 활용할 것이다.조사(자계식 조사)
3) 데이터 클린징
현재 작은 도서관 데이터에서 지역별 독서량, 방문수에 유의미한 영향을 끼칠 수 있는 것은 장서수, 방문자수, 도서예산이다. 좋은 도서관의 자격요건에는 여러 가지 있겠지만, 도서관의 제 역할을 가장 많이 하고 있다고 느낄 수 있는 부분은 당연 '방문자수'이다. 도서관에 있는 책을 읽는 독자들이 많을수록 도서관은 제 기능을 하고 있는 것이다. 도서관의 방문자수를 늘릴 수 있는 것은 그 도서관에 얼마나 많은 책들이 비치되어 있는가(장서수), 앞으로 신간 책을 얼마나 더 재빠르게 구비할 수 있는가(도서예산)로 확인할 수 있다. 또한, 작은 도서관은 책을 좋아하는 개인이 운영하는 경우가 많기 때문에 정식 사서가 없는 경우가 많다. 그렇기 때문에 데이터에도 사서가 0명이라고 되어 있는 곳이 흔하게 있다. 사서 수의 데이터는 그렇게 유의미하지 않다고 판단한다.
먼저, 결측 데이터가 있는지 확인한다.
lib_info.isnull()
| False | False | False | False | False | False | False | False | False | False |
| False | False | False | False | False | False | False | False | False | False |
| False | False | False | False | False | False | False | False | False | False |
| False | False | False | False | False | False | False | False | False | False |
| False | False | False | False | False | False | False | False | False | False |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| False | False | False | False | False | False | False | False | False | False |
| False | False | False | False | False | False | False | False | False | False |
| False | False | False | False | False | False | False | False | False | False |
| False | False | False | False | False | False | False | False | False | False |
| False | False | False | False | False | False | False | False | False | False |
6899 rows × 10 columns
lib_info.isnull().sum()
Unnamed: 0 0
평가년도 0
도서관구분 0
도서관명 0
행정구역 0
시군구 0
장서수 0
사서수 0
방문자수 0
도서예산 0
dtype: int64
결측 데이터는 없다. 다음으로는, 이상데이터를 제거해야 한다. 방문자 수가 가장 중요한 데이터이므로, 최댓값 아웃라이어가 있는 것은 오히려 가설에 증거가 될 수 있는 좋은 단서이다. 그러나, 최솟값 아웃라이어에 있는 값들은 도서관의 유무가 독서량을 늘린다는 가설에 도움이 되지 않는다. 따라서 최솟값 아웃라이어를 먼저 구하고 이상 데이터로 판단한 후 제거한다.
# 방문자 수가 있는 데이터만 선택
if '방문자수' in lib_info.columns:
visitors = lib_info['방문자수']
else:
print(f"Column '{'방문자수'}' not found in the dataframe.")
visitors = None
# IQR 계산
Q1 = visitors.quantile(0.25)
Q3 = visitors.quantile(0.75)
IQR = Q3 - Q1
# 최솟값 아웃라이어 기준
lower_bound = Q1 - 1.5 * IQR
print(Q1)
print(Q3)
print(IQR)
print(lower_bound)
939.0
4800.0
3861.0
-4852.5
lower_bound가 음수가 나왔기 때문에 사용할 수가 없다. 따라서 임의로 수를 정해서 제외한다. 평균적으로 하루에 한 명이 오지 않는다면, 도서관이 제 역할을 다 하지 못한다고 생각한다. 따라서, 방문자수가 365명 아래인 행들은 제외한다.
# 방문자 수가 있는 데이터만 선택
if '방문자수' in lib_info.columns:
visitors = lib_info['방문자수']
else:
print(f"Column '{'방문자수'}' not found in the dataframe.")
visitors = None
# 방문자 수가 365명 이상인 데이터만 선택
filtered_lib_info = lib_info[lib_info['방문자수'] >= 365]
filtered_lib_info
| 0 | 2022 | LIBTYPE000002003 | 경희궁자이3단지 작은도서관 | 서울 | 종로구 | 2671 | 0 | 3650 | 0 |
| 1 | 2022 | LIBTYPE000002003 | 꿈꾸는 평창동 작은도서관 | 서울 | 종로구 | 5390 | 0 | 4446 | 5478000 |
| 2 | 2022 | LIBTYPE000002003 | 나무와 열매 어린이 도서관 | 서울 | 종로구 | 6825 | 0 | 3130 | 1500000 |
| 3 | 2022 | LIBTYPE000002003 | 도담도담한옥도서관 | 서울 | 종로구 | 6390 | 0 | 9390 | 6301200 |
| 4 | 2022 | LIBTYPE000002003 | 두산아파트문고 | 서울 | 종로구 | 3200 | 0 | 371 | 0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 6894 | 2022 | LIBTYPE000002003 | 호근새마을작은도서관 | 제주 | 서귀포시 | 4974 | 0 | 1095 | 1500000 |
| 6895 | 2022 | LIBTYPE000002003 | 희망새마을작은도서관 | 제주 | 서귀포시 | 3002 | 0 | 2088 | 1000000 |
| 6896 | 2022 | LIBTYPE000002003 | (신례1리)예촌작은도서관 | 제주 | 서귀포시 | 7002 | 0 | 1305 | 2000000 |
| 6897 | 2022 | LIBTYPE000002003 | 93대대독서대학 | 제주 | 서귀포시 | 1336 | 0 | 730 | 0 |
| 6898 | 2022 | LIBTYPE000002003 | LH강정작은도서관 | 제주 | 서귀포시 | 2281 | 0 | 1305 | 4000000 |
6106 rows × 10 columns
행이 약, 800행 정도 삭제되었다. 인덱스 번호는 그대로이므로, 다시 인덱스 번호를 순서대로 매겨준다.
filtered_lib_info.reset_index(drop=True, inplace=True)
filtered_lib_info
| 0 | 2022 | LIBTYPE000002003 | 경희궁자이3단지 작은도서관 | 서울 | 종로구 | 2671 | 0 | 3650 | 0 |
| 1 | 2022 | LIBTYPE000002003 | 꿈꾸는 평창동 작은도서관 | 서울 | 종로구 | 5390 | 0 | 4446 | 5478000 |
| 2 | 2022 | LIBTYPE000002003 | 나무와 열매 어린이 도서관 | 서울 | 종로구 | 6825 | 0 | 3130 | 1500000 |
| 3 | 2022 | LIBTYPE000002003 | 도담도담한옥도서관 | 서울 | 종로구 | 6390 | 0 | 9390 | 6301200 |
| 4 | 2022 | LIBTYPE000002003 | 두산아파트문고 | 서울 | 종로구 | 3200 | 0 | 371 | 0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 6894 | 2022 | LIBTYPE000002003 | 호근새마을작은도서관 | 제주 | 서귀포시 | 4974 | 0 | 1095 | 1500000 |
| 6895 | 2022 | LIBTYPE000002003 | 희망새마을작은도서관 | 제주 | 서귀포시 | 3002 | 0 | 2088 | 1000000 |
| 6896 | 2022 | LIBTYPE000002003 | (신례1리)예촌작은도서관 | 제주 | 서귀포시 | 7002 | 0 | 1305 | 2000000 |
| 6897 | 2022 | LIBTYPE000002003 | 93대대독서대학 | 제주 | 서귀포시 | 1336 | 0 | 730 | 0 |
| 6898 | 2022 | LIBTYPE000002003 | LH강정작은도서관 | 제주 | 서귀포시 | 2281 | 0 | 1305 | 4000000 |
6106 rows × 10 columns
그다음으로는 중요하지 않은 컬럼을 삭제해야 한다. 먼저 사서 수 컬럼을 삭제해야 한다.
filtered_lib_info.pop('사서수')
0 0
1 0
2 0
3 0
4 0
..
6101 0
6102 0
6103 0
6104 0
6105 0
Name: 사서수, Length: 6106, dtype: int64
이전에 미리 삭제해서 에러가 뜨지만, 사서수 컬럼이 잘 삭제된 것을 볼 수 있다.
filtered_lib_info
| 0 | 2022 | LIBTYPE000002003 | 경희궁자이3단지 작은도서관 | 서울 | 종로구 | 2671 | 3650 | 0 |
| 1 | 2022 | LIBTYPE000002003 | 꿈꾸는 평창동 작은도서관 | 서울 | 종로구 | 5390 | 4446 | 5478000 |
| 2 | 2022 | LIBTYPE000002003 | 나무와 열매 어린이 도서관 | 서울 | 종로구 | 6825 | 3130 | 1500000 |
| 3 | 2022 | LIBTYPE000002003 | 도담도담한옥도서관 | 서울 | 종로구 | 6390 | 9390 | 6301200 |
| 4 | 2022 | LIBTYPE000002003 | 두산아파트문고 | 서울 | 종로구 | 3200 | 371 | 0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 6894 | 2022 | LIBTYPE000002003 | 호근새마을작은도서관 | 제주 | 서귀포시 | 4974 | 1095 | 1500000 |
| 6895 | 2022 | LIBTYPE000002003 | 희망새마을작은도서관 | 제주 | 서귀포시 | 3002 | 2088 | 1000000 |
| 6896 | 2022 | LIBTYPE000002003 | (신례1리)예촌작은도서관 | 제주 | 서귀포시 | 7002 | 1305 | 2000000 |
| 6897 | 2022 | LIBTYPE000002003 | 93대대독서대학 | 제주 | 서귀포시 | 1336 | 730 | 0 |
| 6898 | 2022 | LIBTYPE000002003 | LH강정작은도서관 | 제주 | 서귀포시 | 2281 | 1305 | 4000000 |
6106 rows × 9 columns
4) 데이터 탐색
그룹화를 어떻게 할 것인가는 딱히 고민할 필요 없다. 작은 도서관의 유무에 따라 지역별 독서량 증가 유무를 알고 싶으니, 행정구역별-시군구별로 그룹화를 하여 방문자 수를 살피면 된다. 먼저, <2019년 국민 독서실태 조사>에서 조사한 내용이다.

<2019년 국민 독서실태 조사>의 지역별 주요 독서지표 분석한 결과, 성인의 경우 중소도시 및 읍면 지역 거주자들의 독서 지표가 대도시(서울 및 광역시) 거주자들보다 독서 지표가 낮은 것으로 보인다. 중소도시 및 읍면 지역에 거주하는 성인의 독서율(종이책+전자책+오디오북 종합독서율 기준)은 대도시 거주자보다 각각9.3%p, 27.6%p 낮다. 반면, 초중고 학생의 경우에는 지역 간 독서지표가 큰 차이가 없는 것으로 나타난다. 연간 독서량은 대도시 거주 학생들에 비해 중소도시 및 읍면 거주 학생들이 약 5권 정도 더 많으며, 공공도서관 이용률 역시 중소도시 및 읍면에 거주하는 학생들이 대도시에 거주하는 학생보다 7%p 정도 높은 것으로 나타난다.
전국 17개 시도의 지역별 5대 독서 지표 분석 결과, 항목별 평균치 이상 항목이 5개인 곳은 서울, 인천, 제주였고, 경기와 강원이 4개 항목, 대구가 3개 항목, 부산, 울산, 세종이 2개 항목에서 전국 평균 이상의 실적을 나타내 상대적으로 독서 실태가 양호하다고 볼 수 있다. 반면 대전, 충북, 충남, 전북, 전남, 경북, 경남은 5대 독서 지표 모두가 평균치 이하로 보인다. 전국으로 비교했을 때, 상대적으로 독서 실태가 좋지 않은 지역으로 볼 수 있다.
작은 도서관 현황 데이터에서 행정구역별 묶어서 방문자수, 장서수, 도서예산을 확인한다. 먼저, 어느 행정구역과 시군구가 있는지 확인해 본다.
# '행정구역' 및 '시군구' 컬럼의 고유값 추출
admin_regions = filtered_lib_info['행정구역'].unique()
cities = filtered_lib_info['시군구'].unique()
print("행정구역의 고유값:")
print(admin_regions)
print("\n시군구의 고유값:")
print(cities)
행정구역의 고유값:
['서울' '부산' '대구' '인천' '광주' '대전' '울산' '세종특별자치시' '경기' '강원' '충북' '충남' '전북'
'전남' '경북' '경남' '제주']
시군구의 고유값:
['종로구' '중구' '용산구' '성동구' '광진구' '동대문구' '중랑구' '성북구' '강북구' '도봉구' '노원구' '은평구'
'서대문구' '마포구' '양천구' '강서구' '구로구' '금천구' '영등포구' '동작구' '관악구' '서초구' '강남구' '송파구'
'강동구' '서구' '동구' '영도구' '부산진구' '동래구' '남구' '북구' '해운대구' '사하구' '금정구' '연제구'
'수영구' '사상구' '기장군' '수성구' '달서구' '달성군' '미추홀구' '연수구' '남동구' '부평구' '계양구' '강화군'
'광산구' '유성구' '대덕구' '울주군' '다정중앙로' '다정북로' '다정남로' '도움1로' '도움3로' '만남로' '마음안1로'
'남세종로' '국세청로' '나성북로' '달빛1로' '보람로' '반곡로' '시청대로' '달빛로' '보듬3로' '부강면' '집현서2로'
'새롬남로' '새롬중앙로' '조치원읍' '다솜로' '소정면' '연동면' '장군면' '연기면' '전의면' '나리1로' '누리로'
'나리로' '노을3로' '도원1로' '마음안로' '대평로' '수원시' '성남시' '의정부시' '안양시' '부천시' '광명시'
'평택시' '동두천시' '고양시' '과천시' '구리시' '남양주시' '오산시' '시흥시' '안산시' '군포시' '의왕시' '하남시'
'용인시' '파주시' '이천시' '안성시' '김포시' '화성시' '광주시' '양주시' '포천시' '여주시' '연천군' '가평군'
'양평군' '춘천시' '원주시' '강릉시' '동해시' '태백시' '속초시' '삼척시' '홍천군' '횡성군' '영월군' '평창군'
'정선군' '철원군' '화천군' '양구군' '인제군' '고성군' '양양군' '청주시' '충주시' '제천시' '보은군' '옥천군'
'영동군' '증평군' '진천군' '괴산군' '음성군' '천안시' '공주시' '보령시' '아산시' '서산시' '논산시' '계룡시'
'당진시' '금산군' '부여군' '서천군' '청양군' '홍성군' '예산군' '태안군' '전주시' '군산시' '익산시' '정읍시'
'남원시' '김제시' '완주군' '진안군' '무주군' '장수군' '임실군' '순창군' '고창군' '부안군' '목포시' '여수시'
'순천시' '나주시' '광양시' '담양군' '곡성군' '구례군' '고흥군' '보성군' '화순군' '장흥군' '강진군' '해남군'
'영암군' '무안군' '함평군' '영광군' '장성군' '완도군' '진도군' '신안군' '포항시' '경주시' '김천시' '안동시'
'구미시' '영주시' '영천시' '상주시' '문경시' '경산시' '의성군' '청송군' '영양군' '영덕군' '청도군' '고령군'
'성주군' '칠곡군' '예천군' '봉화군' '울진군' '울릉군' '창원시' '진주시' '통영시' '사천시' '김해시' '밀양시'
'거제시' '양산시' '의령군' '함안군' '창녕군' '남해군' '하동군' '산청군' '함양군' '거창군' '합천군' '제주시'
'서귀포시']
# 행정구역별로 데이터를 그룹화하고 합산 및 카운팅
grouped_by_region = lib_info.groupby('행정구역').agg({
'장서수': 'sum',
'방문자수': 'sum',
'도서예산': 'sum',
'도서관명': 'count'
}).reset_index()
# 도서관명 컬럼의 이름을 '도서관 수'로 변경
grouped_by_region.rename(columns={'도서관명': '도서관 수'}, inplace=True)
# 결과 출력
grouped_by_region
| 강원 | 1175465 | 747614 | 554448010 | 224 |
| 경기 | 11534961 | 7476915 | 4784425986 | 1676 |
| 경남 | 3432930 | 2193482 | 1189481310 | 489 |
| 경북 | 1787252 | 1029986 | 657905670 | 293 |
| 광주 | 1601091 | 856766 | 586752990 | 346 |
| 대구 | 1574325 | 794620 | 673183961 | 219 |
| 대전 | 1459281 | 665219 | 577268177 | 244 |
| 부산 | 2348753 | 1985125 | 971633520 | 430 |
| 서울 | 7007964 | 5379867 | 2722215366 | 943 |
| 세종특별자치시 | 394395 | 227268 | 87407550 | 59 |
| 울산 | 1172909 | 802806 | 500926171 | 188 |
| 인천 | 1822653 | 1186865 | 664467380 | 300 |
| 전남 | 1603575 | 921384 | 583900035 | 337 |
| 전북 | 2360542 | 1405530 | 1114863500 | 352 |
| 제주 | 714530 | 329891 | 332226496 | 150 |
| 충남 | 1941777 | 1054556 | 722603535 | 389 |
| 충북 | 1346886 | 914052 | 505361170 | 260 |
grouped_by_region
| 강원 | 1175465 | 747614 | 554448010 | 224 |
| 경기 | 11534961 | 7476915 | 4784425986 | 1676 |
| 경남 | 3432930 | 2193482 | 1189481310 | 489 |
| 경북 | 1787252 | 1029986 | 657905670 | 293 |
| 광주 | 1601091 | 856766 | 586752990 | 346 |
| 대구 | 1574325 | 794620 | 673183961 | 219 |
| 대전 | 1459281 | 665219 | 577268177 | 244 |
| 부산 | 2348753 | 1985125 | 971633520 | 430 |
| 서울 | 7007964 | 5379867 | 2722215366 | 943 |
| 세종특별자치시 | 394395 | 227268 | 87407550 | 59 |
| 울산 | 1172909 | 802806 | 500926171 | 188 |
| 인천 | 1822653 | 1186865 | 664467380 | 300 |
| 전남 | 1603575 | 921384 | 583900035 | 337 |
| 전북 | 2360542 | 1405530 | 1114863500 | 352 |
| 제주 | 714530 | 329891 | 332226496 | 150 |
| 충남 | 1941777 | 1054556 | 722603535 | 389 |
| 충북 | 1346886 | 914052 | 505361170 | 260 |
# 한글에서 영문으로 행정구역명 매핑 딕셔너리
korean_to_english = {
'서울': 'Seoul',
'부산': 'Busan',
'대구': 'Daegu',
'인천': 'Incheon',
'광주': 'Gwangju',
'대전': 'Daejeon',
'울산': 'Ulsan',
'세종특별자치시': 'Sejong',
'경기': 'Gyeonggi',
'강원': 'Gangwon',
'충북': 'Chungcheongbuk',
'충남': 'Chungcheongnam',
'전북': 'Jeollabuk',
'전남': 'Jeollanam',
'경북': 'Gyeongsangbuk',
'경남': 'Gyeongsangnam',
'제주': 'Jeju'
}
# '행정구역' 컬럼의 값을 영문으로 변환하는 함수
def translate_to_english(row):
return korean_to_english.get(row['administrative'], row['administrative'])
# '행정구역' 컬럼의 값을 영문으로 변환
grouped_by_region['administrative'] = grouped_by_region.apply(translate_to_english, axis=1)
# 결과 출력
grouped_by_region
| Gangwon | 1175465 | 747614 | 554448010 | 224 |
| Gyeonggi | 11534961 | 7476915 | 4784425986 | 1676 |
| Gyeongsangnam | 3432930 | 2193482 | 1189481310 | 489 |
| Gyeongsangbuk | 1787252 | 1029986 | 657905670 | 293 |
| Gwangju | 1601091 | 856766 | 586752990 | 346 |
| Daegu | 1574325 | 794620 | 673183961 | 219 |
| Daejeon | 1459281 | 665219 | 577268177 | 244 |
| Busan | 2348753 | 1985125 | 971633520 | 430 |
| Seoul | 7007964 | 5379867 | 2722215366 | 943 |
| Sejong | 394395 | 227268 | 87407550 | 59 |
| Ulsan | 1172909 | 802806 | 500926171 | 188 |
| Incheon | 1822653 | 1186865 | 664467380 | 300 |
| Jeollanam | 1603575 | 921384 | 583900035 | 337 |
| Jeollabuk | 2360542 | 1405530 | 1114863500 | 352 |
| Jeju | 714530 | 329891 | 332226496 | 150 |
| Chungcheongnam | 1941777 | 1054556 | 722603535 | 389 |
| Chungcheongbuk | 1346886 | 914052 | 505361170 | 260 |
5) 데이터 분석
행정구역별 장서수, 방문자수, 도서예산, 도서관수 데이터프레임이 완성이 되었다. 각 컬럼별 기준으로 했을 때, 어느 행정구역이 높은 순위를 차지하는지 확인해 볼 수 있다.
#장서수 기준 내림차순
df_sorted_book = grouped_by_region.sort_values(by=['book_count'], ascending=False)
df_sorted_book
| Gyeonggi | 11534961 | 7476915 | 4784425986 | 1676 |
| Seoul | 7007964 | 5379867 | 2722215366 | 943 |
| Gyeongsangnam | 3432930 | 2193482 | 1189481310 | 489 |
| Jeollabuk | 2360542 | 1405530 | 1114863500 | 352 |
| Busan | 2348753 | 1985125 | 971633520 | 430 |
| Chungcheongnam | 1941777 | 1054556 | 722603535 | 389 |
| Incheon | 1822653 | 1186865 | 664467380 | 300 |
| Gyeongsangbuk | 1787252 | 1029986 | 657905670 | 293 |
| Jeollanam | 1603575 | 921384 | 583900035 | 337 |
| Gwangju | 1601091 | 856766 | 586752990 | 346 |
| Daegu | 1574325 | 794620 | 673183961 | 219 |
| Daejeon | 1459281 | 665219 | 577268177 | 244 |
| Chungcheongbuk | 1346886 | 914052 | 505361170 | 260 |
| Gangwon | 1175465 | 747614 | 554448010 | 224 |
| Ulsan | 1172909 | 802806 | 500926171 | 188 |
| Jeju | 714530 | 329891 | 332226496 | 150 |
| Sejong | 394395 | 227268 | 87407550 | 59 |
#방문자수 별 내림차순
df_sorted_visited = grouped_by_region.sort_values(by=[ 'visited'], ascending=False)
df_sorted_visited
| Gyeonggi | 11534961 | 7476915 | 4784425986 | 1676 |
| Seoul | 7007964 | 5379867 | 2722215366 | 943 |
| Gyeongsangnam | 3432930 | 2193482 | 1189481310 | 489 |
| Busan | 2348753 | 1985125 | 971633520 | 430 |
| Jeollabuk | 2360542 | 1405530 | 1114863500 | 352 |
| Incheon | 1822653 | 1186865 | 664467380 | 300 |
| Chungcheongnam | 1941777 | 1054556 | 722603535 | 389 |
| Gyeongsangbuk | 1787252 | 1029986 | 657905670 | 293 |
| Jeollanam | 1603575 | 921384 | 583900035 | 337 |
| Chungcheongbuk | 1346886 | 914052 | 505361170 | 260 |
| Gwangju | 1601091 | 856766 | 586752990 | 346 |
| Ulsan | 1172909 | 802806 | 500926171 | 188 |
| Daegu | 1574325 | 794620 | 673183961 | 219 |
| Gangwon | 1175465 | 747614 | 554448010 | 224 |
| Daejeon | 1459281 | 665219 | 577268177 | 244 |
| Jeju | 714530 | 329891 | 332226496 | 150 |
| Sejong | 394395 | 227268 | 87407550 | 59 |
#도서예산 별 내림차순
df_sorted_budget = grouped_by_region.sort_values(by=['budget'], ascending=False)
df_sorted_budget
| Gyeonggi | 11534961 | 7476915 | 4784425986 | 1676 |
| Seoul | 7007964 | 5379867 | 2722215366 | 943 |
| Gyeongsangnam | 3432930 | 2193482 | 1189481310 | 489 |
| Jeollabuk | 2360542 | 1405530 | 1114863500 | 352 |
| Busan | 2348753 | 1985125 | 971633520 | 430 |
| Chungcheongnam | 1941777 | 1054556 | 722603535 | 389 |
| Daegu | 1574325 | 794620 | 673183961 | 219 |
| Incheon | 1822653 | 1186865 | 664467380 | 300 |
| Gyeongsangbuk | 1787252 | 1029986 | 657905670 | 293 |
| Gwangju | 1601091 | 856766 | 586752990 | 346 |
| Jeollanam | 1603575 | 921384 | 583900035 | 337 |
| Daejeon | 1459281 | 665219 | 577268177 | 244 |
| Gangwon | 1175465 | 747614 | 554448010 | 224 |
| Chungcheongbuk | 1346886 | 914052 | 505361170 | 260 |
| Ulsan | 1172909 | 802806 | 500926171 | 188 |
| Jeju | 714530 | 329891 | 332226496 | 150 |
| Sejong | 394395 | 227268 | 87407550 | 59 |
#도서관 수별 내림차순
df_sorted_lib = grouped_by_region.sort_values(by=['lib_count'], ascending=False)
df_sorted_lib
| Gyeonggi | 11534961 | 7476915 | 4784425986 | 1676 |
| Seoul | 7007964 | 5379867 | 2722215366 | 943 |
| Gyeongsangnam | 3432930 | 2193482 | 1189481310 | 489 |
| Busan | 2348753 | 1985125 | 971633520 | 430 |
| Chungcheongnam | 1941777 | 1054556 | 722603535 | 389 |
| Jeollabuk | 2360542 | 1405530 | 1114863500 | 352 |
| Gwangju | 1601091 | 856766 | 586752990 | 346 |
| Jeollanam | 1603575 | 921384 | 583900035 | 337 |
| Incheon | 1822653 | 1186865 | 664467380 | 300 |
| Gyeongsangbuk | 1787252 | 1029986 | 657905670 | 293 |
| Chungcheongbuk | 1346886 | 914052 | 505361170 | 260 |
| Daejeon | 1459281 | 665219 | 577268177 | 244 |
| Gangwon | 1175465 | 747614 | 554448010 | 224 |
| Daegu | 1574325 | 794620 | 673183961 | 219 |
| Ulsan | 1172909 | 802806 | 500926171 | 188 |
| Jeju | 714530 | 329891 | 332226496 | 150 |
| Sejong | 394395 | 227268 | 87407550 | 59 |
# 장서수 기준 내림차순 정렬된 행정구역
df_sorted_book = grouped_by_region.sort_values(by='book_count', ascending=False)['administrative']
# 방문자수 기준 내림차순 정렬된 행정구역
df_sorted_visited = grouped_by_region.sort_values(by='visited', ascending=False)['administrative']
# 도서예산 기준 내림차순 정렬된 행정구역
df_sorted_budget = grouped_by_region.sort_values(by='budget', ascending=False)['administrative']
# 도서관 수 기준 내림차순 정렬된 행정구역
df_sorted_lib = grouped_by_region.sort_values(by='lib_count', ascending=False)['administrative']
# 새로운 데이터프레임 생성
df_result = pd.DataFrame({
'book_count': df_sorted_book.values,
'visited': df_sorted_visited.values,
'budget': df_sorted_budget.values,
'lib_count': df_sorted_lib.values
})
df_result
| Gyeonggi | Gyeonggi | Gyeonggi | Gyeonggi |
| Seoul | Seoul | Seoul | Seoul |
| Gyeongsangnam | Gyeongsangnam | Gyeongsangnam | Gyeongsangnam |
| Jeollabuk | Busan | Jeollabuk | Busan |
| Busan | Jeollabuk | Busan | Chungcheongnam |
| Chungcheongnam | Incheon | Chungcheongnam | Jeollabuk |
| Incheon | Chungcheongnam | Daegu | Gwangju |
| Gyeongsangbuk | Gyeongsangbuk | Incheon | Jeollanam |
| Jeollanam | Jeollanam | Gyeongsangbuk | Incheon |
| Gwangju | Chungcheongbuk | Gwangju | Gyeongsangbuk |
| Daegu | Gwangju | Jeollanam | Chungcheongbuk |
| Daejeon | Ulsan | Daejeon | Daejeon |
| Chungcheongbuk | Daegu | Gangwon | Gangwon |
| Gangwon | Gangwon | Chungcheongbuk | Daegu |
| Ulsan | Daejeon | Ulsan | Ulsan |
| Jeju | Jeju | Jeju | Jeju |
| Sejong | Sejong | Sejong | Sejong |
장서수, 방문자수, 도서예산, 도서관 수 기준으로 다시 데이터프레임을 짠 후, 이를 출력했다.
- 1-3위까지는 경기, 서울, 경남 순으로 일정한 것으로 보인다. 이는, 모두 숫자의 크기 나열 순이므로 인구 수와 비례하는 경향이 있다. 실제로, 2019년 인구를 보면 경기도는 1324만명, 서울은 973만명, 경남은 부산보다 5만 적은 336만으로 인구 수를 따라가는 경향이 보인다. 부산이 경남보다 5만 앞서지만 3위를 하지 못한 이유는, 부산은 노인이 많고, 잦은 어업 활동으로 인하여 육지에서 활발한 활동 가능 인구 자체가 좀 적기 때문으로 예상한다.
- 제주와 세종 역시 가장 밑 순위에 나란히 있다. 이 역시도 제주 67만, 세종 34만으로 가장 적은 인구의 도시이기 때문이다.
- 대전은 장서수, 도서예산, 도서관 수 모두 12위이지만, 방문자 수가 15위로 가장 간격이 벌어져 있다. 이는 <2019년 국민 도서실태 조사>에서 지역별 독서 지표에서, 연간 독서율이 39.3%로 다른 곳보다 현저히 떨어지는 것을 볼 수 있다.
- 반대로, 울산은 장서수, 예산, 도서관 수 모두 15위지만 방문자 수는 12위를 기록하고 있다. 정확히 대전과 울산의 순위가 디커플링되고 있다. 이 역시 <2019년 국민 도서실태 조사>에서 지역별 독서 지표를 보면, 연간 독서율이 58.3%로 꽤 준수한 순위에 위치해있다.
- 가장 아래 순위인 제주와 세종은 <2019년 국민 도서실태 조사>에서 연간독서량을 보면 각각 63.5%, 53.4%로 준수한 순위에 위치해 있다. 이 곳은 작은도서관의 수에서는 영향을 별로 받지 않는다는 것을 알 수 있다.
print(df_result)
book_count visited budget lib_count
0 Gyeonggi Gyeonggi Gyeonggi Gyeonggi
1 Seoul Seoul Seoul Seoul
2 Gyeongsangnam Gyeongsangnam Gyeongsangnam Gyeongsangnam
3 Jeollabuk Busan Jeollabuk Busan
4 Busan Jeollabuk Busan Chungcheongnam
5 Chungcheongnam Incheon Chungcheongnam Jeollabuk
6 Incheon Chungcheongnam Daegu Gwangju
7 Gyeongsangbuk Gyeongsangbuk Incheon Jeollanam
8 Jeollanam Jeollanam Gyeongsangbuk Incheon
9 Gwangju Chungcheongbuk Gwangju Gyeongsangbuk
10 Daegu Gwangju Jeollanam Chungcheongbuk
11 Daejeon Ulsan Daejeon Daejeon
12 Chungcheongbuk Daegu Gangwon Gangwon
13 Gangwon Gangwon Chungcheongbuk Daegu
14 Ulsan Daejeon Ulsan Ulsan
15 Jeju Jeju Jeju Jeju
16 Sejong Sejong Sejong Sejong
각 기준별, 도시 순위를 새로 만든 데이터프레임을 시각화 그래프 그리기 편하게, 영어로 바꿔주었다.
6) 데이터 시각화
이제, 각 컬럼(장서 수, 방문자수, 도서예산, 도서관 수) 기준으로 시각화 그래프를 그려보았다.
import pandas as pd
import matplotlib.pyplot as plt
# 순위 컬럼 추가
df_result['rank'] = range(1, len(df_result) + 1)
# 시각화
plt.figure(figsize=(20, 20))
for col in df_result.columns[:-1]: # rank 컬럼 제외
plt.plot(df_result[col], df_result['rank'], marker='o', label=col)
plt.title('Rankings of Locations')
plt.xlabel('Locations')
plt.ylabel('Rank')
plt.yticks(range(1, len(df_result) + 1))
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

위의 df_result를 보기 좋게 랭크함수를 이용하여 시각화해 보았다.
7) 데이터 또는 분석 과정 차별화 포인트
데이터 분석을 어떤 방식으로 할 것인가 먼저 고민하였다. 작은 도서관에 대한 컬럼들(장서수, 예산, 도서관수, 방문자수 등)이 있으니 어떤 식으로 활용하는 것이 재미있겠는가 먼저 생각했다. 전국에 작은 도서관들이 많다는 것은 알고 있었으나, 이 정도로 많으리라고는 생각 못했다. 하나의 작은 도서관을 보면 이 도서관이 얼마나 사람들에게 영향을 끼치겠나 생각도 들었으나 데이터를 모아보니 모든 컬럼들이 꽤 높은 숫자를 나타내고 있었다. 예산 역시 꽤 높은 숫자를 차지하고 있었다. 객관적으로 바라보면 높은 숫자지만, 주관적으로 바라봤을 때는 도서관의 숫자가 저렇게 많은데 예산이 낮아서 안타까운 부분도 있었다.
작은 도서관의 존재가 빛을 발하려면, 방문하는 시민들의 수가 많아야 한다. 그렇기 때문에 지역별 도서관의 수와 방문자수를 비교하는 것을 우선으로 두었다. 그러나 단순히 도서관의 수와 방문자수를 비교하는 것은 어쩌면 뻔한 결과를 나타낼 수 있다. 인구가 많은 도시, 도서관의 수가 많은 도시가 방문자가 많은 것은 당연한 결과이다. 물론 예외가 있을 수 있지만 말이다. 그래서, 분석 과정 차별화 포인트로써 문화체육관광부에서 만든 전국 독서지표 자료를 활용하였다. 이는 각 지역별로 비율을 나타내었기 때문에, 절대적 숫자인 도서관수, 방문자수와 개별적 비율인 독서율, 독서량, 방문율 등을 함께 활용하였다.
8) 데이터 분석 수업을 마감하며
서론에서도 썼지만, 빅데이터분석을 배우기 전에는 막연하게 어렵다고 생각을 하였다. 어마어마한 양을 다루기도 어려울 것이며, 문제가 있는 부분을 찾는 것도 한세월이 걸리고, 그 많은 데이터를 어느 방향으로 분석하여 활용할 것인지 감이 안 잡히기도 하였다. 어떻게 데이터를 다루고, 꼬고, 만져주고, 안아주고, 이뻐해 줄 수 있을까. 우리같이 멍청한 일반인들을 위해 세계의 많은 똑똑한 분들이 빅데이터를 분석하기 쉽게 많은 도구들을 만들어 두었다. 심지어 빅데이터를 정확한 근거와 체계적인 단계를 거쳐서 만들어도 두었다. 우리는 내가 무엇을 원하는지만 고민하면, 내가 보기 좋게 만들어낼 수 있다.
나는 엄마의 20년 넘는 취미생활이자 직업인 사립도서관의 운영이 다른 시민들에게 도움이 되는가 궁금했다. 또한, 전국에 사립 작은 도서관들이 많다는 것을 알고 있었으나 이 데이터들이 모아져 있는 게 있을까? 이 데이터들이 있다면 활용을 할 수 있을까? 호기심으로 분석해 보기 시작했다. 일상에서 찾는 호기심에서 시작해야 분석할 때 동기부여가 된다는 것도 느낄 수 있었다. 사실 작은 도서관들이 전국에 많은 숫자로 퍼져 있다지만 공공도서관에 비하면 방문수가 낮은 숫자이다. 그러나 작은 도서관의 역할은 단순한 독서가 아니라 독서모임, 다양한 시민 프로그램, 아동 돌봄, 꿈의 학교, 쉼터, 놀이터 등 시민사회적인 역할을 담당하고 있다. 모쪼록, 재밌는 연구 주제였으며 유익했다.
빅데이터분석개론 수업을 들으면서 빅데이터가 재미있을 수 있구나 생각이 들어 학기 중 ADSP와 SQLD 자격증 역시 준비해서 따보았다. 시험 준비 과정에서 수업에 배웠던 내용들이 정말 많이 나오길래 도움이 많이 되었다. ADSP는 합격을 했으며 SQLD는 결과를 기다리고 있으나 합격할 것 같다. 여러 가지를 얻어갔으니 충분히 가치 있었던 수업이라 생각한다. 감사합니다.