[EDA] 서울시 범죄 현황 데이터 분석1 - 데이터 재설정, 정리, 필요 데이터 추출, GCP API

박미영·2023년 3월 31일
0

📌서울시 범죄 현황 데이터 재설정

필요한 값들만 가진 데이터(Null 값이 아닌 데이터)들로 원본 데이터를 재설정하기

import numpy as np
import pandas as pd



1. 데이터 읽기

crime_raw_data = pd.read_csv("../data/02. crime_in_Seoul.csv", thousands=",", encoding="euc-kr") # thousands 숫자값을 문자로 인식할 수 있어서 설정
crime_raw_data.head()



2. 데이터 정보 확인

info(): 데이터의 개요 확인하기
RangeIndex가 65534인데, 310개다. -> 문제점

crime_raw_data.info()



3. 중복되지 않은 값 확인

특정 컬럼에서 unique 조사
nan 값이 들어가 있다.

crime_raw_data["죄종"].unique() # 중복되지 않은 값 확인



4. NaN값을 가진 데이터 확인

crime_raw_data[crime_raw_data["죄종"].isnull()].head()



5. 원본 데이터 재설정

NaN 값을 가지지 않은 데이터만 다시 원본 데이터로 설정

crime_raw_data = crime_raw_data[crime_raw_data["죄종"].notnull()]



6. 재설정 후 데이터 정보 확인

전체 index가 310으로 바꼈음을 알 수 있다.

crime_raw_data.info()




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

crime_station = crime_raw_data.pivot_table(
    crime_raw_data, 
    index="구분", 
    columns=["죄종", "발생검거"], 
    aggfunc=[np.sum])
crime_station.head()


  • MultiIndex
crime_station.columns

crime_station["sum", "건수", "강도", "검거"][:5]



📍다중 컬럼에서 특정 컬럼 제거

  • 상단에 있는 2개 컬럼 제거하기(sum, 건수)
crime_station.columns = crime_station.columns.droplevel([0, 1]) # 다중 컬럼에서 특정 컬럼 제거
crime_station.columns

  • 현재 index는 경찰서 이름으로 되어 있다.
  • 경찰서 이름으로 구 이름을 알아내야 한다.
crime_station.index



📌Python 모듈 설치

📍pip 명령

  • python의 공식 모듈 관리자
  • pip list
  • pip install module_name
  • pip uninstall module_name
  • mac(M1)에서 제대로 작동
  • pop list
# = !pop list
get_ipython().system("pip list")



📍conda 명령

  • conda list
  • conda install module_name
  • conda uninstall module_name
  • conda install -c channel_name module_name
    • 지정된 배포 채널에서 모듈 설치
  • Windows, mac(intel)에서 제대로 작동, mac(M1)에서는 잘 작동하지 않는다.



📌Google Maps API 설치

  1. GOOGLE - gcp 검색

  2. 결제 정보 등록

  3. 콘솔

  4. 프로젝트 생성

  5. Geocoding API 사용

  6. API 키 생성

  7. 키 제한

  8. googlemaps 설치

  • Windows, mac(intel)
    conda install -c conda-forge googlemaps

  • mac(M1)
    pip install googlemaps

  1. Jupyter googlemaps import

  2. 확인



📌iterrows()

Pandas에 잘 맞춰진 반복문용 명령

  • Pandas 데이터 프레임은 대부분 2차원
  • 이럴 때 for문을 사용하면, n번째라는 지정을 반복해서 가독률이 떨어짐
  • Pandas 데이터 프레임으로 반복문을 만들때 iterrows() 옵션을 사용하면 편함
  • 받을 때, 인덱스와 내용으로 나누어 받는 것만 주의



📌Google Maps를 이용한 데이터 정리

tmp = gmaps.geocode("서울영등포경찰서", language="ko") 
tmp



📍필요한 데이터 추출

딕셔너리이기때문에 이러한 형태로 접근 가능하다.

📍좌표 추출

tmp[0].get("geometry")["location"]

print(tmp[0].get("geometry")["location"]["lat"])
print(tmp[0].get("geometry")["location"]["lng"])


📍주소 추출

tmp[0].get("formatted_address")

📍주소 中 구만 추출

tmp[0].get("formatted_address").split()

tmp[0].get("formatted_address").split()[2]



📍구별, lat, lng 컬럼 추출

  • 경찰서 이름에서 소속된 구 이름 얻기
  • 구이름과 위도 경도 정보를 저장할 준비
  • 반복문 이용해서 위 표의 NaN을 모두 채워주기


1. 컬럼 생성

NaN 값으로 채워서 생성

crime_station["구별"] = np.nan
crime_station["lat"] = np.nan
crime_station["lng"] = np.nan
crime_station.head()



2. Google Maps 구별, lat, lng 컬럼 추출 후 저장

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").split()[2]	# 구 추출
    lat = tmp[0].get("geometry")["location"]["lat"]	# lat 추출
    lng = tmp[0].get("geometry")["location"]["lng"]	# lng 추출
    
    crime_station.loc[idx, "lat"] = lat
    crime_station.loc[idx, "lng"] = lng
    crime_station.loc[idx, "구별"] = tmp_gu



3. 컬럼명 정리

  • 0번째 라인 접근
crime_station.columns.get_level_values(0)
  • 0번째 라인 갯수
len(crime_station.columns.get_level_values(0))

  • 0번째 라인, 1번째 라인을 합쳐서 tmp에 리스트로 저장한다.
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)))
]
tmp

  • 컬럼명 변경
crime_station.columns = tmp



📌데이터 저장

# 데이터 저장
crime_station.to_csv("../data/02. crime_in_Seoul_raw.csv", sep=",", encoding="utf-8")
  • 저장 확인
pd.read_csv("../data/02. crime_in_Seoul_raw.csv")



📌구별 데이터로 정리

  • 데이터 가져오기('구분'을 인덱스 컬럼으로 설정)
crime_anal_station = pd.read_csv(
    "../data/02. crime_in_Seoul_raw.csv", index_col=0, encoding="utf-8") # index_col '구분'을 인덱스 컬럼으로 설정
crime_anal_station.head()


📍crime_anal_gu 피벗 테이블 생성

  • lat, lng은 덧셈을 해도 의미가 없기 때문에 제거
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)

crime_anal_gu.head()



📍검거율 생성

  • 하나의 컬럼을 다른 컬럼으로 나누기
crime_anal_gu["강도검거"] / crime_anal_gu["강도발생"]


  • 다수의 컬럼을 다른 컬럼으로 나누기
crime_anal_gu[["강도검거", "살인검거"]].div(crime_anal_gu["강도발생"], axis=0).head(3)


  • 다수의 컬럼을 다수의 컬럼으로 각각 나누기
num = ["강간검거", "강도검거", "살인검거", "절도검거", "폭력검거"]
den = ["강간발생", "강도발생", "살인발생", "절도발생", "폭력발생"]

crime_anal_gu[num].div(crime_anal_gu[den].values).head()



📍검거율 생성

target = ["강간검거율", "강도검거율", "살인검거율", "절도검거율", "폭력검거율"]

num = ["강간검거", "강도검거", "살인검거", "절도검거", "폭력검거"]
den = ["강간발생", "강도발생", "살인발생", "절도발생", "폭력발생"]

crime_anal_gu[target] = crime_anal_gu[num].div(crime_anal_gu[den].values) * 100
crime_anal_gu.head()



📍필요 없는 컬럼 제거

del crime_anal_gu["강간검거"]
del crime_anal_gu["강도검거"]

crime_anal_gu.drop(["살인검거", "절도검거", "폭력검거"], axis=1, inplace=True)

crime_anal_gu.head()



📍100보다 큰 숫자 찾아서 바꾸기

  • 바꾸기 전

  • 바꾼 후
crime_anal_gu[crime_anal_gu[target] > 100] = 100
crime_anal_gu.head()



📍rename()

컬럼 이름 변경

데이터.rename(columns={"변경전이름1": "변경후이름2", "변경전이름1": "변경후이름2"}, inplace=True)

# 컬럼 이름 변경

crime_anal_gu.rename(columns={"강간발생": "강간", "강도발생": "강도", "살인발생": "살인", "절도발생": "절도", "폭력발생": "폭력"},
                    inplace=True)
crime_anal_gu.head()



📌범죄 데이터 정렬을 위한 데이터 정리



📍정규화

최고값은 1, 최소값은 0

crime_anal_gu["강도"] / crime_anal_gu["강도"].max()

가장 큰 값(강남구)은 1로 다른 수는 0~1 사이의 값으로 되어있는 것을 볼 수 있다.


  • 살인, 강도, 강간, 절도, 폭력 컬럼 정규화
col = ["살인", "강도", "강간", "절도", "폭력"]
crime_anal_norm = crime_anal_gu[col] / crime_anal_gu[col].max()
crime_anal_norm.head()


  • 살인검거율, 강도검거율, 강간검거율, 절도검거율, 폭력검거율 컬럼 정규화
# 검거율 추가
col2 = ["강간검거율", "강도검거율", "살인검거율", "절도검거율", "폭력검거율"]
crime_anal_norm[col2] = crime_anal_gu[col2]
crime_anal_norm.head()



  • 구별 CCTV 자료에서 인구수와 CCTV 수 추가
result_CCTV = pd.read_csv("../data/01. CCTV_result.csv", index_col="구별", encoding="utf-8")
crime_anal_norm[["인구수", "CCTV"]] = result_CCTV[["인구수", "소계"]]
crime_anal_norm.head()


  • 정규화된 범죄발생 건수 전체의 평균을 구해서 범죄 대표값으로 사용
col = ["살인", "강도", "강간", "절도", "폭력"]
crime_anal_norm["범죄"] = np.mean(crime_anal_norm[col], axis=1) # mean: 넘파이에서 행렬의 평균을 구하는 함수
crime_anal_norm.head()



💡 np.mean()

  • 강남구 범죄 평균값
np.mean(np.array([0.357143, 1.000000, 1.000000, 0.977118, 0.733773]))


  • 강남구, 강동구 범죄 평균값
np.mean(np.array(
    [[0.357143, 1.000000, 1.000000, 0.977118, 0.733773],
    [0.285714, 0.358974, 0.310078, 0.477799, 0.463880]]
))

하나의 평균값으로 나온다.
만약 각 각 행마다의 평균값을 구하고 싶다면 axis=1을 추가로 작성해줘야한다.


numpy에서는 axis=1 행, axis=0 열을 기준, pandas에서는 axis=0 행, axis=1 열을 기준 으로 계산을 한다.
⚠️ axis는 패키지마다 차이점이 있을 수 있으니 유의하도록 해야한다!!⚠️

  • axis=1 (지금 현재 구해야하는 방법!)
np.mean(np.array(
    [[0.357143, 1.000000, 1.000000, 0.977118, 0.733773],
    [0.285714, 0.358974, 0.310078, 0.477799, 0.463880]]
), axis=1) # axis=1 행, axis=0 열  

만약 axis=0 으로 계산해보면 세로 기준으로 평균을 내서 5가지의 값이 나오게 된다.

np.mean(np.array(
    [[0.357143, 1.000000, 1.000000, 0.977118, 0.733773],
    [0.285714, 0.358974, 0.310078, 0.477799, 0.463880]]
), axis=0) # axis=1 행, axis=0 열 



  • 검거율의 평균을 구해서 검거 컬럼의 대표값으로 사용
col = ["강간검거율", "강도검거율", "살인검거율", "절도검거율", "폭력검거율"]
crime_anal_norm["검거"] = np.mean(crime_anal_norm[col], axis=1) # axis=1 행을 따라서 연산하는 옵션
crime_anal_norm.head()




"이 글은 제로베이스 데이터 취업 스쿨 강의 자료 일부를 발췌한 내용이 포함되어 있습니다."

0개의 댓글