서울시 범죄 현황 데이터 분석_2

YJ·2023년 3월 31일

▷ 오늘 학습 계획: EDA 강의(범죄 4~6)

프로젝트 개요

데이터 과학의 목적: 가정(또는 인식)을 검증하고 표현하는 것

데이터 개요

  • 필요한 모듈 import → numpy, pandas
  • 데이터 읽기
crime_raw_data = pd.read_csv("../data/02. crime_in_Seoul.csv", thousands = ",", encoding="euc-kr")
# 숫자값들이 콤마를 사용하고 있어서 문자로 인식될 수 있다.
# thousands -> 콤마를 제거하고 숫자형으로 읽는다
  • 데이터 개요 확인하기
crime_raw_data.info()
# RangeIndex가 65534인데, 데이터는 310개
  • 특정 컬럼에서 unique 조사
crime_raw_data["죄종"].unique()
# nan값이 들어가 있음
  • nan값만 추출하기
crime_raw_data[crime_raw_data["죄종"].isnull()]
  • nan이 아닌 데이터만 다시 가져오기
crime_raw_data = crime_raw_data[crime_raw_data["죄종"].notnull()]
crime_raw_data.info()

서울시 범죄 현황 데이터 정리

  • Pandas Pivot Table 적용
crime_station = crime_raw_data.pivot_table(
    crime_raw_data, 
    index="구분", 
    columns=["죄종", "발생검거"], 
    aggfunc=[np.sum])
crime_station.columns
# multiIndex 확인됨
  • 다중 컬럼에서 특정 컬럼("sum", "건수") 제거
crime_station.columns = crime_station.columns.droplevel([0,1])
crime_station.index
# 경찰서 이름으로 index 구성됨
# 경찰서 이름을 통해 구 이름 알아내야 함

데이터 정리_Google Maps

import googlemaps
gmaps_key = "Google Map API Key 입력"
gmaps = googlemaps.Client(key=gmaps_key)
tmp = gmaps.geocode("서울영등포경찰서", language="ko")
  • 위도, 경도, 구 이름 구하기
# 전체 결과 크기가 1인 list형, 큰 리스트 안에 dict형
tmp[0].get("geometry")["location"]["lat"]  #위도
tmp[0].get("geometry")["location"]["lng"]  #경도
tmp[0].get("formatted_address").split()[2]  #구 이름
  • 구 이름과 위도 경도 정보를 저장하기 위해 컬럼 새로 만들고 NaN값 입력
crime_station["구별"] = np.nan
crime_station["lat"] = np.nan
crime_station["lng"] = np.nan
  • iterrows() 반복문으로 NaN값 모두 채워주기
count = 0
for idx, rows in crime_station.iterrows():
    station_name = "서울" + str(idx) + "경찰서"    
    tmp = gmaps.geocode(station_name, language="ko")
    tmp_gu = tmp[0].get("formatted_address")    
    lat = tmp[0].get("geometry")["location"]["lat"]
    lng = tmp[0].get("geometry")["location"]["lng"]
    crime_station.loc[idx, "lat"] = lat
    crime_station.loc[idx, "lng"] = lng
    crime_station.loc[idx, "구별"] = tmp_gu.split()[2]
    print(count)
    count += 1
  • 두 줄로 되어 있는 컬럼을 하나로 합치기
tmp = [
    crime_station.columns.get_level_values(0)[n] + crime_station.columns.get_level_values(1)[n]
    for n in range(0, len(crime_station.columns.get_level_values(0)))
]
  • 바꾼 컬럼으로 columns 지정하기
crime_station.columns = tmp

구별 데이터로 정리

  • 서울은 한 구에 경찰서가 두 곳인 구가 있어서 구의 이름으로 다시 정렬
    index_col: 특정 컬럼을 인덱스로 지정
crime_anal_station = pd.read_csv("../data/02. crime_in_Seoul_raw.csv", 
	index_col=0, encoding = "utf-8")
  • 구별 피벗테이블
crime_anal_gu = pd.pivot_table(
crime_anal_station, index="구별", aggfunc=np.sum
)
  • 위도와 경도 컬럼 삭제
del crime_anal_gu["lat"]
crime_anal_gu.drop("lng", axis=1, inplace=True)
  • 검거율 생성
target=["강간검거율", "강도검거율", "살인검거율", "절도검거율", "폭력검거율"]
num=["강간검거", "강도검거", "살인검거", "절도검거", "폭력검거"]
den=["강간발생", "강도발생", "살인발생", "절도발생", "폭력발생"]
crime_anal_gu[target] = crime_anal_gu[num].div(crime_anal_gu[den].values)*100
  • 필요 없는 컬럼 제거
del crime_anal_gu["강간검거"]
del crime_anal_gu["강도검거"]
del crime_anal_gu["살인검거"]
crime_anal_gu.drop(["절도검거", "폭력검거"], axis = 1, inplace = True)
  • 그래프에서 문제될 수 있어서 100보다 큰 숫자 찾아서 바꾸기
crime_anal_gu[crime_anal_gu[target] > 100] = 100
  • 컬럼 이름 변경
crime_anal_gu.rename(
	columns={"강간발생":"강간", 
    		"강도발생":"강도", 
            "절도발생":"절도", 
            "폭력발생":"폭력", 
            "살인발생":"살인"}, inplace=True)

데이터 정렬을 위한 데이터 정리

  • 정규화: 최댓값1, 최솟값0
    본래 DataFrame은 두고, 정규화된 데이터 따로 만들기
col = ["살인", "강도", "강간", "절도", "폭력"]
crime_anal_norm = crime_anal_gu[col] / crime_anal_gu[col].max()
  • 정규화된 데이터에 검거율 컬럼 추가
col2 = ["강간검거율", "강도검거율", "살인검거율", "절도검거율", "폭력검거율"]
crime_anal_norm[col2] = crime_anal_gu[col2]
  • 구별 CCTV 자료에서 인구수와 CCTV수 추가
result_CCTV = pd.read_csv("../data/01. CCTV_result.csv", index_col="구별", encoding="utf-8")
crime_anal_norm[["인구수", "CCTV"]] = result_CCTV[["인구수", "소계"]]
  • 정규화된 범죄발생 건수 전체의 평균을 구해서 범죄 대표값으로 사용
col = ["강간", "강도", "살인", "절도", "폭력"]
crime_anal_norm["범죄"] = np.mean(crime_anal_norm[col], axis = 1)
  • 검거율의 평균을 구해서 검거의 대표값으로 사용
col = ["강간검거율", "강도검거율", "살인검거율", "절도검거율", "폭력검거율"]
crime_anal_norm["검거"] = np.mean(crime_anal_norm[col], axis = 1)

범죄 현황 데이터 시각화

pairplot

  • 강도, 살인, 폭력에 대한 상관관계 확인
sns.pairplot(
    data = crime_anal_norm,
    vars = ["살인", "강도", "폭력"],
    kind = "reg",
    size = 3);
# kind : {'scatter', 'kde', 'hist', 'reg'}
  • "인구수", "CCTV"와 "살인", "강도"의 상관관계 확인
sns.pairplot(
    data = crime_anal_norm, 
    x_vars = ["인구수", "CCTV"], 
    y_vars = ["살인", "강도"], 
    kind = "reg", 
    size = 4)
    plt.show()
  • "인구수", "CCTV"와 "살인검거율", "폭력검거율"의 상관관계 확인
sns.pairplot(
    data = crime_anal_norm, 
    x_vars = ["인구수", "CCTV"], 
    y_vars = ["살인검거율", "폭력검거율"], 
    kind = "reg", 
    size = 4)
    plt.show()
  • "인구수", "CCTV"와 "절도검거율", "강도검거율"의 상관관계 확인
sns.pairplot(
    data = crime_anal_norm, 
    x_vars = ["인구수", "CCTV"], 
    y_vars = ["절도검거율", "강도검거율"], 
    kind = "reg", 
    size = 4)
    plt.show()
  • "검거" 컬럼을 기준으로 검거율 heatmap
def drawGraph():
    # 데이터 프레임 생성
    target_col = ["강간검거율", "강도검거율", "살인검거율", "절도검거율", "폭력검거율", "검거"]
    crime_anal_norm_sort = crime_anal_norm.sort_values(by="검거", ascending=False)
    #그래프 설정
    plt.figure(figsize=(10,10))
    sns.heatmap(
        data = crime_anal_norm_sort[target_col], 
        annot=True, #데이터값표현
        fmt="f", 
        linewidth=0.5, #간격설정(디폴트값 0)
        cmap="RdPu")
    plt.title("범죄 검거 비율(정규화된 검거의 합으로 정렬)")
    plt.show()
drawGraph()
  • "범죄"컬럼을 기준으로 범죄발생 건수 heatmap
def drawGraph():
    # 데이터 프레임 생성
    target_col = ["살인", "강도", "강간", "절도", "폭력", "범죄"]
    crime_anal_norm_sort = crime_anal_norm.sort_values(by="범죄", ascending=False)
    #그래프 설정
    plt.figure(figsize=(10,10))
    sns.heatmap(
        data = crime_anal_norm_sort[target_col], 
        annot=True, #데이터값표현
        fmt="f", 
        linewidth=0.5, #간격설정(디폴트값 0)
        cmap="RdPu")
    plt.title("범죄 비율(정규화된 발생 건수로 정렬)")
    plt.show()
drawGraph()

범죄 현황에 대한 지도 시각화

  • folium.Choropleth()
    구별 범죄 현황 지도 시각화(범죄 발생 건수, 인구 대비 범죄 발생 건수)
  • folium.Marker(): 경찰서 위치 지도에 표시
  • folium.CircleMarker(): 경찰서별 검거율 원의 넓이로 표현

서울시 범죄 현황 발생 장소 분석

범죄 발생 장소별 데이터를 통한 추가 검증

def drawGraph():
    plt.figure(figsize = (10,10))
    sns.heatmap(
        crime_loc_norm_sort,
        annot = True,
        fmt = "f",
        linewidths = 0.5,
        cmap = "RdPu")
    plt.title("범죄 발생 장소")
    plt.show()
drawGraph()

📝 퀴즈 풀면서 헷갈렸던 부분: Pandas data frame을 반복문에서 사용하는 iterrows() 함수, pandas의 read_csv 명령에서 thousands 옵션 → 이해했다고 생각했는데 문제 풀때는 헷갈려서 고민했다. 복습하면서 개념 정리 다시 해야겠다.

▷ 내일 학습 계획: EDA 강의(웹데이터 1~3)

[이 글은 제로베이스 데이터 취업 스쿨의 강의 자료 일부를 발췌하여 작성되었습니다.]

0개의 댓글