제로베이스 데이터 파트타임 스쿨 학습 일지 [25.05.11]

[강의 요약]

[Part 04. EDA/웹 크롤링/파이썬 프로그래밍_ Ch 03. 서울시 범죄 현황 데이터 분석] 강의 수강

클립 8~23까지 강의 수강하였음

23_실습 - 범죄현황 데이터 시각화까지

🐢 100일 챌린지 🔥 : [▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰                                       ] 56/100일 (56%)

 

 

 

 

[클립 8~23까지 정리]

▶ 1. Google Maps API로 경찰서 위치 파악

경찰서 이름만 있는 상태에서 해당 경찰서가 어느 구에 있는지, 위도/경도는 무엇인지 알아내기 위해

Google Maps API를 사용했다.

import googlemaps
from tqdm import tqdm  # 반복문 진행 상태 표시

gmaps_key = "(발급받은 API 키)"
gmaps = googlemaps.Client(key=gmaps_key)

 

위치 정보 요청 예시는 다음과 같다.

station_name = '서울강남경찰서'
station_info = gmaps.geocode(station_name, language='ko')
lat = station_info[0]['geometry']['location']['lat']
lng = station_info[0]['geometry']['location']['lng']
  • googlemaps.Client(key='키') : 클라이언트 객체 생성
  • geocode('주소명') : 주소나 장소명으로 위치(좌표)를 요청
  • 반환값은 리스트이며, geometry.location.lat, lng을 통해 위도/경도 추출한다.

 

구 이름 추출은 다음과 같다.

gu_name = station_info[0]['formatted_address'].split()[2]
  • formatted_address : 전체 주소 문자열
  • split()[2] : 예를 들어 "서울특별시 강남구 역삼동"이라면, 세 번째 단어 강남구 추출

 

 

▶ 2. 모든 경찰서 주소 처리 (반복문 사용)

for idx, row in crime_station.iterrows():
    station_name = '서울' + str(idx) + '경찰서'
    tmp = gmaps.geocode(station_name, language='ko')
    lat = tmp[0].get("geometry")['location']['lat']
    lng = tmp[0].get("geometry")['location']['lng']
    gu = tmp[0].get("formatted_address").split()[2]
    crime_station.loc[idx, 'lat'] = lat
    crime_station.loc[idx, 'lng'] = lng
    crime_station.loc[idx, '구별'] = gu
  • iterrows() : DataFrame의 각 행을 반복해서 (index, row) 튜플로 반환
  • DataFrame.loc[행, 열] = 값 : 특정 위치에 값을 직접 넣는 방법

 

 

▶ 3. 구별 데이터 정리 (pivot_table 재사용)

crime_gu = crime_station.pivot_table(index='구별', aggfunc='sum')
del crime_gu['lat']
del crime_gu['lng']
  • pivot_table() : 행 기준으로 요약 집계
    • index='구별': 구별로 묶고
    • aggfunc='sum': 같은 구 이름끼리 합계 계산
  • del 컬럼명 : 특정 열 삭제

 

 

▶ 4. 검거율 계산 및 정제

crime_gu['강간검거율'] = (crime_gu['강간검거'] / crime_gu['강간']) * 100
  • 검거율 = 검거건수 / 발생건수 × 100

 

crime_gu[crime_gu > 100] = 100
  • 검거율이 100%를 넘는 경우도 있는데, 통계적으로 부자연스러우므로 100으로 잘라냄

 

 

▶ 5. MinMaxScaler로 정규화

from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
crime_gu_norm = pd.DataFrame(
    scaler.fit_transform(crime_gu),
    columns=crime_gu.columns,
    index=crime_gu.index
)
  • MinMaxScaler() : 값을 0~1 범위로 압축 (최소 0, 최대 1)
  • fit_transform(data) : 정규화 수행
  • 결과는 numpy 배열이므로 다시 DataFrame()으로 감싸준다.

 

 

▶ 6. seaborn 스타일과 히트맵 시각화

import seaborn as sns
import matplotlib.pyplot as plt

sns.set(style='whitegrid')
sns.heatmap(
    crime_gu[['강도검거율', '살인검거율', '폭력검거율']],
    annot=True,
    fmt='.1f',
    cmap='Blues'
)
plt.title("범죄 유형별 검거율")
plt.show()
  • sns.set(style='whitegrid') : 그래프 배경 스타일 설정
  • heatmap(data) : 행/열 형태의 숫자 데이터를 색으로 시각화
  • annot=True : 셀 안에 숫자 출력
  • fmt='.1f' : 소수점 1자리까지 표시
  • cmap='Blues' : 파란색 계열 색상 맵 사용

 

 

 

[추가 정리]

▶ MinMaxScaler()

사용한 이유가 뭘까?

  • 어떤 구는 인구가 많아서 범죄도 많고, 어떤 구는 작아서 적다.
  • 이런 “크기 차이”를 공평하게 비교하려면, 값들을 같은 기준(0~1 사이)으로 바꿔야 한다.
  • 그게 바로 정규화. MinMaxScaler는 최솟값을 0, 최댓값을 1로 맞춰준다.

 

 

사용예시는 다음과 같다.

from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()

scaled = scaler.fit_transform([[10], [20], [30]])
  • 원래 값이 10, 20, 30이라면
  • 정규화하면 0.0, 0.5, 1.0 으로 바뀐다.
  • 최솟값 → 0, 최댓값 → 1, 그 사이는 비율에 맞춰서 바꾼다.

 

 

pandas DataFrame에 적용하려면 어떻게 해야 할까?

df_scaled = pd.DataFrame(scaler.fit_transform(df), columns=df.columns, index=df.index)

 

 

seaborn.heatmap()

사용한 이유가 뭘까?

  • heatmap()은 표 형태의 수치를 색깔로 표현해 주는 시각화 도구
  • 즉, 숫자가 클수록 진한 색. 작을수록 연한 색. 이런 식으로 쉽게 눈에 들어오게 도와준다.

 

 

기본 사용법은 다음과 같다.

import seaborn as sns
import matplotlib.pyplot as plt

data = [[50, 70], [90, 30]]
sns.heatmap(data, annot=True, cmap='Blues')
plt.show()
  • data : 시각화할 2차원 데이터 (리스트 or DataFrame)
  • annot=True : 셀 안에 숫자도 함께 표시
  • cmap='Blues' : 파란색 계열 색상 사용
  • fmt='.1f' : 소수점 1자리까지 표시

 

pandas와 함께 사용한다면?

sns.heatmap(df[['강도검거율', '폭력검거율']], annot=True, fmt='.1f', cmap='Reds')

 

 

 

[나의 생각 정리]

백지에서 작성해라고 한다면... 힘들 것 같다.

많은 연습이 필요할 듯하다.

 

 

[적용점]

데이터 분석(EDA)에서 사용

 

 

“이 글은 제로베이스 데이터 스쿨 주 3일반 강의 자료 일부를 발췌하여 작성되었습니다.”