[강의 요약]
[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일반 강의 자료 일부를 발췌하여 작성되었습니다.”
'제로베이스 데이터 취업 파트타임 > 100일 챌린지_일일 학습 일지' 카테고리의 다른 글
제로베이스 데이터 파트타임 스쿨 학습 일지 [25.05.13] (0) | 2025.05.13 |
---|---|
제로베이스 데이터 파트타임 스쿨 학습 일지 [25.05.12] (2) | 2025.05.12 |
제로베이스 데이터 파트타임 스쿨 학습 일지 [25.05.10] (0) | 2025.05.10 |
제로베이스 데이터 파트타임 스쿨 학습 일지 [25.05.09] (0) | 2025.05.09 |
제로베이스 데이터 파트타임 스쿨 학습 일지 [25.05.08] (1) | 2025.05.08 |