군장병 AI 트랙(기본) PART 2 필기

배코딩·2022년 10월 4일
0

군장병 AI 교육

목록 보기
2/8

PART 2

푸리에 변환 쉬운 설명


웹 방문자 관련 통계를 내주는 구글 애널리틱스

데이터 분석 현업에서도 많이 쓰이는 추세인, 데이터 대시보드 쉽게 만들어주는 elastic stack (유튜브 "elastic 사용자 그룹" 참고)

데이터 시각화해주는 Zeppelin (주피터 노트북에서 보여주는 것과 비슷하지만 다른 강점 하나는 바로 셀 단위로 여러 언어를 손쉽게 사용할 수 있다는 점임. 주피터 노트북에서도 커널에서 언어를 바꿀 수 있지만 불편하고 귀찮), 회사에서 서버에 올려놓고 쓸 때 유용. 개인적으로는 그렇게 유용하진 않음


크롤링 도구 scrapestorm (한계점 있음)


공공데이터 사이트

공공 데이터 포털

국가 통계 포털

MDIS(MicroData Integrated Service)

awesome public datasets

google AI datasets

google dataset search

kaggle competition datasets

데이터온 (대한민국 모든 데이터를 한 곳에서)

AI 오픈이노베이션 허브 (한국어 음성, 대화, 안면 등)

금융결제원 오픈 API 통합 포털 (오픈뱅킹, 금융인증)

서울시 우리마을가게 상권분석 서비스

서울 열린 데이터 광장

2020 문화체육관광 빅데이터플랫폼(국립중앙도서관, 국민체육진흥공단 무료체력검정 데이터 등)


DataFrame 객체의 첫 번째 열은 인덱스 열임.

다만 일반적인 인덱스의 의미와는 상충함.

기본값이 연속적인 숫자일 뿐, 특정 열을 인덱스 열로 삼을 수도 있음

행의 이름 열이라고 생각


pd 대표적인 함수 4개

head()
tail()
describe()
info()

null, NoneType, None, N/A(not available), NaN -> 결측치의 의미로 쓰이는 것들

결측치 보강하는 법
1. 랜덤하게 채워넣기
2. 주변 행 값으로 채워넣기
3. 열의 대푯값 채워넣기
4. 다른 열을 기준으로 행을 그룹지은 후, 그 그룹의 대표값으로 채워넣기
5. 나머지 열들로 머신러닝 예측모델을 만든 후 예측해 채워넣기
6. 특정 기준 비율 이상으로 빠져있을 때 해당 열 삭제


Series 자료형은 약간 벡터, 또는 키 값이 있는 리스트라고 생각하면 편함.

A 행을 조회할 때 df.loc[A] (리턴 타입 Series, 두 번째 대괄호 인덱싱으로 열까지 특정 가능)

이걸 DataFrame으로 꺼내고 싶거나 여러 행을 조회하고 싶다면 대괄호 한 번더 감싸서 df.loc[[A]]

df.iloc[3:6, 0:3] -> 3행부터 5행까지, 그 중에서도 0열부터 2열까지

A 열을 조회할 때는 df[A]임. 여러 열 조회할 땐 리스트 형태로 조회

df[A].str -> key: 행, value: A열 값 문자열 형태 인 Series

df[A].str.lower() -> value를 모두 소문자로 바꿔 Series로 나타냄 (문자열 메소드를 그대로 사용 가능)

df[ df[A].str.contains("ar") ] -> A열 중 "ar"을 포함하는 것들만을, "행"에 대해 필터링함



4강

기존 dataframe에서 일부 열만 떼내어 새로운 dataframe 만들기

df_new = df[['열이름1', '열이름2', '열이름3']]


apply 함수 : 열 Series의 값 조작

df_new['new_hair'] = df_new['hair'].apply(lambda x: x+1)


index열을 지정하여 새로운 df 만들기(like pivot table)

pivot_df = pd.pivot_table(df_new, index='type', aggfunc=np.average)

집계 함수 기본 값은 mean


열 삭제하기

del pivot_df['new_hair']


행 삭제하기

pivot_df.drop([행 이름])

열도 삭제 가능함.

pivot_df.drop([열 이름], axis=1)

axis가 0일 땐 열 방향, 1일 땐 행 방향 (자세한 설명은 아래 데이터프레임 병합 설명에서 참고)


열 이름 바꾸기

pivot_df.rename(columns={'기존열이름':'바꿀열이름', '기존열이름':'바꿀열이름'}, inplace=True)

원래 rename 메소드는 원본을 변경하지 않고 변경된 df를 리턴만 하는데, inplace 매개변수를 True로 주면 원본을 변경해주는 대신 리턴을 하지는 않음


정렬

pivot_df.sort_index(by='행이름', inplace=True)
pivot_df.sort_values(by='열이름', ascending=False, inplace=True)

TMI: 리스트 정렬하던대로 여기에 reverse를 쳐버리면 unexpected argument 오류가 남. 이건 되게 중요한 오류인데 보통 라이브러리의 업뎃에 따라 매개변수의 변화가 생겼는데 이를 인지못하고 기존의 사용법대로 매개변수를 넣었다가 저 오류가 뜨는 경우가 자주 있음. 어떤 블로그를 보고 라이브러리를 배우다가 분명 똑같이 쳤는데 argument 오류가 난다면 라이브러리의 버전 차이를 의심해보자.


얕은 복사와 깊은 복사

pivot_df_2 = pivot_df
pivot_df_3 = pivot_df.copy()

df2같은 경우에는 pivot_df가 얕은 복사가 되어있다. 원본 df의 참조 값을 그대로 가져왔기 때문에, 완전히 독립되어 있지않고 둘 중 하나를 변경하면 나머지 하나도 따라서 변경이 된다. 애초에 같은 df를 참조하고 있기 때문이다.

df3에는 깊은 복사가 되어있다. 내용만 같고 원본 df와는 아예 별개의 df를 갖는다. 즉 원본 df와 똑같은 df를 메모리 상에 하나 더 복사해놓고, 이 것의 참조값을 df3에 저장하는 것이다.

df3을 변경하든 df를 변경하든, 서로에게는 영향을 전혀 주지 않고 독립적으로 존재한다.

copy 함수에는 deep=True가 기본 값으로 지정되어 있다.


6강

특정 열 인덱스 열로 지정하기

df.set_index('열 이름')


인덱스 열 일반 열로 되돌리기

df.reset_index()

아예 삭제를 하려면 df_reset_index(drop=True)


  • 열과 열 끼리의 사칙연산 가능

  • dataframe의 len 함수 리턴값은 행의 개수임

  • 주피터 노트북에서 ctrl 누른 채로 멀티 커서 지정 가능. 키워드 여러 개 동시에 칠 때 유용

조건에 부합하는 특정 값들만 조작하기

100이 넘는 값들을 100으로 맞춰주기

방법 1) 어려움. 굳이 이 방법말고 방법 2로 하자. 방법 1은 그냥 몇 가지 배울 점 학습하는 용도

gu_df_temp = gu_df.copy()

columns = ['강간검거율', '강도검거율', '살인검거율', '절도검거율', '폭력검거율']
gu_df_rate = gu_df_temp[columns]

for row_idx, row_series in gu_df_rate.iterrows():
    for col in columns:
        if row_series[col] > 100:
            gu_df_temp.at[row_idx, col] = 100

gu_df_temp.head(10)

dataframe에서 값 조회하기

df['열이름']['행이름']
df.loc['행이름']['열이름']
df.at['행이름', '열이름']

  • loc보단 at이 더 빠르므로 at을 애용하자

7강

  • dataframe에 논리 연산(부등호 등)을 하면 모든 값을 논리 연산에 따른 boolean 값으로 바꿈

마스킹 기법

조건에 부합하는 특정 값들을 마스킹 기법으로 바꿔보자

df[ df[['열이름1', '열이름2', '열이름3'] ] > 100] = 100

열 Series를 인덱싱하는 대괄호안에 boolean 값으로 바뀐 dataframe을 넣어주면 마스킹됨


필터링

마스킹과 다른 점은, 기준이 되는 값이 dataframe이 아닌 series이고, 결과로 나오는게 필터링 된 dataframe임. 값을 바꾸려는게 아니라 조건을 충족하는 행들을 추려낼 때 쓰는게 필터링

조건을 여러 개 줄 수도 있는데, 이 때는 1) 각 조건을 소괄호로 묶어줘야하고, 2) and가 아닌 비트 논리 연산자 &를 써야됨. 오직 필터링에서만 and가 안 먹힌다고 함

ex) gu_df[ (gu_df['살인(발생)'] > 7) & (gu_df['폭력(발생)'] > 2000) ]

or도 마찬가지로 비트 논리 연산자 |로 쓰자

not의 비트 논리 연산자는 ~


  • dataframe을 조건에 맞는 boolean 값으로 바꾸고 싶을 때, 값이 문자열인 경우에는 str 객체 활용 (df.str.contains("지역명"))

결측치 채우기

gu_df['열이름'] = gu_df['열이름'].fillna(채울 값)

해당 열의 평균값으로 결측치를 땜빵해주고 싶다면, 괄호안에 gu_df['열이름'].mean()


데이터 프레임 합치기

데이터프레임 A, B를 합치는 3가지 방법

  1. A.join(B)
  • A, B 데이터프레임의 index column이 동일해야만 한다.
  • B의 index column 중 A와 겹치는 것들만 넣어줌
  • A의 index column 순서에 맞춰서 B의 열들을 끼워 맞춰 넣는다.
  1. pd.merge(A, B, left_on='구별', right_on='구이름', how='inner')
  • A와 B 각각에서 열 하나를 잡고, 두 열에 대해 집합 연산(how 매개변수)을 한 새로운
    열을 index column으로 잡고 dataframe을 합침
  • A 기준 열의 순서를 유지하면서 합침
  • 두 dataframe의 index column이 같다면 pd.merge(A, B, left_index=True, right_index=True)로 해도 됨. 근데 이럴 땐 그냥 join으로 하는게 더 편함
  1. pd.concat([A, B], axis="0")
  • 인덱스 열의 순서가 서로 맞지 않아도 그냥 그대로 옆에 때려붙임
  • 행방향 or 열방향으로 적용 가능
  • 보통 열 보다는 행을 이어 붙일 때 씀

참고로 axis가 0이면 열 방향, 1이면 행 방향임. 여기서 열 방향이라는 것은 dataframe에서 열과 열 끼리 연산한다는 것이고, 행 방향은 행 끼리 연산한다는 뜻이다.

예를 들어 어떤 열 A로 df에 대해 div 함수를 쓰면, axis=0일 때 df의 모든 열을 A열로 나눔. 열과 열을 나누는 형태이므로 열방향임.

요약하면

1) axis=0일 경우 열 방향으로 모든 행을 따라가며 연산을 진행한다(각 열 내부에 속한 모든 행에 대해 순서대로 연산을 적용), 모든 행을 따라가며 연산한다는 점에서 index 방향 연산이라고도 함

2) axis=1일 경우 행 방향으로 모든 열을 따라가며 연산을 진행(각 행 내부에 속한 모든 열에 대해 순서대로 연산을 적용), 모든 열을 따라가며 연산을 한다는 점에서 columns 방향 연산이라고도 함. 헷갈리니까 걍 행, 열 방향이라고만 외워두자

concat에서 axis가 0이면 열 방향, 즉 위 아래로 이어붙이는 형태임 axis=1이면 왼쪽 오른쪽 방향으로 두 dataframe을 붙임.


read_csv 등으로 파일을 불러올 때 매개변수 index_col로 인덱스 열을 지정하면서 불러올 수 있음

ex) df = pd.read_csv('asd.csv', encoding='utf-8', index_col="열이름')


8강 : 데이터 시각화 (1)


한글 데이터 시각화를 위한 준비

  • 주피터 노트북 코드 결과 창에 그래프를 띄우고싶다면

%matplotlib inline


  • matplotlib에서 한글이 깨지는 문제 해결
from matplotlib import font_manager, rc

font_name = font_manager.FontProperties(fname="폰트 파일 경로").get_name()

rc('font', family=font_name)

한글 깨질 때마다 복붙해서 실행해주면 됨.

참고로 하모니카os 환경에서 goorm ide의 주피터 노트북 환경에서 할 때는

! fc-list :lang=ko | grep ttf

이걸 실행해서 나오는 폰트 파일 경로들 중에 하나를 골라 쓰면 된다.


  • sns heatmap으로 차트를 그릴 때, feature의 scale이 엉망이면 제대로 표현할 수가 없다. 예를 들어 어떤 feature는 대부분 천의 자리인데 어떤 feature는 일의 자리라면, 전체 스케일이 천의 자리까지 설정되어서 일의 자리가 대부분인 feature는 같은 색깔로 도배되는 현상이 생겨버림. 이는 머신러닝 또는 딥러닝 때도 문제가 될 수 있어서 중요한 문제임

  • x_data를 표현하는 이름들

column, feature, attribute, dimension(열이 5개면 dataframe을 5차원 데이터라고 표현)


feature scale 정상화하는 정규화(normalization) 기법 2가지

  • min-max algorithm

각 feature마다 최솟값을 0, 최대값을 1로 설정하여 모든 값을 0 이상 1 이하의 값으로 맞추는 알고리즘 적용

newX = oldXmin(feature)max(feature)min(feature)\frac{oldX - min(feature)}{max(feature) - min(feature)}


  • standardization

각 feature의 평균을 0, 표준편차를 1로 설정하여 모든 값이 -1과 1의 언저리 값으로 설정되도록 하는 기법

newX = oldXmean(feature)std(feature)\frac{oldX - mean(feature)}{std(feature)}


이 두 가지 방법을 구현해주는 함수가 있으므로 수식을 외울 필요는 없음. 대체로 직관적인 min-max를 쓰지만 대체로 standardization 기법이 성능이 좋게 나옴


  • dataframe의 통계 메소드는 보통 열 단위로 함수를 적용하여 Series로 리턴하는 듯(열 이름 key, 통계값 value)

  • df[['열이름1', '열이름2', '열이름3']] / weight_col

weight_col은 Series임 (key가 열이름1, 2, 3이고 value가 각 열의 최대값이라고 하자)

dataframe을 숫자로 나누면 모든 값을 숫자로 나눈 new_df를 리턴하고,

dataframe을 Series로 나누면 Series의 키 값과 일치하는 열을 찾아 그 열을 싹 다 value로 나눠 줌. 이 때 일치하는 열 name이 없으면 리턴되는 df에는 그 series key 값이 새로운 열로 추가되고 값은 모두 NaN이 됨


  • 이런 원리들로 인해, 데이터 프레임 A에 대해 A / A.max(), A * A.mean() 같은 연산들이 가능함.

  • df.quantile(x)

4분위수 함수임. 전체 데이터에서 x% 지점의 데이터 값을 구함

x가 100이라면 열에서 최대값을 구할테고, 0이면 최소값, 0.5라면 median(중위값)이 나올거임


  • 이런 min, max, quantile, mean 등의 통계값들을 싹 다 연산한 결과를 표로 정리해 보여주는게 df.describe()

  • seaborn 모듈로 시각화할 때 조정하고 싶은 속성들이 있다면 그걸 다 외우는게 아니라 구글링해서 검색하면 됨. 가령 heatmap에서 색깔을 바꾸고 싶다면 seaborn heatmap color change로 검색하면 됨. colormap 속성은 기억해두자

sns heatmap 시각화 좀 더 편하게 수정


# 전체 figure 사이즈 조정
plt.figure(figsize = (10, 10))

# annot : 셀 내 수치 입력 여부
# fmt : 셀 내 수치의 format (f == float)
# linewidths : 셀 간 거리(여백 만들기)
# cmap : matplotlib colormap @ https://goo.gl/YWpBES
sns.heatmap(crime_count_norm.sort_values(by='살인', ascending=False), annot=True, fmt='f', linewidths=.5, cmap='Reds')

plt.title('범죄 발생(살인발생으로 정렬) - 각 항목별 최대값으로 나눠 정규화')
plt.show()

plt.figure 함수는 도화지를 여는 함수임

plt는 도화지라고 생각. 바닥에 도화지를 설정해주고(title, size 등등)

show 함수를 쓰면 그 모든 속성을 한 장의 도화지 위에 구현한 후 그래프를 보여줌

여기서 그래프는 sns임

사실 sns만 써도 그래프를 띄울 수 있고, plt.figure는 생략해도 되는데 그래프 사이즈를 조정하고 싶다면 figure 함수의 인자로 사이즈를 넘겨 조정해주는 거임


여기서 의문점이 들 수 있는게, sns는 plt도 아닌데 plt로 설정한 도화지 위에 잘 얹어져서 나옴. 이럴 수 있는 이유는 sns가 matplotlib 기반이라서, heatmap 함수를 까보면 안에 대부분 plt 함수로 구현이 되어있기 때문임.

sns는 어떤 기능을 구현하기 위해 plt로 작성해야하는 코드들을 하나의 함수로 묶어 간편하게 쓸 수 있도록 만든 파생 모듈이라고 생각하면 될 듯


  • 범죄 데이터에서 여러 범죄 항목의 구별 인구수에 따른 발생 비율을 나타낸 데이터프레임이 있을 때, 구별로 전체 범죄 발생 비율을 구할 때, 단순히 범죄별로 싹 다 더해서 평균내면 문제가 있을 수 있음, 예를 들어 살인과 절도의 범죄의 경중이 다른데, 저런 식으로 평균을 내면 살인과 절도의 경중이 똑같게 되버리기 때문임. 그래서 가중 평균을 적용해서, 살인 열에는 1.3을 곱하고 절도 열에는 0.5를 곱한 후 그 값을 분자로 삼아 평균을 내면 되는거임.

파이썬 여러 가지 데이터 시각화 라이브러리


[데이터 종류와 시각화 목적에 따라 어떤 차트를 써야할 지에 대해 참고하기 좋은 사이트] (유의점 및 소스코드 포함)](https://www.data-to-viz.com/)


Data Viz Project (각종 차트별 정의/용도/유사차트/데이터형식)


  • Categoric 열 : 예를 들어 학력 열의 값이 1~3이고 1이 고졸, 2가 대졸, 3이 대학원일 때, 이런 식으로 값이 그 자체로 의미를 갖기 보다는 그 너머에 범주로서의 의미가 존재할 때 Data to Viz 사이트에서 Categoric 탭의 추천 차트를 보면 됨

  • Numeric 열 : 예를 들어 주식 종목 열의 값이 가격 값이라면, 그 값 자체로 의미를 가지므로 Data to Viz 사이트의 Numeric 탭의 추천 차트를 보고 쓰면 됨

값에 산술 연산을 적용했을 때 그 의미가 자연스러운지를 생각해보면 편함


data to viz 사이트의 좋은 점은 차트를 사용할 때의 주의점도 적혀있어서 좋음


10강 (지도 시각화)

지도 시각화 : folium 라이브러리 활용
지도 데이터 : GeoJSON 활용. 지역을 그려내기 위한 지역의 각 꼭짓점의 위도와 경도를 제공하는 국제 규약

깃헙에서 받을 때 참고
province : 시/도 단위
municipality : 구 단위
submunicipality : 동 단위

일단은 용량 적고 속도 빠른 topo-simple로 실습 ㄱㄱ


  • json 파일 열기

import json

geo_path = '파일 경로'
geo_str = json.load(open(get_path, encoding='utf-8'))

이 때 open 함수의 mode 매개변수 기본값은 r임


JSON은 데이터 교환 표준 포맷임. (JSON 이전에 쓰던 XML, 현재도 쓰이고 있는 YAML도 있음)

javascript object notation의 약자인데 직역하면 자바스크립트 객체 표기법임.

이 것이 파이썬에서는 동일한 자료구조로 dict가 있음.

이처럼 다른 언어로 된 서버 컴퓨터 간 데이터 교환에 json이 활용됨. 저 객체 또는 딕셔너리 형태의 자료구조는 어느 언어에나 다 있음.


geoJSON 안에 보면 구 단위로 features들이 있는데, 이걸 하나하나 꺼내 쓸 필요없고 그냥 geoJSON 자체를 불러와서 저장한 변수 geo_str를 folium 모듈에 넣어주기만 해서 쓰면 되는거임. folium 라이브러리는 이미 geoJSON을 쓸 준비가 다 되어있음


pyprnt : JSON 구조를 쉽게 파악할 수 있게 해주는 도구

pip install pyprnt

from pyprnt import prnt

prnt(딕셔너리)


  • folium으로 지도 그리기

map_folium = folium.Map(location=[위도값, 경도값], zoom_start=숫자, tiles='Stamen Toner')


  • folium으로 그린 뒷배경 지도 위에 씌울 geo_data 기반 데이터 시각화 지도
    choropleth는 콜로플레스라고 부르면 됨
# 살인사건 발생건수 시각화
# Choropleth map : 정의 @ https://goo.gl/yrTRHU
# Another available library for Choropleth map : Altair @ https://altair-viz.github.io/gallery/choropleth.html
map.choropleth(geo_data = geo_str, # 서울시 행정구역별 polygon drawing
               data = gu_df['살인'], # 시각화의 대상이 될 데이터
               columns = [gu_df.index, gu_df['살인']], # 1) df의 index 칼럼을 가져와 인식하고
               fill_color = 'PuRd', #PuRd, YlGnBu <- color brewer (http://colorbrewer2.org/) : ‘BuGn’, ‘BuPu’, ‘GnBu’, ‘OrRd’, ‘PuBu’, ‘PuBuGn’, ‘PuRd’, ‘RdPu’, ‘YlGn’, ‘YlGnBu’, ‘YlOrBr’, and ‘YlOrRd’
               key_on = 'feature.id') # GeoJSON 규약을 따름, json 파일(지도 데이터)의 "feature" type의 "id" 에 매칭된다

# key_on: Variable in the GeoJSON file to bind the data to. 
# Must always start with 'feature' and be in JavaScript objection notation. 
# Ex: 'feature.id' or 'feature.properties.statename'.

외워서 쓰는게 아님!


11강 (GCP 활용 지도 시각화)

API 활용 : 구글 클라우드 플랫폼의 Geocoding API

검거율 그대로를 기준으로 지도를 그리면, 해당 데이터에서 경찰서 별 검거율의 차이가 적으므로 원의 지름도 작아져 잘 표현이 안됨. 그래서 경찰서별 검거율 점수를 계산해 주자.

검거율 점수를 리레인지할텐데, min-max 알고리즘을 약간 변형함.

여기서는 min이 1, max가 100이 되게끔 하고싶음.

따라서 min-max로 0~1 범위로 만드는 식을 적고, 거기에 (100-1)=99를 곱해주면 레인지가 0~99로 바뀔거임. 여기서 1을 더해주면 1~100의 레인지를 가짐. (굳이 최소를 1로 맞추는 이유는, 0인 데이터는 시각화가 아예 안되는 문제가 생기기 때문)

이걸 구현하는 함수가 다 따로 있으므로 원리만 이해하고 구현 방법을 외우지는 말자.


구글맵스 API 불러오기

import googlemaps
gmaps = googlemaps.Client(key="API 키 여기에 넣기") # -- input your key --

tmpMap = gmaps.geocode('서울강남경찰서', language="ko")
tmpMap

구글맵스 API로 경찰서 별 위도, 경도 구하기

lat = []
lng = []

for name in df['경찰서']:
    # gmaps.reverse_geocode((longitude 값, latitude 값), language="ko") == 경도 & 위도 값으로 주소값 가져오기
    # gmaps.geocode('한글 주소', language="ko") 로 위도/경도, 우편번호까지 알 수 있음
    tmpMap = gmaps.geocode(name) # ex) 서울강남경찰서
    tmpLoc = tmpMap[0].get('geometry') # 배열 형태( [~] )로 들어오기 때문에 [0]으로 호출
    lat.append(tmpLoc['location']['lat']) # dict(tmpLoc)의 데이터는 dict['key값'] 로 value 호출
    lng.append(tmpLoc['location']['lng'])
    
df['lat'] = lat
df['lng'] = lng

df.head()

검거율 점수를 활용하여 경찰서 별로 원 마커를 지도 위에 띄우기

map = folium.Map(location=[37.5502, 126.982], zoom_start=11)

for n in df.index: # range(len(df.index)) 처럼 할 필요 없이 바로 df.index 를 순회하여 record 자체에 접근할 수 있음
    # 경찰서별로 원형 마커를 생성하여 점수를 radius 로 매겨 지도에 표시함
    # folium.Circle() 의 경우는 radius가 자동으로 meter 단위가 됩니다. (아래 CircleMarker에서의 radius는 pixel 단위)
    folium.CircleMarker ([df['lat'][n], df['lng'][n]], 
                         radius=df['점수'][n]*0.5, # circle 의 크기를 결정
                         color='#3186cc', fill=True, fill_color='#3186cc').add_to(map)

map

원 마커와 folium 라이브러리의 choropleth 지도 합쳐서 띄우기

map = folium.Map(location=[37.5502, 126.982], zoom_start=11)

map.choropleth(geo_data = geo_str,
               data = crime_ratio['전체발생비율'],
               columns = [crime_ratio.index, crime_ratio['전체발생비율']],
               fill_color = 'PuRd', #PuRd, YlGnBu
               key_on = 'feature.id')

for n in df.index:
    folium.CircleMarker([df['lat'][n], df['lng'][n]], 
                        radius=df['점수'][n]*0.7, # 0.5 -> 0.7
                        color='#3186cc', fill=True, fill_color='#3186cc').add_to(map)
    
map

dataframe을 다른 형식 파일로 저장

# DF to csv file

df.to_csv('processed_data.csv', encoding='utf-8') # 혹은 euc-kr or cp949

# Saving a folium map as an HTML file

map.save('folium_map.html')

12강 (상세 버전 GeoJSON 활용)


JSON 파일 불러오기

geo_path = 'skorea-2018-municipalities-geo.json'
geo_str = json.load(open(geo_path, encoding='utf-8'))

상세 GeoJSON(구) 내의 모든 구에 대해 서울 내의 구만 걸러내기

in_seoul = [] # 서울 내 지역만 모을 리스트

for feature in geo_str['features']:
    if feature['properties']['code'].startswith('11'): # 서울 내 지역의 경우 code가 11로 시작 (11010~11250)
        in_seoul.append(feature)
        
del geo_str['features']
geo_str['features'] = in_seoul

feature의 properties의 code value를 보면 서울 내의 구들은 모두 11로 시작함. 이 걸 활용하여 걸러내기


지도 만들기

map = folium.Map(location=[37.5502, 126.982], zoom_start=11)

map.choropleth(geo_data = geo_str,
               data = crime_ratio['전체발생비율'],
               columns = [crime_ratio.index, crime_ratio['전체발생비율']],
               fill_color = 'PuRd', 
               key_on = 'feature.properties.name')

for n in df.index:
    folium.CircleMarker([df['lat'][n], df['lng'][n]], 
                        radius=df['점수'][n]*0.7, 
                        color='#3186cc', fill=True, fill_color='#3186cc').add_to(map)
map

13강 (Additional tools for Python (JupyterLab)


주피터 노트북 tools

1) Visual Python

특정 기능 구현 코드를 버튼 클릭 하나로 대신 써줌


2) PandasGUI

dataframe을 GUI로 잘 정리해서 보여줌. 엑셀에 있는 기능들 비슷한 거 많이 있음. 그래프도 쉽게 그릴 수 있음


3) Bamboolib

PandasGUI랑 기능이 비슷함. dataframe을 불러와서 편리한 조작과 그래프 만들기 등이 있음.


4) LUX

자동 데이터시각화 라이브러리. 4가지 도구 중 가장 권장되는 도구임.

마찬가지로 dataframe에 대해 여러 가지 시각화를 편리하게 할 수 있음.


Pandas 학습


1) 110 Pandas Practice problems


2) 10 Python Pandas tricks that make your work more efficient


3) 40 Examples to Master pandas


JupyterLab


아나콘다 재단에서 공식적으로 배포하는 주피터 노트북 대체재임. 주피터 노트북에서 여러 기능이 추가된 버전이라 생각하면 됨.

주피터 노트북에서 아쉽거나 불편했던 부분을 개선 및 기능 추가가 편하긴 하지만, 주피터 노트북과 마찬가지로 브라우저 상에서 작동한다는 점에서, 한계점이 그대로 남아있다는 단점이 있다.

그래서 별도의 데스크탑 어플이 출시되었고 발전되어나가고 있다.

그런데 주피터 노트북 대체재중에서 가장 권장되는 도구는 deepnote임.


14강 (추가학습자료 1 - Numpy & Matplotlib)


  • import numpy as np

array의 생성


  • 1차원 배열

arr1 = np.array([1,2,3])



  • 2차원 배열

arr2 = np.array([[1,2,3],[4,5,6]])


type(arr1) -> numpy.ndarray (nth dimension array)


arr1.dtype -> dtype('int64')


arr2.shape -> (2, 3)


arr2.ndim -> 2


a = np.zeros((2,2)) -> 2x2 영행렬


a = np.ones((2,2)) -> 2x2 모든 원소가 1인 행렬


a = np.eye(3) -> 3x3 항등행렬


a = np.random.random((2,2)) -> 2x2 모든 원소가 0~1 사이의 랜덤한 실수인 행렬


a = np.random.randint(1, 100, size=(5,5)) -> 5x5 모든 원소가 1~100 사이의 랜덤한 정수인 행렬


arr.sort() -> numpy.ndarray 도 리스트처럼 정렬 가능함. 인덱싱도 마찬가지


array operators


arr = np.arange(9) -> array([0,1,2,3,4,5,6,7,8]) (array of range의 축약)


arr = arr.reshape(3,3) -> 3x3 행렬로 다시 모양 변경


np.array에 대해 sum, min, max 등 산술연산 다 되는데, 인수가 없으면 모든 원소를 대상으로 수행하고, 매개변수로 axis를 입력받으면, 그 방향으로 연산해서 결과를 리턴한다.

ex) arr.max() -> 8, arr.max(axis=0) -> array([6,7,8]) (열방향)

median은 np.median으로 사용


diag = np.diag(arr) -> array([0, 4, 8])
diag = np.diag(diag) -> array([[0,0,0], [0,4,0], [0,0,8]])

1차원 배열을 넣으면 대각행렬을 만들어주고, n차원 배열을 넣으면 거기서 주대각 원소를 추출하여 1차원 배열 형태로 리턴


matrix operators


A = np.array([[1,2,3], [4,5,6]])
B = np.array([[1,2,3], [4,5,6]])
C = np.array([[1,2], [3,4], [5,6]])


elementwise operating

  • 행과 열 크기가 같은 행렬에 대해, 매칭되는 원소끼리 사칙연산하는 것

A + B -> array([[2,4,6], [8,10,12]])
A - B -> array([[0,0,0], [0,0,0]])
A * B -> array([[1,4,9], [16,25,36]])
A / B -> array([[1., 1., 1.], [1., 1., 1.]])


행렬 곱

result = np.dot(A, C) -> array([[22, 28], [49, 64]])


Matplotlib


line plots


x = [1, 2, 3, 4, 5]
y = [10, 20, 30, 40, 50]

plt.plot(x, y) -> 좌표를 찍고 선으로 연결해줌

plt.grid() -> 십자선 추가

plt.xlabel('x축') -> x축 label 추가

plt.ylabel('y축')

plt.title('제목')

plt.show()

plt.plot(arr1, arr2, "red")
plt.plot(arr1, arr3, "blue") -> .plot으로 그린 그래프가 figure에 누적됨

plt.subplot(2, 1, 1) -> figure를 2행 1열로 나눴다고 칠 때 첫 번째 칸을 지정


df = pd.DataFrame(np.random.randn(10, 4).cumsum(axis=0), columns = ["A", "B", "C", "D"], index=np.arange(0, 100, 10))

np,random.randn -> 10행 4열의 난수 행렬

cumsum -> 누적합

df.plot() -> df를 그대로 plot에 담아 figure에 그린다.

df["B"].plot() -> series에도 plot 메소드가 있다.


Bar plots


s2 = pd.Series(np.random.rand(16), index=list("abcdefghijklmnop"))

s2.plot(kind="bar") -> bar 형태로 그려줌
s2.plot(kind="barh") -> bar horizontal


df2 = pd.DataFrame(np.random.rand(6, 4), index=["one", "two", "three", "four", "five", "six"], columns=list("ABCD"))

df2.plot(kind="bar", stacked=True)


  • 그래프에서 마이너스가 깨질 때

rc('axes', unicode_minus=False)


Scatter plots


x1 = np.random.normal(1, 1, size=(100, 1))
x2 = np.random.normal(-2, 4, size=(100, 1)) -> 평균이 -2, 표준편차가 4인 정규분포에서의 랜덤한 값을 갖는 100행 1열의 행렬 생성

x = np.concatenate((x1, x2), axis=1) -> 행 방향으로 합치기


plt.scatter(df3["x1"], df3["x2"], label="Scatter", color="r", marker="*", s=100) -> s == size


Pie charts


data = [5, 10, 30, 20]
activities = ["sleeping", "eating", "working", "playing"]

plt.pie(data, labels=activities)

plt.title("Pie Chart")
plt.legend() -> 범례
plt.show()


plt.pie(data, labels="activities, startangle=90)


Excel data to plot


  사용일자 노선명 역ID 역명 승차총승객수 하차총승객수 등록일자
0 20171201 경부선 1722 서정리 6052 5683 20171204
1 20171201 2호선 224 서초 26536 26469 20171204
2 20171201 중앙선 1207 양정 899 785 20171204


사용일자, 역ID, 등록일자는 실제 의미가 문자열이므로 describe 함수의 통계 대상에서 제외해줘야됨.

df_sub["사용일자"] = df_sub["사용일자"].astype(str)


date_ride = df_sub[['사용일자', '승차총승객수']].groupby(['사용일자']).agg(['sum'])

groupby : pivot과 유사함. 사용일자 열을 기준으로 값이 같은 행들끼리 그룹핑해줌


plt.figure(figsize=(12,8))

plt.title('Subway-ride Daily Trend',fontsize=20)
plt.plot(date_ride,'r-') -> 빨간색, 선으로 이어줌

plt.xlabel('Date')
plt.xticks(rotation='vertical') -> xlabel 수직으로 세움
plt.ylabel('# of riders')
plt.yticks(np.arange(4000000,9000000,1000000))

plt.show()


15강 (추가학습자료 2 - Cheatsheets & Pandas-Profiling)


대부분의 라이브러리는 여러 가지 핵심적인 문법, 사용법 등이 정리되어있는 Cheatsheet가 있음.

오랜만에 라이브러리를 접했을 때 전체적인 활용법을 상기시키는 용도로 활용하면 좋을 듯


  • for 문을 돌릴 때 진척도를 시각화하는 TQDM 라이브러리

Pandas-Profiling


EDA를 위한 라이브러리임. (Exploratory Data Analysis 탐색적 데이터 분석)

데이터를 탐색하면서 빠진 데이터는 없는지, 데이터 간의 상관관계가 존재하는지 등을
살펴보면서 데이터에 대한 이해도를 높이는 과정

profile
PS, 풀스택, 앱 개발, 각종 프로젝트 내용 정리 (https://github.com/minsu-cnu)

0개의 댓글