[zero-base/] DS Part 4. EDA - 23일차 스터디 노트

손윤재·2024년 1월 3일

제로베이스 DS 22기

목록 보기
24/55
post-thumbnail

실습 프로젝트 1️⃣

【서울시 CCTV 현황 데이터 분석】

실습 목표


1. 분석 데이터 불러오기

🔰 서울시 구별 CCTV 현황 데이터(.csv)

    import pandas as pd

    CCTV_Seoul = pd.read_csv("../data/01. Seoul_CCTV.csv")
  • 한글이 깨져 나올 경우 encoding='utf-8'로 옵션을 설정해 준다.

< 컬럼명 변경 >

	CCTV_Seoul.rename(columns={"기관명": "구별"}, inplace=True)
    CCTV_Seoul.head()

🔰 서울시 구별 인구 현황 데이터(.xls)

    popul_seoul = pd.read_excel(
        "../data/01. Seoul_Population.xls", header=2, usecols="B, D, G, J, N"
    )

  • 필요한 부분만 읽어온다.
    • header는 자료를 읽기 시작할 행을 지정한다.
    • 필요한 엑셀의 컬럼인 ‘합계’만 가져온다.

< 컬럼명 변경 >

    popul_seoul.rename(
        columns={
            popul_seoul.columns[0]: "구별",
            popul_seoul.columns[1]: "인구수",
            popul_seoul.columns[2]: "한국인",
            popul_seoul.columns[3]: "외국인",
            popul_seoul.columns[4]: "고령자"
        },
        inplace=True
    )


2. 분석 데이터 훑어보기

🔰 CCTV 데이터

< 가장 많은 CCTV를 보유한 구 >

CCTV_Seoul.sort_values(by='소계', ascending=False).head()

< “최근증가율” 컬럼 추가 >

  • 이전에 보유한 CCTV 개수 대비 최근 3년(2014~2016)간 CCTV를 가장 많이 설치한 구는?
CCTV_Seoul["최근증가율"] = (
	(CCTV_Seoul["2014년"] + CCTV_Seoul["2015년"] + CCTV_Seoul["2016년"]) / CCTV_Seoul["2013년도 이전"] * 100
)

CCTV_Seoul.sort_values(by='최근증가율', ascending=False).head()

🔰 인구 데이터

< 첫 행(row[0])의 '합계' 데이터 삭제 >

  • '합계' 데이터는 필요 없으므로 행을 지우는 명령인 drop() 메서드를 사용해 지운다.
    popul_seoul.drop([0], inplace=True)
    popul_seoul.head()

< 외국인과 고령자 비율 컬럼 추가 >

  • 데이터 행 25개를 컬럼 연산으로 한번에 연산이 가능하다.
    popul_seoul["외국인비율"] = popul_seoul["외국인"] / popul_seoul["인구수"] * 100
    popul_seoul["고령자비율"] = popul_seoul["고령자"] / popul_seoul["인구수"] * 100
    popul_seoul.head()


3. 분석 데이터 병합하기

🔰 “구별”로 CCTV & 인구 데이터 병합

	merge_data = pd.merge(CCTV_Seoul, popul_seoul, on="구별")

🔰 필요 없는 연도별 데이터 컬럼 삭제

    del merge_data["2013년도 이전"]
    del merge_data["2014년"]
    merge_data.drop(["2015년", "2016년"], axis=1, inplace=True)

🔰 인덱스 지정

  • 시각화 작업을 위해 인덱스를 변경한다.
  • 인덱스로 지정하려면 중복되는 값이 없어야 한다.
  • 인덱스를 재정의 하는 메서드는 set_index()이다.
    merge_data.set_index("구별", inplace=True)
    merge_data.head()

🔰 상관관계 파악

  • 상관관계(correlation)란, 두 변량 사이에 한쪽이 증가하면 다른 쪽도 증가 또는 감소하는 경향이 있을 때, 이 두 변량 사이에는 상관관계가 있다고 한다.
    단, 상관관계가 있다하여 두 변랑이 인과관계인 것은 아니다.
  • 데이터의 관계를 찾을 때, 최소한의 근거가 있어야 해당 데이터를 비교하는 의미가 있다.
  • 상관계수가 0.2 이상인 데이터를 비교하는 것은 의미가 있다.
  • 상관계수 연상을 위해서는 int나 float 자료형이어야 한다.
	merge_data.corr()

  • CCTV 전체 수(소계)와 가장 상관관계가 있는 데이터는 "인구수"(0.232555)이다.
  • 인구대비 CCTV 비율을 새로운 컬럼으로 만든다.
	merge_data["CCTV비율"] = merge_data["소계"] / merge_data["인구수"] * 100


4. 분석 데이터 시각화하기

🔰 pandas에서 plot 그리기

  • pandas DataFrame은 데이터 변수에서 바로 plot() 함수를 사용할 수 있다.
  • 데이터가 많을 경우 정렬한 후 그리는 것이 효과적일 때가 많다.
    merge_data["인구수"].plot(kind="bar", figsize=(10, 6))
    merge_data["인구수"].plot(kind="barh", figsize=(10, 9))

🔰 “소계” 및 "CCTV비율" 컬럼 시각화

    def drawGraph():
        merge_data["소계"].sort_values().plot(
            kind="barh", grid=True, title="가장 CCTV가 많은 구", figsize=(10, 9)
        )
    drawGraph()
    def drawGraph():
        merge_data["CCTV비율"].sort_values().plot(
            kind="barh", grid=True, title="인구대비 CCTV비율이 가장 높은 구", figsize=(10, 9)
        )
    drawGraph()

🔰 데이터의 경향(trend) 시각화

  1. 인구수와 소계 컬럼으로 scatter plot 그리기
    def drawGraph():
        plt.figure(figsize=(14, 10))
        plt.scatter(merge_data["인구수"], merge_data["소계"], s=50)
        plt.xlabel("인구수")
        plt.ylabel("CCTV")
        plt.grid(True)
        plt.show()
        
    drawGraph()

  1. numpy를 이용해 1차 직선 만들기

    • numpy가 제공하는 함수를 이용해 1차 직선(y=ax+b)을 만들어 그래프로 비교한다.
    • np.polyfit() : 직선을 구성하기 위한 계수(기울기와 y절편)를 계산
    • np.poly1d(): polyfit으로 찾은 계수로 파이썬에서 사용할 수 있는 함수로 만들어주는 역할
    import numpy as np
    
    pf1 = np.polyfit(merge_data["인구수"], merge_data["소계"], 1)
    // array([1.11155868e-03, 1.06515745e+03])
    
    f1 = np.poly1d(pf1)
    // poly1d([1.11155868e-03, 1.06515745e+03])
  1. 인구가 40만인 구에서 서울시의 전체 경향에 맞는 적당한 CCTV 수는?

    • 경향선을 그리기 위한 X 데이터 생성
    • np.linspace(a, b, n): a부터 b까지 n개의 등간격 데이터 생성
    fx = np.linspace(100000, 700000, 100) // 100,000과 700,000 사이에 100개의 수 생성
    
    def drawGraph():
        plt.figure(figsize=(14, 10))
        plt.scatter(merge_data["인구수"], merge_data["소계"], s=50)
        plt.plot(
    		fx, f1(fx), ls="dashed", lw=3, color="g"
    	)
        plt.xlabel("인구수")
        plt.ylabel("CCTV")
        plt.grid()
        plt.show()
        
    drawGraph()

🔰 강조하고 싶은 데이터 시각화

  1. 그래프 다듬기

    • 위에서 구한 경향(trend) 함수 f1을 활용해 오차를 만든다.
    • 오차 = 실제 CCTV 개수 - 경향으로 예측한 CCTV 개수
    merge_data["오차"] = merge_data["소계"] - f1(merge_data["인구수"])

    df_sort_desc = merge_data.sort_values(by="오차", ascending=False)
    df_sort_asc = merge_data.sort_values(by="오차")
  1. 경향에서 벗어난 데이터 강조하기

    • 오차가 큰 데이터로 상위 5개, 하위 5개를 선별해 마커 옆에 특별히 구 이름을 명시한다.
    • text() : 그래프에 글자를 그리는 함수
    from matplotlib.colors import ListedColormap
    
    #colormap 을 사용자 정의(user define)로 세팅 
    color_step = ["#e74c3c", "#2ecc71", "#95a9a6", "#2ecc71", "#3498db", "#3498db"]
    my_cmap = ListedColormap(color_step)
    def drawGraph():
        plt.figure(figsize=(14, 10))
        plt.scatter(
    			merge_data["인구수"], merge_data["소계"],
    			s=50, c=merge_data["오차"], cmap=my_cmap
    	)
        plt.plot(fx, f1(fx), ls="dashed", lw=3, color="g")
        
        for n in range(5):
            // 상위 5개 (text가 점을 가리지 않도록 살짝 우측(*1.02) 아래(*0.98)로 이동)
            plt.text(
                df_sort_desc["인구수"][n] * 1.02, # x 좌표
                df_sort_desc["소계"][n] * 0.98,  # y 좌표
                df_sort_desc.index[n], # title 
                fontsize=15,
            )    
            // 하위 5개 
            plt.text(
                df_sort_asc["인구수"][n] * 1.02, 
                df_sort_asc["소계"][n] * 0.98,
                df_sort_asc.index[n],
                fontsize=15
            )
            
        plt.xlabel("인구수")
        plt.ylabel("CCTV")
        plt.colorbar()
        plt.grid()
        plt.show()
        
    drawGraph()

profile
ISTP(정신승리), To Be Data Scientist

0개의 댓글