[EDA] (1) 서울시 CCTV 현황 데이터 분석

greta·2023년 5월 29일
0

1. 데이터 읽기

  • 판다스 불러오기
import pandas as pd 
  • 데이터 불러오기
CCTV_Seoul = pd.read_csv("../data/01. Seoul_CCTV.csv")
# 다른 형식도 가능 (read_excel, ...)
  • 데이터 확인하기
CCTV_Seoul.head() #괄호 안에 숫자만큼, 없으면 5개
CCTV_Seoul.tail()
  • 컬럼명 변경
CCTV_Seoul.rename(columns={CCTV_Seoul.columns[0]: "구별"}, inplace=True)
# inplace=True는 변경된 값을 바로 저장하여 덮어씀

Pandas 기초

  • Python에서 R 만큼의 강력한 데이터 핸들링 성능을 제공하는 모듈
  • 단일 프로세스에서는 최대 효율
  • 코딩 가능하고 응용 가능한 엑셀로 받아들여도 됨
  • 누군가 스테로이드를 맞은 엑셀로 표현함

Series

  • index와 value로 이루어져 있습니다
  • 한 가지 데이터 타입만 가질 수 있습니다
import pandas as pd 
import numpy as np 

pd.Series()
  • 날짜 데이터
dates = pd.date_range("20210101", periods=6)

DataFrame

  • pd.Series()
    • index, value
  • pd.DataFrame()
    • index, value, column
  • 데이터프레임 정보 탐색
df.head()
df.tail()
df.index
df.columns
df.values
df.info() # 데이터 프레임의 기본 정보 확인
df.describe() # 데이터 프레임의 기술통계 정보 확인
  • 데이터 정렬
df.sort_values(by="B", ascending=False, inplace=True)
  • 데이터 선택
# 한 개 컬럼 선택 
df["A"] 
df.A

# 데이터 프레임 만들기
df = pd.DataFrame(data, index=dates, columns=["A", "B", "C", "D"])

# 여러 컬럼 선택
df[["A", "B"]]

offset index

  • [n:m] : n부터 m-1 까지
  • 인덱스나 컬럼의 이름으로 slice 하는 경우는 끝을 포함합니다
  • iloc : inter location
    • 컴퓨터가 인식하는 인덱스 값으로 선택
df[0:3]
df["20210101":"20210104"]
df.loc[:, ["A", "B"]]
df.loc["20210102":"20210104", ["A", "D"]]
df.loc["20210102":"20210104", "A":"D"]
df.loc["20210102", ["A", "B"]]
df.iloc[3]
df.iloc[3, 2]
df.iloc[3:5, 0:2]
df.iloc[[1, 2, 4], [0, 2]]
df.iloc[:, 1:3]

condition

# A 컬럼에서 0보다 큰 숫자(양수)만 선택 
df["A"] > 0 #결과가 Series로
df[df["A"] > 0] #결과가 DataFrame으로

컬럼 추가

  • 기존 컬럼이 없으면 추가
  • 기존 컬럼이 있으면 수정
df["E"] = ["one", "one", "two", "tree", "four", "seven"]
  • isin() : 특정 요소가 있는지 확인
df["E"].isin(["two"])
df["E"].isin(["two", "five"])
df[df["E"].isin(["two", "five", "three"])]

특정 컬럼 제거

  • del
  • drop
del df["E"]
df.drop(["D"], axis=1) # axis=0 가로, axis=1 세로
df.drop(["20210104"])

apply()

  • 행 또는 열 또는 전체의 셀에 원하는 연산 지원
df["A"].apply("sum")
df["A"].apply("mean")
df["A"].apply("min"), df["A"].apply("max")
df[["A", "D"]].apply("sum")
df["A"].apply(np.sum)
df["A"].apply(np.mean)
df["A"].apply(np.std)
df.apply(np.sum)
df["A"].apply(함수)

2. CCTV 데이터 훑어보기

# 기존 컬럼이 없으면 추가, 있으면 수정
CCTV_Seoul["최근증가율"] = (
    (CCTV_Seoul["2016년"] + CCTV_Seoul["2015년"] + CCTV_Seoul["2014년"]) / CCTV_Seoul["2013년도 이전"] * 100
)

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

3. 인구현황 데이터 훑어보기

  • 불필요한 인덱스(행) 제거하기
pop_Seoul.drop([0], axis=0, inplace=True)
  • 비율 추가
# 외국인비율, 고령자비율 

pop_Seoul["외국인비율"] = pop_Seoul["외국인"] / pop_Seoul["인구수"] * 100
pop_Seoul["고령자비율"] = pop_Seoul["고령자"] / pop_Seoul["인구수"] * 100
pop_Seoul.head()

pop_Seoul.sort_values(["인구수비율"], ascending=False).head(5)
pop_Seoul.sort_values(["외국인비율"], ascending=False).head(5)

Pandas에서 데이터 프레임을 병합하는 방법

  • pd.concat()
  • pd.merge()
  • pd.join()

pd.merge()

  • 두 데이터 프레임에서 컬럼이나 인덱스를 기준으로 잡고 병합하는 방법
  • 기준이 되는 컬럼이나 인덱스를 키값이라고 합니다
  • 기준이 되는 키값은 두 데이터 프레임에 모두 포함되어 있어야 합니다

4. 두 데이터 합치기

data_result = pd.merge(CCTV_Seoul, pop_Seoul, on="구별")
data_result.drop(["2015년", "2016년"], axis=1, inplace=True)

인덱스 변경

  • set_index()
  • 선택한 컬럼을 데이터 프레임의 인덱스로 지정
data_result.set_index("구별", inplace=True)

상관계수

  • corr()
  • correlation 의 약자입니다
  • 상관계수가 0.2 이상인 데이터를 비교
data_result.corr()

* matplotlib 기초

불러오기 및 한글 사용 설정

import matplotlib.pyplot as plt 
from matplotlib import rc 

rc("font", family="Arial Unicode MS") # Windows : Malgu Gothic 
# %matplotlib inline 
get_ipython().run_line_magic("matplotlib", "inline")

최근 다른 강의에서 koreanize matplotlib 을 import 해오는 걸 봤는데... 다시 확인해볼 필요가 있음

matplotlib 그래프 기본 형태

plt.figure(figsize=(10, 6))
plt.plot(x, y)
plt.show

1) 그래프 기초

def drawGraph():

    plt.figure(figsize=(10, 6))
    plt.plot(t, np.sin(t), label="sin")
    plt.plot(t, np.cos(t), label="cos")
    plt.grid(True) # 격자무늬 바탕 추가
    plt.legend(loc=2) # 범례 
    plt.title("Example of sinewave") # 제목 추가
    plt.xlabel("time") # xlabel 추가
    plt.ylabel("Amplitude") # ylabel 추가 
    plt.show()
    
drawGraph() 

2) 그래프 커스텀

plt.figure(figsize=(10, 6))
plt.plot(t, t, "r--") # red ---- 
plt.plot(t, t ** 2, "bs") # blue 사각형
plt.plot(t, t ** 3, "g>") # green 삼각형
plt.show()

def drawGraph():

    plt.figure(figsize=(10, 6))
    plt.plot(
        t,
        y,
        color="red", 
        linestyle="--", 
        marker="o", 
        markerfacecolor="blue",
        markersize=10, 
    )

    plt.xlim([-0.5, 6.5]) # x축 나타낼 범위
    plt.ylim([0.5, 9.5]) # y축 나타낼 범위
    plt.show() 
    
drawGraph()

3) 산점도 그래프 scatter plot

def drawGraph():

    plt.figure(figsize=(10, 6))
    plt.scatter(t, y)
    plt.show()
    
drawGraph()

colormap = t 

def drawGraph():

    plt.figure(figsize=(10, 6))
    plt.scatter(t, y, s=150, c=colormap, marker="<")
    plt.colorbar()
    plt.show()
    
drawGraph()

4) Pandas에서 plot 그리기

  • matplotlib 을 가져와서 사용합니다
data_result["인구수"].plot(kind="bar", figsize=(10, 10));

data_result["인구수"].plot(kind="barh", figsize=(10, 10));

def drawGraph():
    data_result["소계"].sort_values().plot(
        kind="barh", grid=True, title="가장 CCTV가 많은 구", figsize=(10, 10));
drawGraph()

6. 데이터의 경향 표시

Numpy를 이용한 1차 직선 만들기

  • np.polyfit(): 직선을 구성하기 위한 계수를 계산
  • np.poly1d(): polyfit 으로 찾은 계수로 파이썬에서 사용할 수 있는 함수로 만들어주는 기능
import numpy as np 
fp1 = np.polyfit(data_result["인구수"], data_result["소계"], 1)
f1 = np.poly1d(fp1)
fx = np.linspace(100000, 700000, 100)
  • 경향선을 그리기 위한 X 데이터 생성
  • np.linspace(a, b, n): a부터 b까지 n개의 등간격 데이터 생성
def drawGraph():
    
    plt.figure(figsize=(14, 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(True)
    plt.show() 
drawGraph()

7. 강조하고 싶은 데이터를 시각화해보자

그래프 다듬기

경향과의 오차 만들기

  • 경향(trend)과의 오차를 만들자
  • 경향은 f1 함수에 해당 인구를 입력
  • f1(data_result["인구수"])
data_result["오차"] = data_result["소계"] - f1(data_result["인구수"])

# 경향과 비교해서 데이터의 오차가 너무 나는 데이터를 계산 
df_sort_f = data_result.sort_values(by="오차", ascending=False) # 내림차순 
df_sort_t = data_result.sort_values(by="오차", ascending=True) # 오름차순   
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(data_result["인구수"], data_result["소계"], s=50, c=data_result["오차"], cmap=my_cmap)
    plt.plot(fx, f1(fx), ls="dashed", lw=3, color="g")

    for n in range(5):
        # 상위 5개 
        plt.text(
            df_sort_f["인구수"][n] * 1.02, # x 좌표
            df_sort_f["소계"][n] * 0.98,  # y 좌표
            df_sort_f.index[n], # title 
            fontsize=15,
        )
    
        # 하위 5개 
        plt.text(
            df_sort_t["인구수"][n] * 1.02, 
            df_sort_t["소계"][n] * 0.98,
            df_sort_t.index[n],
            fontsize=15
        )
        
    
    plt.xlabel("인구수")
    plt.ylabel("CCTV")
    plt.colorbar()
    plt.grid(True)
    plt.show() 
drawGraph()

  • 데이터 저장
data_result.to_csv("../data/01. CCTV_result.csv", sep=",", encoding="utf-8")

🎅오늘의 한마디

실제 데이터를 만지고 그래프도 그려보니 너무 재미있다. 데이터의 전처리가 되어있어서 그럴 수도 있겠지만, 지치지않고 즐겁게 계속하길.

0개의 댓글