데이터 관계분석
이번 장에서 다루는 내용.
- 서울시 CCTV 수와 인구수의 관계를 분석하려고 한다.
- 그러기 위해서는 구별 CCTV수와 인구수를 알아야한다.
※ Jupyter Notebook을 사용하려고 한다.
※ numpy, pandas, matplotlib를 사용하여 데이터를 편집하고 그래프로 시각화하려고 한다.
1. 데이터 다운로드[1]
- 구글에서 위 사진과 같이 검색한다.
- 마우스 버튼이 있는 내용보기를 누른다.
- csv형식의 파일을 다운로드 받는다.
2. 읽어오기[1]
1) pandas와 numpy
import pandas as pd # pandas를 pd라고 부르겠다. import numpy as np # numpy를 np라고 부르겠다.
[1] pandas
- 데이터 분석 및 처리를 쉽게 할 수 있도록 만들어 놓은 파이썬 패키지이다.
[2] numpy
- Numerical Python의 약자이며 수치계산을 하기 위해 만들어진 파이썬 패키지이다.
2) csv파일 읽어오기
# 위에서 다운로드 받은 서울시 년도별 CCTV현황파일 읽어오기 CCTV_Seoul = pd.read_csv('./CCTV_in_Seoul_2018.csv', encoding='euc-kr') # .read_csv([파일경로], encoding = [인코딩타입])함수의 형식 CCTV_Seoul.head() # 상위 5개만 출력
3) 컬럼리스트 확인
# CCTV_Seoul은 읽어온 데이터를 저장하는 변수명 # CCTV_in_Seoul_2018.csv에 있는 컬럼명 -> 리스트로 출력 CCTV_Seoul.columns
- 위와 같이 리스트가 출력됨을 확인할 수 있다.
4) 1번째 컬럼 확인
# 첫번째 컬럼명 호출 CCTV_Seoul.columns[0]
'기관명' <- 좌측 텍스트가 첫번째 컬럼명임을 확인할 수 있다.
5) 컬럼명 변경
# CCTV_Seoul의 index 0번째 값의 이름을 바꾼다. # inplace = True는 변수를 직접 변경한다는 뜻이다. CCTV_Seoul.rename(columns={CCTV_Seoul.columns[0] : '구별'}, inplace = True) CCTV_Seoul.head()
- 첫번째 컬럼명이 '기관명'에서 '구별'로 변경됨을 확인할 수 있다.
3. 데이터 다운로드[2]
- 정제된 데이터를 가져오기 위해 http://data.seoul.go.kr/에 접속한다.
-
- 데이터 이용하기-> 데이터서비스 -> 서울통계 데이터 -> 서울통계 서비스 를 클릭한다.
- 인구 -> 주민등록인구(연령별/구별) 에 들어간다.
- csv형식으로 다운로드 한다.
4. 읽어오기[2]
1) 엑셀파일 읽어오기
# population_in_Seoul.xls 파일을 읽기 pop_Seoul = pd.read_excel('./population_in_Seoul.xls', encoding = 'euc-kr') pop_Seoul.head()
- 다운로드한 파일을 pop_Seoul변수에 읽어와 위 그림과 같이 상위 5개만 출력하였다.
2) 출력영역 정하기
# population_in_Seoul.xls의 데이터 중, # header = 2 옵션은 위에서 3번째줄부터 값들을 저장한다는 의미이다. # parse_cols='B, D, G, J, N' 옵션은 B, D, G, J, N 열의 값만 저장한다. pop_Seoul = pd.read_excel('./population_in_Seoul.xls', header=2, parse_cols='B, D, G, J, N', encoding = 'euc-kr') pop_Seoul.head()
- 3번째 행부터 특정 열만 저장되어 출력된 것을 확인할 수 있다.
3) 컬럼명 변경하기
# 위에서 1번 정제과정을 거친 population_in_Seoul.xls의 가로줄 이름을 바꾸고 # 실제 데이터에서도 적용 pop_Seoul.rename(columns={pop_Seoul.columns[0] : '구별', pop_Seoul.columns[1] : '인구수', pop_Seoul.columns[2] : '한국인', pop_Seoul.columns[3] : '외국인', pop_Seoul.columns[4] : '고령자'}, inplace = True) pop_Seoul.head()
- 컬럼명이 변경된 것을 확인할 수 있다.
4) 정렬하기[1]
- 오름차순
#CCTV_in_Seoul_2018.csv의 맨 위 부터 5줄을 출력 #소계를 중심으로 오름차순 # ascending 옵션의 True는 오름차순, False는 내림차순 정렬이다. CCTV_Seoul.sort_values(by='소계', ascending=True).head(5)
- 소계를 기준으로 오름차순 정렬되었다.
- 내림차순
#소계를 중심으로 내림차순 CCTV_Seoul.sort_values(by='소계', ascending=False).head(5)
- 소계를 기준으로 내림차순 정렬되었다.
5) 새로운 컬럼 생성하기[1]
#CCTV의 최근 증가율을 구하기 위해서는 17년+16년+15년+14년을 더해서 13년 이전으로 나누고 100를 곱해준다. #'최근증가율'을 기준으로 내림차순 정리하여 5째줄까지 출력. CCTV_Seoul['최근증가율'] = (CCTV_Seoul['2017년'] + CCTV_Seoul['2016년'] + CCTV_Seoul['2015년'] + CCTV_Seoul['2014년']) / CCTV_Seoul['2013년 이전'] * 100 #최근증가율을 중심으로 내림차순 CCTV_Seoul.sort_values(by='최근증가율', ascending=False).head(5)
- 최근증가율이라는 컬럼이 생성되었고 내용은 13년대비 최근 5년간 CCTV증가비율을 계산하였다.
6) 이상치데이터 삭제하기
[1] 이상치데이터란?
- 측정 데이터 범위를 벗어난 값을 말한다.
# '구별' 컬럼에서 1번이라도 나온 값을 출력 # (중복된 것도 1번만 나옴) # 서울시에 강서구가 1개만 있어야 한다. pop_Seoul['구별'].unique() # 구가 아닌 nan이 들어있다.(이상치데이터)
- 출력결과를 잘 살펴보면 마지막에 nan 이라는 데이터가 들어있고 Enter로 인해 발생한 것으로 예상된다.
7) index 찾기
# isnull() : '구별'에서 NAN값이 있는 것을 출력 # 널값이 있는 행 출력!! pop_Seoul[pop_Seoul['구별'].isnull()]
- 26번째 인덱스임을 확인한다.
8) 행 삭제
# 위에서 26번줄에서 Nan이 있는 것을 알아서 삭제하려고 한다. pop_Seoul.drop([26], inplace=True) pop_Seoul.tail()
- 아래서부터 5개를 출력해서 26번째 인덱스가 삭제됨을 확인한다.
9) 새로운 컬럼 생성하기[2]
# 외국인/고령자 비율을 구하기 위해서 인구수로 나누어주고 100을 곱한다. # 외국인비율과 고령자비율이라는 필드 2개가 생성되었다. pop_Seoul['외국인비율'] = pop_Seoul['외국인'] / pop_Seoul['인구수'] * 100 pop_Seoul['고령자비율'] = pop_Seoul['고령자'] / pop_Seoul['인구수'] * 100 pop_Seoul.head()
- 그림에서 보이는 것처럼 외국인비율과 고령자비율 열이 추가되었다.
10) 정렬하기[2]
# '인구수'를 기준을 내림차순 정렬 후 출력 pop_Seoul.sort_values(by='인구수', ascending=False).head(10)
- 인구수를 기준으로 내림차순 정렬되었다.
11) 파일 내보내기
# pop_Seoul_finalData.xls 저장 pop_Seoul.to_excel('./pop_Seoul_result_save.xls', encoding='euc-kr') # 저장 후 파일을 열어서 확인해볼 수 있다.
12) 병합하기
# CCTV_Seoul과 pop_Seoul의 공동 컬럼인 '구별' 컬럼으로 두 데이터프레임을 합친다. # 합치고 난 후, 맨 위 5줄을 출력 data_result = pd.merge(CCTV_Seoul, pop_Seoul, on="구별") data_result.head()
- '구별' 컬럼을 기준으로 두 데이터프레임이 합쳐진 것을 확인할 수 있다.
13) 열 삭제하기
# 행 방향으로 데이터 삭제 : drop # 열 방향으로 데이터 삭제 : del del data_result['2013년 이전'] del data_result['2014년'] del data_result['2015년'] del data_result['2016년'] del data_result['2017년'] data_result.head()
- 5개의 열이 삭제된 것을 확인할 수 있다.
14) 상관관계 확인하기
# np.corrcoef() : 상관계수를 계산해주는 함수 # 1이면 양의 상관관계 - 1사분면 상의 비례그래프 # -1이면 음의 상관관계 - 1사분면 상의 반비례그래프 # 0이면 상관 없음 # 고령자비율과 CCTV의 개수을 상관관계 보기 np.corrcoef(data_result['고령자비율'],data_result['소계']) # 1을 제외한 값을 기준으로 상관관계가 있는지 없는지 확인할 수 있다
- 1을 100%으로 보면 0.25는 25%로 '고령자비율'과 'CCTV개수' 는 상관관계가 크지 않다고 보여진다.
# 외국인비율과 CCTV의 개수을 상관관계 보기 np.corrcoef(data_result['외국인비율'],data_result['소계'])
- 0%에 가까운 3%정도 되는 것으로 보아 상관이 거의 없는 것으로 보여진다.
5. 그래프로 분석하기
1) 그래프 작성시 사용하는 라이브러리 추가하기
#matplotlib(맷플로라이브) -> 그래프 그릴 때 사용하지만 한글을 지원하지 않기 때문에 폰트를 변경해야 한다. import platform import matplotlib.pyplot as plt %matplotlib inline #주피터 노트북에서 지원해주는 라이브러리이다. from matplotlib import font_manager, rc #폰트 관련된 모듈이다. 매트플로라이브에 들어있다. plt.rcParams['axes.unicode_minus'] = False if platform.system() == 'Darwin' : rc('font', family='AppleGothic') elif platform.system() =='Windows' : path = "c:/Windows/Fonts/malgun.ttf" font_name = font_manager.FontProperties(fname=path).get_name() rc('font', family=font_name) else : print('Unknown system... sorry')
2) 막대그래프 시각화하기
# 'barh' : 수평 막대그래프 # 그래프 뒤 격자무늬 표시하기 # 그래프 사이즈는 10 * 10 # .show()는 보여주다. data_result['소계'].plot(kind='barh', grid=True, figsize=(10, 10)) plt.show() # plt는 위에서 import matplotlib.pyplot as plt 로 선언.
- '구별'로 '소계'를 막대그래프로 보여준다.
3) 정렬하기[3]
# 데이터 값을 오름차순으로 정렬 # 기본으로 내림차순 정리가 되어있다. # grid 는 보여주다 data_result['소계'].sort_values().plot(kind='barh', grid=True, figsize=(10, 10))
- '소계'를 기준으로 내림차순 정렬이 되어있다.
4) 새로운 컬럼 생성하기[3]
#고령자 / 인구수 data_result['고령자비율'] = data_result['고령자'] / data_result['인구수'] * 100 data_result['고령자비율'].sort_values().plot(kind='barh', grid=True, figsize=(10, 10)) plt.show()
- 한 눈에 봐도 알 수 있듯이 강북구에 인구 수 대비 고령자가 많이 사는 것을 확인할 수 있다.
5) 산포도그래프 시각화하기
#그래프 사이즈는 6 * 6 # 산포도 그래프로 시각화 # 점의 크기는 50 # xlabel의 이름은 '인구수' # ylabel의 이름은 'CCTV' # 그래프 배경에 격자 무늬 표시 plt.figure(figsize=(6,6)) plt.scatter(data_result['인구수'], data_result['소계'], s=50) plt.xlabel('인구수') plt.ylabel('CCTV') plt.grid() plt.show()
- x축과 y축으로 구성된 2차원 화면에서 산포도를 확인할 수 있다.
6) 직선 그리기[1]
# np.polyfit() : 직선을 만드는 함수이다. # 직선의 개수는 1개이다 # 독립변수 : 인구수, 종속변수, 소계를 최소 에러값으로 fitting하는 다항식 곡선식을 구한다. # 참고 URL : https://docs.scipy.org/doc/numpy-1.14.0/reference.gernerated.numpy.polyfit.h... # 출력결과의 하나는 기울기이고 하나는 절편이다. fp1 = np.polyfit(data_result['인구수'], data_result['소계'], 1) fp1 #직선을 긋는 함수
7) 수치값 표현하기
# 우리눈에는 직선으로 보이지만 하나하나를 수치값을 표현한다. # x축 데이터는 np.linspace로 값을 할당하고, # y축4 데이터는 np.polyld로 값을 할당한다. f1 = np.poly1d(fp1) print(f1) #x축 값 100,000 ~ 700,000 구간을 100개의 구간으로 나눔 fx = np.linspace(100000, 700000, 100) print(fx)
8) 직선그리기[2]
# 직선의 모양(dashed)은 점선이고 선의 두께는 3, 선 색깔은 'green'으로 설정 # 원의 크기는 s = 50 plt.figure(figsize=(10, 10)) plt.scatter(data_result['인구수'], data_result['소계'], s = 50) plt.plot(fx, f1(fx), ls='dashed', lw=3, color='g') plt.xlabel('인구수') plt.ylabel('CCTV') plt.grid() plt.show()
9) 오차 구하기
fp1 = np.polyfit(data_result['인구수'], data_result['소계'], 1) f1 = np.poly1d(fp1) fx = np.linspace(100000, 700000, 100) # 오차를 구할 때, '소계'-'인구수'를 한다. # 이 때, 음수로 결과가 나오지 않도록 np.abs 함수를 사용해 절대값으로 출력한다. data_result['오차'] = np.abs(data_result['소계'] - f1(data_result['인구수'])) # '오차'로 내림차순 정리 df_sort = data_result.sort_values(by='오차', ascending=False) df_sort.head()
10) 오차범위 적용해서 그래프 시각화하기
# 그래프의 크기는 14 * 10 # 산포도 그래프의 x값은 '인구수', y값은 '소계', '오차' 데이터 표시는 데이터의 값에 따라 # 색이 변한다. plt.figure(figsize=(14, 10)) plt.scatter(data_result['인구수'], data_result['소계'], c = data_result['오차'], s = 50) plt.plot(fx, f1(fx), ls='dashed', lw=3, color='g') # 0~9까지 위에 있는 10개 지역을 text로 표시하는 for문 for n in range(10): # x 값으로부터 1.02, y 값으로부터 0.98만큼 떨어진 곳에 text를 표시하고 # fontsize는 15 plt.text(df_sort['인구수'][n]*1.02, df_sort['소계'][n]*0.98, df_sort.index[n], fontsize=15) plt.xlabel('인구수') plt.ylabel('인구당비율') plt.grid() plt.show()
※ 자주 사용하는 주피터노트북 옵션
- 처음부터 전체 실행할 때 사용한다.
- 복사본을 만들어놓고 작업할 때 사용한다.
- 출력결과만 따로 확인할 때 사용한다.
- 작성한 코드를 파이썬 소스로 다운로드할 때 사용한다.
- 기존에 실행했었던 남아있는 내용을 지우고 재실행할 때 사용한다.
- 소스 라인을 표시할 때 사용한다.
'Programming Language > Python' 카테고리의 다른 글
[File_Filter] 파일 분류하는 방법 (0) | 2019.08.06 |
---|---|
함수 기초 (0) | 2018.10.03 |
자료타입 (0) | 2018.09.15 |
파이썬 기본문법 (0) | 2018.09.04 |
Anaconda3 설치방법 (0) | 2018.09.04 |
댓글