▷ 오늘 학습 계획: 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 구성됨 # 경찰서 이름을 통해 구 이름 알아내야 함
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)