SlideShare a Scribd company logo
1 of 120
Download to read offline
파이썬
데이터과학
이태영
se2n@naver.com
파이썬을 이용한 데이터 분석,
그리고 머신러닝 실전 입문
레벨-2
이태영
구글 ‘데이터과학 파이썬‘ 분야 SEO 국내 1위
(경력)
2015 BC FEP 실시간 승인 거래 분석 시스템 설계/개발/구축
2015 BC 집현전 대상 ‘오픈소스를 활용한 빅데이터 플랫폼 구축’
2018 BC R&D Cell 최우수상 ‘AI 기반 서비스 플랫폼 구축’
2020 BC 차세대프로젝트 Scalable FEP/MCI 시스템 구축
(특허/등록건)
2012 고객 단말기의 맥 어드레스 정보를 이용한 결제 방법 및 시스템
2013 고객 단말기의 맥 어드레스 정보를 이용한 결제 방법 및 시스템
2014 카드 상품 추천 방법 및 카드사 서버
2014 사용 업종 예측을 위한 카드 사용 패턴 분석 방법 및 수행 서버
2015 가맹점 개인화 추천 방법 및 가맹점 추천 서버
(논문)
2017 Scalable 네트워크 아키텍처와 In-memory 컴퓨팅에 기반한
실시간 결제 분석 시스템, 고려대.
2018 Abnormal Payment Transaction Detection Scheme
based on Scalable Architecture and Redis Cluster, IEEE.
(자격)
2020 Algorithms Specialization, Stanford University.
2020 Applied Data Science Specialization, University of Michigan.
무슨 자격으로 강의를 하나요?
@관심사 : Scalable Architecture, Machine Learning, Object Detection, Visualization, Data Analysis, Pattern Recognition
#BCCard #IT기획팀 #신기술 #전략기획
자료를 공개하는 이유
# 유명해지고 싶다
# 놀면 뭐하니
# 강의는 취미
# 특허도 취미
# 데이터사이언티스트
# 풀스택개발자
# 비씨카드 # 데이터분석왕 # 이태영
독서백편의자현(讀書百遍義自見)
삽질할 용기
강의자료 100번도 말고
딱 3번만 복습
그리고 궁금하면 질문!
모든 데이터셋은 https://github.com/sh2orc/datascience 등록되어 있습니다.
이번 과정을 통해 배울 지식
1. 데이터과학 입문
• 데이터분석 워크플로우
• EDA(Exploratory Data Analysis)
2. 데이터 시각화
• matplotlib
• seaborn
• SVG 지도 시각화
3. 실전, 데이터분석
• 코스피 주가 종목 분석
• 서울시 대기오염 분석
• 행정구역 인구 변화 분석 (지도 기반)
• 서울시 아파트 현황 분석
• 강남구 아파트 매매 분석
4. 자연어처리 분석
• VISA 보고서 분석
• 워드 클라우드 (Word Cloud)
• 베이지안 이론(Bayesian Rule)
• N-Gram 분석과 언어 모델링
• 단어 연관 분석 (Word2Vec)
1. 데이터과학 입문
데이터과학 입문
데이터분석 워크플로우1)
Aim and
Scope
Data
Elaboration
데이터 교정
Data
Collection
데이터 수집
Data
Input
Data
Managing
Factor
Analysis
1D
Exploration
2D
Exploration
3D
Exploration
Data
Clustering
Data
Synthesizing
데이터합성
Data
Communicating
데이터소통
Decision
Making
Decision
Communicating
EDA (탐색적 데이터 분석)
Explorartory Data Analysis
1) Exploratory And Multivariate Data Analysis, Michel Jambu, 1991.
데이터과학 입문
EDA (Explorartory Data Analysis)
• 데이터과학 과정의 핵심적인 부분으로 데이터에 대한 이해를 높이는 것
• 모델링에 앞서 선행되는 작업으로 데이터의 분포나 변수간 관계 파악
• EDA의 기본 도구는 도표(plot), 그래프(graph), 요약통계(summary statistics)
• 데이터에 관한 직관적 접근을 통해 측정된 값(변수)들의 관계를 이해하고 예측
• 데이터의 시각화를 이용하지만 EDA는 데이터 시각화로서 끝나지 않으며 인사이트를 찾는 행위
• 단 한 번의 시각화나 수치 분석이 아닌 다양한 각도에서 데이터 접근이 필요함
"탐색적 데이터분석은 우리가 존재한다고 믿는 것들은 물론이고 존재하지 않는다고
믿는 것들을 발견하려는 태도, 유연성, 그리고 자발성이다." - Doing Data Science 중
"'잘못된 질문'에 대한 '확실한 답'은 항상 결론이 확실할 수 있으나 종종 결론이 애매
모호하게 나긴 하지만 '정확한 질문'에 대한 '대략적인 답이 더 낫다' - 존 튜키
2. 데이터 시각화
Matplotlib
기초 개념
• Matplotlib
• 산업계, 교육계에서 널리 사용되고 있는 수치 해석 소프트웨어
• 2차원 데이터를 시각화하기 위한 패키지
• MATLAB과 유사한 사용자 인터페이스
• 그래프의 종류, 축, 눈금선 그래프 이름 등 그림 요소의 상세한 서식 설정 가능
• 다양한 출력 형식(PNG,SVG,JPG 등)으로 저장 가능
%matplotlib inline
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
data = [0, 1]
ax.plot(data)
plt.show()
fig.savefig('image.png') #image.png로 저장
Matplotlib
Figure와 Subplot
• 핵심 개념 : Figure와 Subplot
Figure
Subplot (Axes) Subplot (Axes)
Figure 서브 플롯 (그래프영역) 작성 하는 틀
Subplot 그래프를 작성하기 위한 영역
Axes Figure 안의 (Sub)Plot들은 각각의 Axes 객체 속함
Axis 플롯의 가로 축이나 세로 축을 의미
Axis
Axis
Matplotlib
Figure와 Subplot
• add_subplot() 메소드
• add_subplot(지정위치 값)에서 지정위치 값은 3자리 숫자
• 지정위치 값은 순서대로 [총 행수], [총 열수], [서브플롯 번호] 의미
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(221) #2행 2열 1번
ax2 = fig.add_subplot(222) #2행 2열 2번
ax3 = fig.add_subplot(223) #2행 2열 3번
ax1.text(.2, .5, 'ax1(221)', fontsize=15)
ax2.text(.2, .5, 'ax2(222)', fontsize=15)
ax3.text(.2, .5, 'ax3(223)', fontsize=15)
plt.show()
Matplotlib
Figure와 Subplot
• add_subplot() 메소드
• add_subplot(지정위치 값)에서 지정위치의 3자리 숫자를 콤마(,)로 를 구분 가능
• add_subplot([총 행수], [총 열수], [서브플롯 번호]) 가능
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(2,2,1) #2행 2열 1번
ax2 = fig.add_subplot(2,2,2) #2행 2열 2번
ax3 = fig.add_subplot(2,2,3) #2행 2열 3번
ax1.plot([0,1]) # Y축값 (0, 1)
ax2.plot([1,0]) # Y축값 (1, 0)
ax3.plot([1,1]) # Y축값 (1, 1)
plt.show()
Matplotlib
Figure와 Subplot
• subplots() 메소드
• pyplot.subplots() 메소드를 이용해 Figure 생성과 Subplot 배치를 동시 설정
• pyplot.subplots() 메소드의 리턴 값은 figure와 axes 객체 배열
• axes[열 인덱스, 행 인덱스]
• 인덱스는 0부터 시작하는 점을 참고
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2, 2) #2x2 Axes 배열 생성
axes[0, 0].plot([0,1]) # Y축값 (0, 1)
axes[0, 1].plot([1,0]) # Y축값 (1, 0)
axes[1, 0].plot([1,1]) # Y축값 (1, 1)
plt.show()
Matplotlib
꺾은선 그래프
• Axes.plot([x], y, [fmt], data=None, **kwargs) 메소드
• plot() 메소드의 파라미터가 하나일 경우 Y 값으로 설정되고, X 값은 자동적으로 지정
• plot() 메소드에 사용되는 데이터형
• 파이썬 기본 1차원 구조체(리스트, 튜플)
• numpy.ndarray
• pandas.Series
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
x = [0, 2, 4]
y = [0, 4, 2]
ax.plot(x, y)
plt.show()
Matplotlib
좌표에 값 표시
• Axes.annotate( "value", xy=(float, float) ) 메소드
• annotate() 메소드를 이용하여 특정 위치 좌표에 값 표현 가능
• xy 옵션에는 x, y 좌표값에 대한 float 튜플 입력
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
x = [0, 2, 4]
y = [0, 4, 2]
ax.plot(x, y)
ax.annotate('0', xy=(0, 0))
ax.annotate('2', xy=(2, 4))
ax.annotate('4', xy=(4, 2))
plt.show()
Matplotlib
꺾은선 그래프
• 여러 개의 선을 그리는 경우
• 1개의 서브플롯에 여러 개의 그래프를 그릴 수 있음
• Axes 객체에 plot()을 여러 번 호출
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
x = [0, 1, 2]
y1 = [0, 4, 3]
y2 = [3, 2, 0]
ax.plot(x, y1)
ax.plot(x, y2)
plt.show()
Matplotlib
꺾은선 그래프
• 하루치 거래 승인 꺾은선 그래프
• pandas의 Series를 지정하여 그리기
import matplotlib.pyplot as plt
import pandas as pd
df = pd.read_csv('trns_1day_series')
fig = plt.figure(figsize=(10, 4)) # 그래프 크기
ax = fig.add_subplot(111)
ax.plot(df.index, df.APPROVAL, label='승인') # 승인건수
ax.plot(df.index, df.REJECT , label='거절') # 거절건수
ax.set_title('1일 거래 건수 현황') # 차트 타이틀
ax.set_ylabel('건수') # Y축 레이블
ax.set_xlabel('시간') # X축 레이블
ax.legend() #범례 유효화
plt.show()
Matplotlib
차트 한글 폰트 지정
• 맑은 고딕체 폰트 확인
from matplotlib import rcParams
rcParams['font.sans-serif'] = 'Malgun Gothic'
rcParams['font.weight'] = 'regular'
rcParams['axes.titlesize'] = 15
rcParams['ytick.labelsize'] = 12
rcParams['xtick.labelsize'] = 12
import matplotlib.font_manager as fm
font_list = fm.findSystemFonts(fontpaths=None, fontext='ttf')
[(f.name, f.fname) for f in fm.fontManager.ttflist if 'Malgun' in f.name]
Out[]: [('Malgun Gothic', 'C:WindowsFontsmalgun.ttf'),
('Malgun Gothic', 'C:WindowsFontsmalgunsl.ttf'),
('Malgun Gothic', 'C:WindowsFontsmalgunbd.ttf')]
• 맑은 고딕체 폰트 지정
Matplotlib
차트 한글 폰트 지정 (CentOS)
• 나눔 스퀘어 폰트 확인 및 차트 폰트 사용 지정
import matplotlib.font_manager as fm, rc
[ f.fname for f in fm.fontManager.ttflist if 'Nanum' in f.name]
Out[]: [ '/usr/share/fonts/nanumfont/NanumSquareL.ttf',
'/usr/share/fonts/nanumfont/NanumSquareR.ttf', .... ]
font_path = '/usr/share/fonts/nanumfont/NanumSqaureR.ttf'
font_name = fm.FontProperties(fname=font_path).get_name()
rc('font', family = font_name)
• 나눔 스퀘어(https://hangeul.naver.com/2017/nanum) 폰트 설치 (TTF파일을 아래 디렉토리로 복사)
/usr/share/fonts/nanumfont
~/.pyenv/versions/3.6.10/envs/py36/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf/
• 캐쉬 디렉토리 제거 및 폰트 캐쉬 갱신
rm -rf ~/.cache
fc-cache
Matplotlib
꺾은선 그래프
• 그래프 스타일 적용 옵션
• linestyle = solid, dashed, dotted, dashdotted 등 그래프 선의 형태
• color = black, grey, red, blue 등 그래프의 색깔
• marker = o , >, ^ 등 좌표에 해당하는 값 부분을 표시하는 마커
color linestyle
Matplotlib
꺾은선 그래프
• 그래프 스타일 적용
• color = 'r' 대표 16색에 대해서는 앞글자 1개만 지정해도 됨
• linestyle = 'dashed' 선의 스타일을 결정
• marker = 'o' 마커의 타입을 결정
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
x = [0, 1, 2]
y1 = [0, 4, 3]
y2 = [3, 2, 0]
ax.plot(x, y1, color='g', linestyle='dashed', marker='o')
ax.plot(x, y2, color='r', linestyle='dotted', marker='^')
plt.show()
Matplotlib
꺾은선 그래프
• 하루치 거래 승인 꺾은선 그래프
• 선 그래프의 스타일 적용
import matplotlib.pyplot as plt
import pandas as pd
df = pd.read_csv('trns_1day_series')
fig = plt.figure(figsize=(10, 4))
ax = fig.add_subplot(111)
ax.plot(df.index, df.APPROVAL, label='승인', linestyle='dotted', c='g') # 승인건수
ax.plot(df.index, df.REJECT , label='거절', linestyle='dashed', c='r') # 거절건수
ax.set_title('1일 거래 건수 현황') # 차트 타이틀
ax.set_ylabel('건수') # Y축 레이블
ax.set_xlabel('시간') # X축 레이블
#범례 유호화
ax.legend()
plt.show()
Matplotlib
막대 그래프
• Axes.bar(*args, data=None, **kwargs) 메소드
• 막대 그래프는 수량을 막대의 길이로 나타낸 그래프
• 파라미터로 X, Y 값을 지정
• tick_label = [] 에서 배열 인자로 눈금에 대한 레이블 지정 가능
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
x = [1, 2]
y = [3, 5]
labels = ['A', 'B']
ax.bar(x, y, tick_label=labels)
plt.show()
Matplotlib
막대 그래프
• Axes.barh(*args, data=None, **kwargs) 메소드
• 막대 그래프를 수평으로 나타내도록 한다.
• 입력 값은 bar() 메소드와 동일
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
x = [1, 2]
y = [3, 5]
labels = ['A', 'B']
ax.barh(x, y, tick_label=labels)
plt.show()
Matplotlib
막대 그래프
• 실패한 막대 그래프의 그룹화
• 여러 번의 Axes.bar(x, y) 호출에서 X 좌표 위치가 동일할 경우 덮어 씌워짐
• BAR 차트에서 데이터 그룹화를 위해서는 표현을 위한 전략 필요
import matplotlib.pyplot as plt
import pandas as pd
df = pd.read_csv('trns_1day_series')
s_mean, s_max = df.mean() , df.max()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.bar([1,2,3,4], s_mean, label='평균') #X축 좌표 = [1,2,3,4]
ax.bar([1,2,3,4], s_max , label='최대') #X축 좌표 = [1,2,3,4]
plt.show()
Matplotlib
막대 그래프
• 데이터를 각각 표현하는 방법
• '평균' 데이터들의 좌표를 1씩 공간을 만들고, 그 사이에 '최대' 데이터들을 위치
• '평균' 데이터들의 X좌표 = [1,3,5,7]
• '최대' 데이터들의 X좌표 = [2,4,6,8]
import matplotlib.pyplot as plt
import pandas as pd
df = pd.read_csv('trns_1day_series')
s_mean, s_max = df.mean() , df.max()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.bar([1,3,5,7], s_mean, label='평균')
ax.bar([2,4,6,8], s_max, label='최대')
ax.legend()
plt.show()
서로 X 축의 좌표를 침범하지 않게 한다
Matplotlib
막대 그래프
• 같은 인덱스는 붙이고, 다른 인덱스는 멀리.
• 두 '평균' 데이터, '최대' 데이터의 X좌표는 각각 1, 2부터 시작
• 차트 폭(width)을 1로 지정하여 '평균'과 '최대' 그래프를 붙임
• 각각의 X좌표는 3씩 증가시키면 인덱스별 분류가 좀더 쉽게 인식
import matplotlib.pyplot as plt
import pandas as pd
df = pd.read_csv('trns_1day_series')
s_mean, s_max = df.mean() , df.max()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.bar([1,4,7,10], s_mean, width=1, label='평균')
ax.bar([2,5,8,11], s_max, width=1, label='최대')
ax.legend()
plt.show()
남은 문제 - 레이블을 카테고리화를 시켜야 한다.
Matplotlib
막대 그래프
• X 축의 레이블 표시 기준 변경
• 각 데이터셋은 4가지 데이터 기준으로 표현 (SEND, RECV, APPROVAL, REJECT)
• X좌표에 분류된 데이터 중심 값을 4개 지정하여 표시
• set_xticks([X축 값1, X축 값2,…,… ]) : 여기에 지정된 X축 값만 레이블로 나타남
df = pd.read_csv('trns_1day_series')
s_mean, s_max = df.mean() , df.max()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.bar([1,3,5,7], s_mean, label='평균')
ax.bar([2,4,6,8], s_max, label='최대')
ax.set_xticks([1.5, 4.5, 7, 11])
ax.legend()
plt.show()
Matplotlib
막대 그래프
• X좌표의 레이블 카테고리 값 지정
• X좌표의 tick 값을 숫자가 아닌 카테고리 지정 값으로 변경
• set_xticklabels([카테고리 값1, 카테고리 값2, …, ])
• set_xticks() 메소드가 먼저 호출된 이후 지정되어야 함
df = pd.read_csv('trns_1day_series')
s_mean, s_max = df.mean() , df.max()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.bar([1,3,5,7], s_mean, label='평균')
ax.bar([2,4,6,8], s_max, label='최대')
ax.set_xticks([1.5, 4.5, 7, 11])
ax.set_xticklabels(['SEND','RECV','APPROVAL','REJECT'])
ax.legend()
plt.show()
Matplotlib
두 개 축을 가진 그래프
• 두 개의 Y축 기준을 나타내는 그래프
• Y 축을 LEFT 사이드와 RIGHT 사이드로 2개 축 지정
• twinx() : X 축의 기준을 공유하여 2개 Y축을 가질 경우
• twiny() : Y 축의 기준을 공유하여 2개 X축을 가질 경우
fig = plt.figure(figsize=(10, 4))
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx() # X축 공유하는 Y축 분리
ax1.plot(df.index, df.APPROVAL, label='승인', color='green' )
ax2.bar(df.index, df.REJECT , label='거절', color='purple' )
ax1.set_title('1일 거래 건수 현황')
ax1.set_ylabel('승인 건수') #Y1축 레이블
ax2.set_ylabel('거절 건수') #Y2축 레이블
ax1.set_xlabel('시간')
ax1.legend(loc=2) #범례 위치 지정
ax2.legend(loc=1) #범례 위치 지정
plt.show()
Matplotlib
산점도 그래프
• 점(scatter) 그래프
• Axes.scatter(x, y, …) 메소드 사용
• X축과 Y축에 수량이나 크기 등을 표시하기 위해 적합
• 일반적으로 데이터 분포 상황을 확인할 때 많이 활용
fig = plt.figure(figsize=(10, 4))
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx() # X축 공유하는 Y축 분리
ax1.plot(df.index, df.APPROVAL , label='승인', color='green')
ax2.scatter(df.index, df.REJECT , label='거절', color='purple' )
ax1.set_title('1일 거래 건수 현황')
ax1.set_ylabel('승인 건수') #Y1축 레이블
ax2.set_ylabel('거절 건수') #Y2축 레이블
ax1.set_xlabel('시간')
ax1.legend(loc=2) #범례 위치 지정
ax2.legend(loc=1) #범례 위치 지정
plt.show()
Matplotlib
원 그래프
• 원(circle) 그래프
• Axes.pie(x, labels=[], …) 메소드 사용
• 배열 X는 필수, labels 와 같은 옵션들에 의해 스타일이 결정
from matplotlib import rcParams
import matplotlib.pyplot as plt
rcParams['font.sans-serif'] = 'Malgun Gothic'
rcParams['font.weight'] = 'regular'
rcParams['axes.titlesize'] = 15
fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111)
label_list = ['승인','입금','제휴']
dataset = [50, 100, 30]
ax.pie(dataset, labels=label_list)
plt.show()
Seaborn
기초 개념
• 시각화와 통계 기능을 보다 편리하게 제공
• 시각화 기능은 Matplotlib 패키지를 기반으로 개발되어 편리한 시각화 기능
• 통계적 기능은 Statsmodel 패키지를 기반으로 개발되어 편리한 분석 기능
• 샘플 데이터를 제공하여 교육용 데이터가 풍부하게 제공
• 단순 그래프부터 히트맵까지 다양한 시각화 기능 제공함
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
df = pd.read_csv('trns_1day_series') df.describe()
sns.boxplot(data=df) #박스플롯으로 표시 SEND RECV APPROVAL REJECT
count 1440 1440 1440 1440
mean 10274.083 10274.832 10062.035 212.04792
std 6683.457 6683.4421 6584.3905 135.07823
min 769 769 714 16
25% 3580.75 3579.25 3469 84
50% 11115 11133.5 10901.5 210.5
75% 15745 15729.25 15451 305
max 24859 24911 24565 907
Seaborn
박스 플롯
• 카테고리 기준으로 데이터 변화를 표현할 때 유리
• 표현할 때는 카테고리를 명확하게 구분 지어야 함
• 어떤 기준으로 데이터의 수치를 표현할지!
• 카테고리 기준은 hue 옵션에 지정하면 됨 (hue 사용 시 X축, Y축 기준은 필수)
df = pd.read_csv('titanic.csv', sep='t')
df.head()
sns.boxplot(x='Survived', y='Age', hue='Sex', data=df) #성별 기준으로, 생존여부 기준으로 나이 분포
PassengerI
d
Survived Pclass Name Sex Age SibSp Parch Ticket Fare
Cabi
n
Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22 1 0 A/5 21171 7.25 NaN S
1 2 1 1
Cumings, Mrs. John Bradley (Florence Bri Th.
..
female 38 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26 0 0
STON/O2. 310128
2
7.925 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35 1 0 113803 53.1 C123 S
4 5 0 3 Allen, Mr. William Henry male 35 0 0 373450 8.05 NaN S
Seaborn
박스 플롯
#기관코드별 정상(APPROVAL)/거절(REJECT) 처리시간 분포 시각화
df = pd.read_csv('trns_msg_log/trns_msg_log', sep=':', dtype=str) #거래 로그 DataFrame
s_df = df[df.TRNS == '1'] #SEND 거래
r_df = df[df.TRNS == '2'] #RECV 거래
tf = pd.merge(s_df, r_df, on=['FIRM_CODE','SEQ'])
tf['APPROVAL'] = tf.RESP_CODE_y.isin(['00','01']) #정상 여부
# SEND와 RECV 전문 처리시간
tf['S_DATETIME'] = pd.to_datetime(tf.TIME_x, format='%H%M%S')
tf['R_DATETIME'] = pd.to_datetime(tf.TIME_y, format='%H%M%S')
tf['TIME_GAP'] = tf.R_DATETIME - tf.S_DATETIME
tf['TIME_GAP'] = tf.TIME_GAP.dt.seconds #시간을 초 단위 정수로 변환
#승인/거절 카테고리 기준으로, 기관별 처리시간 분포
sns.boxplot(x='FIRM_CODE',
y='TIME_GAP',
hue='APPROVAL', data=tf)
Seaborn
회귀분석 그래프
• lmplot() 메소드를 이용하여 회귀분석 판별
• hue 옵션 사용을 통해 기준을 세분화 하여 시각화 가능
df = pd.read_csv('titanic.csv', sep='t')
#나이별 운임료 회귀분석
sns.lmplot(x='Age',y='Fare', data=df)
#생존여부 기준으로 나이별 운임료 회귀분석
sns.lmplot(x='Age',y='Fare',
hue='Survived', data=df)
Seaborn
회귀분석 그래프
• tips 데이터셋을 이용하여 전체 지불금액(total_bill)과 팁(tip) 상관관계 분석
df = sns.load_dataset('tips')
df.head()
#생별 기준으로 전체 지불금액과 팀의 상관관계 회귀분석
sns.lmplot(x='total_bill', y='tip', hue='sex', data=df) hue ='smoker'로 했을 경우
total_bill tip sex smoker day time size
0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.5 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4
Seaborn
히트맵(Heatmap)
• 두 개의 카테고리에 해당되는 값의 변화와 분포를 나타낼 때 유리
• DataFrame에서 인덱스와 칼럼이 카테고리 값이 됨
• DataFrame 이용 시 pivot(index, columns, values) 메소드를 이용하여 변조 필요
df = pd.read_csv('titanic.csv', sep='t')
#생존자 기준으로 Age, Sex, Fare를 그룹화하여 건수를 추출
tf = df[df.Survived==1].groupby(['Age','Sex','Fare']).count().reset_index()
tf = tf[['Age','Sex','Fare','Pclass']]
tf = tf.rename(columns={'Pclass':'Count'})
zf = tf.pivot('Age','Fare', 'Count').fillna(0)
sns.heatmap(zf) # 연령, 운임에 따른 승객수 현황
Age Sex Fare Count
0 0.83 male 29 1
1 3 female 41.5792 1
2 4 female 16.7 1
3 5 female 27.75 1
4 12 male 11.2417 1
Seaborn
히트맵(Heatmap)
• df.pivot()의 경우 중복이나 값이 없을 때 아래 에러가 발생
ValueError: Index contains duplicate entries, cannot reshape
• pd.pivot_table의 경우는 index의 중복이 있어도 해결 가능
• pd.pivot_table의 경우 aggfunc 옵션이 제공되어 np.sum, np.mean 등 그룹함수 사용 가능
df = pd.read_csv('titanic.csv', sep='t')
tf = df.groupby(['Age','Sex','Survived']).count().reset_index().rename(columns={'Pclass':'Count'})
tf = tf[['Age','Sex','Survived','Count']]
# 좌측 인덱스가 Age(연령), 상단 칼럼은 Survived(생존여부)로 한 사람수를 나타내는 DataFrame으로 변조
zf = pd.pivot_table(tf,index='Age',columns='Survived',values='Count', aggfunc=np.sum).fillna(0)
sns.heatmap(zf)
pd.pivot_table(index='Sex', columns='Survived', values='Count', aggfunc=np.sum)
대한민국 지도 시각화
SVG 기반 지도 시각화
• 웹 SVG 태그 기반으로 대한민국 지도상의 시각화 방법
• SVG 태그 요소에 접근하여 색상을 변경하는 방식
• BeautifulSoup4 이용 (pip install bs4)
• south-korea.svg 지역명으로 접근 용이하게 수정해놨음 (https://github.com/sh2orc/datascience)
from IPython.display import SVG # jupyter에서 SVG 출력용
from bs4 import BeautifulSoup as bs # SVG 태그 접근 : beautifulsoup
map_south_svg = None
with open('south-korea.svg','r', encoding='utf-8') as f:
map_south_svg = f.read()
<svg>
<path id="광역시/도명" fill="#도형색깔" stroke="#윤곽선색깔" />
</svg>
south-korea.svg 구조
SVG(soup.prettify()) #출력
p = soup.find('path',{'id':'경기도'})
p['fill'] = '#ff2277' # 태그 fill 속성 = 핑크색
p = soup.find('path',{'id':'인천광역시'})
p['fill'] = '#22ff77' # 태그 fill 속성 = 연두색
대한민국 지도 시각화
SVG 기반 지도 시각화
• soup.find 함수를 통해 특정 태그에 접근 가능
• 태그마다 id별 지역명을 세팅해놨으므로 한글로 접근 가능
soup.select('svg > path[id]')[0].attrs['id'] #svg 태그 하위 path 태그(id 속성을 가진)를 모두 선택
'서울특별시'
p = soup.find('path',{'id':'서울특별시'})
p['fill'] = '#2277ff' #태그 fill 속성 = 청색
대한민국 지도 시각화
서울시 구 단위 시각화
map_seoul = None
with open('seoul-district.svg', 'r', encoding='utf-8') as f:
map_seoul = f.read()
soup = bs(map_seoul)
p = soup.find('path', {'id' : '영등포구' })
p['fill'] = '#99cc33'
SVG(soup.prettify())
• seoul-district.svg 지역구명으로 접근이 가능 확인
• BeautifulSoup 이용하여 영등포구 색상 변경 (테스트용)
대한민국 지도 시각화
CairoSVG를 이용한 이미지로 변환 (Windows)
• cairosvg 파이썬 라이브러리 설치 (pip install cairosvg)
• Uniconvertor 2.0 설치 (https://sk1project.net/uc2/download/)
• [시스템속성 - 환경변수 - 시스템변수 - Path] Uniconvertor의 dll 패스 추가
C:Program FilesUniConvertor-2.0rc4dlls
대한민국 지도 시각화
CairoSVG를 이용한 이미지로 변환 (Windows)
import io
from PIL import Image
import cairosvg
in_mem = io.BytesIO() #메모리 버퍼
cairosvg.svg2png(bytestring=soup.select('svg')[0].encode('utf-8'), write_to=in_mem)
img = Image.open(in_mem) # img 객체로 저장 (notebook에서 img 변수 직접 확인 가능)
img.save('seoul-img.png') #파일명으로 저장
• cairosvg.svg2png (bytestring=, write_to= )로 사용
• write_to= 문자로 입력 시 해당 파일명로 저장됨, 파일명이 아닌 ByteIO 객체 입력시 해당 객체로 저장
• bytestring= 에는 svg 태그 하위 내용이 입력되며 문자열은 byte로 변환 필수
• 이미지 프로세싱을 하기 위해서는 Pillow(PIL)의 Image 객체로 변환 필요
3. 실전, 데이터 분석
코스피 종목 기술 분석
LG유플러스 일별 종가 기준 분석
• 네이버 주식에서 LG유플러스(032640) 주가 스크래핑
• BeautifulSoup 라이브러리를 이용한 테이블 파싱
• 종목코드는 네이버 주가에서 종목명 옆에 나오는 값
• 기술적 분석은 가격에 모든 정보가 반영되어있다는 가정으로 진행
import pandas as pd
from bs4 import BeautifulSoup as bs
def scrap_page(code, page):
url = f'http://finance.naver.com/item/sise_day.nhn?code={code}&page={page}'
res = requests.get(url)
soup = BeautifulSoup(res.text, 'lxml')
df = pd.read_html(str(soup.find('table')), header=0)[0]
df = df.dropna()
return df
코스피 종목 기술 분석
LG유플러스 일별 종가 기준 분석
• scrap_page 함수 리턴되는 DataFrame는 함수 .append 이용하여 연결
• 스크래핑이 어려운 경우 LGU_190530_200729 파일 pd.read_csv 이용
import matplotlib.pyplot as plt
df = pd.DataFrame()
for i in range(1,30):
df = df.append( scrap_page('032640', i) )
df.sort_values('날짜', inplace=True)
fig = plt.figure( figsize=(20,10) )
ax = plt.subplot(111)
ax.plot(df['날짜'], df['종가'])
plt.show()
차트 출력은 되나 xticks가 너무 많이 나타남
코스피 종목 기술 분석
LG유플러스 일별 종가 기준 분석
• x축 tick 값들이 너무 많이 나타나서 xticks를 제거하는 방법
• ax.xticks([]) : axes 빈 리스트를 입력하면 x축 표시 값 삭제
fig = plt.figure( figsize=(20,10) )
ax = plt.subplot(111)
ax.plot(df['날짜'], df['종가'])
ax.xticks([]) # 차트에서 x-ticks 제거
plt.show()
코스피 종목 기술 분석
LG유플러스 일별 종가 기준 분석
• x축 tick 값들 중 특정 값만 나타나게 할 수 있다.
• ax.xticks(['표시할축값', ]) : tick 리스트에 표시할 대상 값을 지정하면 해당 값에 대한 표시 가능
fig = plt.figure( figsize=(20,10) )
ax = plt.subplot(111)
ax.plot(df['날짜'], df['종가'])
ax.xticks(['2020.07.01','2020.07.17'])
plt.show()
코스피 종목 기술 분석
LG유플러스 일별 종가 기준 분석
• ax.xticks(['표시할축값', ]) : tick 리스트에 표시할 대상 값을 지정하면 해당 값에 대한 표시 가능
• ax.xaxis.set_major_locator를 이용하여 표시 단위를 조정 가능
import matplotlib.ticker as ticker
fig = plt.figure( figsize=(20,10) )
ax = plt.subplot(111)
ax.xaxis.set_major_locator(ticker.MultipleLocator(30)) #표시 단위를 30개(일)로 표시
ax.plot(df['날짜'], df['종가'])
plt.show()
코스피 종목 기술 분석
LG유플러스 일별 종가 기준 분석
• np.polyfit(x, y, 다항차수)를 통해 계수를 추출하고, np.poly1d(계수)를 이용하여 회귀식을 도출
• 일별 종가에 대한 회귀분석값을 만들어서 회귀분석선을 표현
import numpy as np
fig = plt.figure( figsize=(20,10) )
ax = plt.subplot(111)
fp = np.polyfit(df.index, df.종가, 1)
fx = np.poly1d(fp)
df['회귀분석'] = fx(df.index)
ax.plot(df['날짜'], df['종가'])
ax.plot(df['날짜'], df['회귀분석'])
ax.legend(['LG유플러스'])
plt.xticks(['2019.05.30','2019.12.27','2020.03.13', '2020.06.01', '2020.07.17'])
plt.show()
코스피 종목 기술 분석
LG유플러스 일별 종가 기준 분석
• 2020.03.13 코로나-19 폭락장 이후 회귀분석선
fp = np.polyfit(df.index, df.종가, 1)
fx = np.poly1d(fp)
df['회귀분석'] = fx(df.index)
ax.plot(df['날짜'], df['종가'])
ax.plot(df['날짜'], df['회귀분석'])
ax.set_title('LG유플러스')
tf = df[df.날짜 > '2020.03.13']
tf = tf.reset_index()
fp = np.polyfit(tf.index, tf.종가, 1)
fx = np.poly1d(fp)
tf['회귀분석'] = fx(tf.index)
ax.plot(tf['날짜'], tf['회귀분석'])
ax.legend(['종가', '회귀분석(전체)', '회귀분석(폭락이후)'])
plt.show()
코스피 종목 기술 분석
LG유플러스 일별 종가 기준 분석
• seaborn을 이용한 회귀분석 lmplot( x=, y=, data=) 이용
• lmplot을 이용하면 편리하게 현황이 분석 가능하지만 적용된 회귀식을 알 수 없다
• x=, y= 으로 지정되는 pandas의 컬럼은 실수가 되어야 하므로 x축을 index(숫자)로 지정
tf = df[df.날짜 > '2020.03.13'] #코로나 폭락장 이후 데이터
tf = tf.reset_index() #index를 초기화 & 컬럼 'index'로 생성 (회귀분석 계산 위해)
ax = sns.lmplot(x='index', y='종가', data=tf) # 사이즈 조절 방법 aspect=2, height=5
ax.set_xticklabels(tf.날짜)
코스피 종목 기술 분석
LG유플러스 일별 종가 기준 분석
• 3월 13일 이후 상승, 하락한 날짜를 대상으로 분류(카테고리) 후 각각의 회귀분석
• 전일비 컬럼 값이 존재하나 전일 대비 상승(+), 하락(-) 기호가 없으므로 계산 필요
#tf['전일종가'] = tf.종가.shift(1) # 종가 Series를 요소를 shift 이동
tf['전일대비증감'] = tf['종가'] - tf['전일종가']
tf['전일대비증감'].fillna(0, inplace=True)
tf['증가여부'] = tf.전일대비증감.apply(lambda x : '상승' if x>=0 else '하락')
sns.lmplot(x='index',y='종가', data=tf, hue='증가여부', aspect=2, height=5)
서울시 대기 오염 분석
미세먼지 상관 관계 분석
• 2018년 기준 지역구별 미세먼지, 이산화질소농도, 오존농도, 이산화탄소농도, 아황산가스 등
• 출처 : 서울시 열린데이터 https://data.seoul.go.kr/dataList/OA-2218/S/1/datasetView.do
import pandas as pd
import seaborn as sns # seaborn의 상관관계 분석차트 이용 위해
from matplotlib import rcParams
rcParams['font.family'] = 'Malgun Gothic' # 폰트 맑은고딕 지정
%matplotlib inline
df = pd.read_csv('일별평균대기오염도_2018.csv')
측정일시 측정소명
이산화질소농도
(ppm)
오존농도(ppm)
이산화탄소농도
(ppm)
아황산가스(pp
m)
미세먼지(㎍/㎥)
초미세먼지(㎍/
㎥)
20180101 강남구 0.033 0.010 0.6 0.006 34.0 22.0
20180101 강남대로 0.040 0.007 0.8 0.006 NaN 17.0
20180101 강동구 0.038 0.010 0.7 0.005 48.0 24.0
20180101 강변북로 0.033 0.008 0.6 0.005 48.0 15.0
20180101 강북구 0.026 0.018 0.6 0.004 38.0 18.0
서울시 대기 오염 분석
미세먼지 상관 관계 분석 (joinplot)
• sns.jointplot을 이용하면 2개의 데이터 종류를 서로 상대적 분석을 할 때 용이
• 실수로 구성된 경우에 사용하며 sns.joinplot(x=, y=, )에서 각각 값을 지정
• sns.joinplot(kind=) 옵션으로 'scatter', 'hex' 등 존재
sns.jointplot(df['미세먼지'], df['초미세먼지'], kind='hex') sns.jointplot(df['미세먼지'], df['이산화질소농도'], kind='hex')
서울시 대기 오염 분석
미세먼지 상관 관계 분석 (pairplot)
• 컬럼명 클린징 후 월단위 측정소 기준 컬럼별 평균
• sns.pairplot을 이용하면 데이터 상관계수를 확인 가능
df.columns = [ col.split('(')[0] for col in df.columns ] #컬럼명 클린징 ( ) 포함 제거
df['년월'] = df.측정일시.apply(lambda x : str(x)[:6])
tf = df.groupby(['년월', '측정소명']).mean()
tf = tf.drop(columns='측정일시')
#회귀분석 kind='reg'
sns.pairplot(tf, kind='reg', size=2)
서울시 대기 오염 분석
미세먼지 상관 관계 분석 (pairplot)
• sns.pairplot(hue= ) 옵션에 카테고리화된 데이터를 지정하면 해당 기준으로 상관관계 분석
• 대기상태를 미세먼지 기준으로 좋음, 보통, 나쁨, 매우나쁨으로 카테고리화 가능
- 미세먼지㎍/㎥ 기준 : 좋음(0~15), 보통(16~35), 나쁨(36~75), 매우나쁨(76~)
tf['미세먼지'] = tf.미세먼지.fillna(method='bfill') #NaN 값이 있을 경우 직전 값으로 채움
tf['미세먼지_정규'] = tf.미세먼지.apply(lambda x:round(x)) #실수를 반올림하여 정수로 변경
tf['대기상태'] = tf.미세먼지_정규.apply(lambda x: '좋음' if x in range(0, 16) else
'보통' if x in range(16,36) else
'나쁨' if x in range(36,76) else
'매우나쁨' )
tf.loc['201809']
이산화질소농도 오존농도 이산화탄소농도 아황산가스 미세먼지 초미세먼지 미세먼지상태 미세먼지_정규
측정소명
강남구 0.023500 0.019533 0.363333 0.004833 16.166667 7.366667 보통 16
강남대로 0.034100 0.015069 0.453333 0.003533 24.700000 12.300000 보통 25
강동구 0.019800 0.023967 0.376667 0.003533 22.900000 9.133333 보통 23
강변북로 0.030600 0.018833 0.446667 0.003200 24.933333 10.700000 보통 25
강북구 0.012433 0.031033 0.326667 0.002200 16.266667 7.700000 보통 16
강서구 0.021233 0.029200 0.350000 0.002567 17.866667 9.100000 보통 18
공항대로 0.036433 0.017200 0.473333 0.007000 26.033333 12.366667 보통 26
서울시 대기 오염 분석
미세먼지 상관 관계 분석 (pairplot)
sns.pairplot(tf, kind='reg', hue='대기상태', size=2)
서울시 대기 오염 분석
미세먼지 상관 관계 분석 (pairplot)
• sns.pairplot(x_var=, y_var= ) 옵션에 각각 기준을 지정하면 특정 데이터들에 대한 상관관계 분석 가능
• [미세먼지, 초미세먼지]와 [이산화질소농도, 아황산가스]의 상관관계 분석
- 이미 각 데이터별 대기상태를 카테고리화 시켜놓았으니 유의미한 데이터 분석 가능
sns.pairplot(tf, x_vars=['미세먼지', '초미세먼지'], y_vars=['이산화질소농도', '아황산가스'],
hue='대기상태', kind='reg')
서울시 대기 오염 분석
미세먼지 월별 현황 분석 (heatmap)
• sns.headtmap()을 이용할 때 X축과 Y축을 이루는 데이터셋을 어떤 기준으로 정할지 중요
• X축을 년월, Y축을 측정소명, 표현 데이터를 미세먼지로 하여 미세먼지의 변화를 보고자 함
tf
이산화질소농도 오존농도 이산화탄소농도 아황산가스 미세먼지 초미세먼지 미세먼지_정규 대기상태
년월 측정소명
201801 강남구 0.036387 0.009355 0.603226 0.005871 42.548387 32.903226 43 나쁨
강남대로 0.058452 0.007677 0.838710 0.005484 63.566667 25.258065 64 나쁨
강동구 0.038613 0.012742 0.690323 0.005065 56.354839 35.064516 56 나쁨
강변북로 0.036065 0.009258 0.690323 0.005774 54.129032 21.064516 54 나쁨
강북구 0.030548 0.020419 0.612903 0.004903 46.806452 25.612903 47 나쁨
... ... ... ... ... ... ... ... ... ...
• 미세먼지 데이터만 필요하고, DataFrame을 인덱스는 년월, 컬럼을 측정소명으로 변경
tf[['미세먼지']].unstack()
미세먼지
측정소명 강남구 강남대로 강동구 강변북로 강북구 ... 종로 종로구 중구 중랑구 천호대로 행주 홍릉로 화랑로
년월
201801 42.548387 63.566667 56.354839 54.129032 46.806452 ... 41.689655 44.774194 44.516129 54.709677 62.580645 NaN 52.903226 49.935484
201802 50.037037 65.074074 59.555556 60.925926 49.666667 ... 47.925926 46.333333 45.777778 49.000000 63.037037 NaN 56.259259 53.962963
201803 37.100000 51.800000 44.950000 47.300000 36.800000 ... 34.600000 35.700000 34.850000 35.900000 52.700000 NaN 46.450000 44.550000
서울시 대기 오염 분석
미세먼지 월별 현황 분석 (heatmap)
• 컬럼은 레벨 2의 멀티컬럼으로 되어있으므로 미세먼지 헤더 제거 후 측정소명만 사용하도록 변경
tf = tf[['미세먼지']].unstack()
tf.columns
MultiIndex([('미세먼지', '강남구'),
('미세먼지', '강남대로'),
('미세먼지', '강동구'),
('미세먼지', '강변북로'),
......
tf.columns = [ col[1] for col in tf.columns ]
강남구 강남대로 강동구 강변북로 ... 한강대로 행주 홍릉로 화랑로
년월
201801 42.548387 63.566667 56.354839 54.129032 ... 58.354839 NaN 52.903226 49.935484
201802 50.037037 65.074074 59.555556 60.925926 ... 63.407407 NaN 56.259259 53.962963
201803 37.100000 51.800000 44.950000 47.300000 ... 51.800000 NaN 46.450000 44.550000
201804 44.380952 58.333333 60.571429 58.285714 ... 60.523810 NaN 59.142857 54.476190
201805 33.000000 43.523810 41.857143 48.285714 ... 51.666667 NaN 47.047619 40.333333
201806 42.285714 48.000000 51.857143 58.000000 ... 64.571429 NaN 58.857143 48.000000
201807 21.586207 24.448276 30.517241 27.103448 ... 36.206897 NaN 33.551724 33.350000
서울시 대기 오염 분석
미세먼지 월별 현황 분석 (heatmap)
• heatmap 출력 분석 : 미세먼지가 7~10월까지는 보통 이하를 유지
plt.figure(figsize=(30,15))
sns.heatmap(tf)
서울시 대기 오염 분석
미세먼지 월별 현황 분석 (heatmap)
• heatmap 텍스트 표시하려면 annot= 옵션 사용 및 fmt= 옵션으로 출력 포멧 지정
sns.heatmap(tf, annot=True, fmt='.0f')
행정구역별 인구 변화 분석
SVG 기반 대한민국 지도 시각화
• 레벨 1과정에서 다뤘던 행정구역별 인구 변화 데이터 셋 이용
from IPython.display import SVG # jupyter에서 SVG 출력용
from bs4 import BeautifulSoup as bs # SVG 태그 접근 : beautifulsoup
import pandas as pd
# matplotlib로 시각화
df = pd.read_csv('행정구역_시군구_시계열_인구변화', header=[0,1], index_col=0, dtype=str)
전국 서울특별시 부산광역시 ... 제주특별자치도
총인구수 남자인구수 여자인구수 총인구수 남자인구수 여자인구수 총인구수 남자인구수 여자인구수 ... 총인구수 남자인구수 여자인구수
2011.01 50534731 25318961 25215770 10312835 5110837 5201998 3566560 1772383 1794177 ... 571468 285659 285809
2011.02 50555262 25328299 25226963 10314245 5110818 5203427 3566480 1772175 1794305 ... 571913 285883 286030
2011.03 50575130 25337290 25237840 10307783 5107011 5200772 3564873 1770952 1793921 ... 572447 286152 286295
2011.04 50594424 25346019 25248405 10301829 5103919 5197910 3563042 1769903 1793139 ... 572918 286424 286494
2011.05 50613213 25354703 25258510 10295643 5100399 5195244 3562985 1769690 1793295 ... 573459 286668 286791
... ... ... ... ... ... ... ... ... ... ... ... ... ...
2020.01 51847509 25862863 25984646 9733509 4745088 4988421 3411819 1674202 1737617 ... 670749 337231 333518
행정구역별 인구 변화 분석
총 인구수 기준 변화 값 계산
• 지역별 2011년1월 - 2020년5월 인구변화 수치
• 컬럼에서 전국은 제외하고 각 지역별 총인구수의 차이 계산
import numpy as np
state_arr = np.unique([col[0] for col in df.columns if col[0] !='전국'])
array(['강원도', '경기도', '경상남도', '경상북도', '광주광역시', '대구광역시', '대전광역시', '부산광역시', '서울특별시', '세종특별자치시',
'울산광역시', '인천광역시', '전라남도', '전라북도', '제주특별자치도', '충청남도', '충청북도'], dtype='<U7')
people_dict = {}
for state in state_arr: #s = 강원도, 경기도, ...., 충청북도
people_201101 = df.loc[2011.01][state]['총인구수']
people_202005 = df.loc[2020.05][state]['총인구수']
diff_people = int(people_202005) - int(people_201101)
people_dict[state]= [int(people_201101), int(people_202005), diff_people]
행정구역별 인구 변화 분석
총 인구수 기준 변화 값 계산
• people_dict는 지역명을 key 가지는 딕셔너리 객체, key 당 3개의 요소로 구성된 배열
df = pd.DataFrame.from_dict(people_dict, orient='index', columns=['2019_05','2020_05','변화인구수'])
{'강원도': [1528790, 1538639, 9849],
'경기도': [11801232, 13324041, 1522809],
'경상남도': [3291435, 3351347, 59912],
'경상북도': [2688586, 2648760, -39826],
'광주광역시': [1456308, 1455533, -775],
'대구광역시': [2512071, 2429059, -83012],
'대전광역시': [1504617, 1471915, -32702],
......}
2011_01 2020_05 변화인구수
강원도 1528790 1538639 9849
경기도 11801232 13324041 1522809
경상남도 3291435 3351347 59912
경상북도 2688586 2648760 -39826
광주광역시 1456308 1455533 -775
대구광역시 2512071 2429059 -83012
대전광역시 1504617 1471915 -32702
부산광역시 3566560 3406942 -159618
서울특별시 10312835 9724496 -588339
세종특별자치시 0 345373 345373
..... ..... ..... .....
행정구역별 인구 변화 분석
총 인구수 기준 변화 값 계산
• 인구변화율 계산을 해보면 세종특별시 같이 폭증한 값이 존재. *이를 Outlier라고 함.
• 상대적 비교와 같이 구분 지을 때 너무 값이 차이나면 이를 줄이기 위한 정규화가 필요
df['인구변화율'] = (df['2020_05'] - df['2011_01']) / df['2020_05'] * 100
2011_01 2020_05 변화인구수 인구변화율
강원도 1528790 1538639 9849 0.640111
경기도 11801232 13324041 1522809 11.429033
경상남도 3291435 3351347 59912 1.787699
경상북도 2688586 2648760 -39826 -1.503571
광주광역시 1456308 1455533 -775 -0.053245
대구광역시 2512071 2429059 -83012 -3.417455
대전광역시 1504617 1471915 -32702 -2.221732
부산광역시 3566560 3406942 -159618 -4.685081
서울특별시 10312835 9724496 -588339 -6.050072
세종특별자치시 0 345373 345373 100.000000
울산광역시 1127337 1143148 15811 1.383110
인천광역시 2761122 2950063 188941 6.404643
전라남도 1916912 1855945 -60967 -3.284957
전라북도 1868745 1810097 -58648 -3.240047
제주특별자치도 571468 670793 99325 14.807101
충청남도 2076239 2118510 42271 1.995317
충청북도 1550474 1596710 46236 2.895704
행정구역별 인구 변화 분석
DataFrame quantile 이용한 임계치 기반 정규화
• pandas의 quantile 함수를 통해 백분위 수를 구할 수 있음
• 94% 백분위 값을 초과하는 Outlier 값은 치환하여 조정
limit = df['인구변화율'].quantile(0.94) # 94% 해당하는 값
df['인구변화율_정규'] = df['인구변화율'].apply(lambda x : limit if x > limit else x)
2011_01 2020_05 변화인구수 인구변화율 인구변화율_정규
강원도 1528790 1538639 9849 0.640111 0.640111
경기도 11801232 13324041 1522809 11.429033 11.429033
경상남도 3291435 3351347 59912 1.787699 1.787699
경상북도 2688586 2648760 -39826 -1.503571 -1.503571
광주광역시 1456308 1455533 -775 -0.053245 -0.053245
대구광역시 2512071 2429059 -83012 -3.417455 -3.417455
대전광역시 1504617 1471915 -32702 -2.221732 -2.221732
부산광역시 3566560 3406942 -159618 -4.685081 -4.685081
서울특별시 10312835 9724496 -588339 -6.050072 -6.050072
세종특별자치시 0 345373 345373 100.000000 18.214817
울산광역시 1127337 1143148 15811 1.383110 1.383110
인천광역시 2761122 2950063 188941 6.404643 6.404643
전라남도 1916912 1855945 -60967 -3.284957 -3.284957
전라북도 1868745 1810097 -58648 -3.240047 -3.240047
제주특별자치도 571468 670793 99325 14.807101 14.807101
충청남도 2076239 2118510 42271 1.995317 1.995317
충청북도 1550474 1596710 46236 2.895704 2.895704
행정구역별 인구 변화 분석
히스토그램과 pd.cut을 이용한 카테고라이즈
• 값들의 도수 분포 현황을 확인하고자 할 때 히스토그램을 활용
• 히스토그램을 확인하는 방법 : matplotlib.pyplot.hist (그래프 시각화)
fig = plt.figure()
ax1 = fig.add_subplot(211) #2행 1열 1번
ax2 = fig.add_subplot(212) #2행 1열 2번
#bins = 도수분포구간(7개)
ax1.hist(df['인구변화율'], bins=7)
ax1.legend(['인구변화율'])
# bins = 도수분포구간(7개)
ax2.hist(df['인구변화율_정규'], bins=7)
ax2.legend(['인구변화율_정규'])
plt.show()
행정구역별 인구 변화 분석
히스토그램과 pd.cut을 이용한 카테고라이즈
• np.histogram을 이용하여 도수 분포 현황 추출
• 분포시킬 구간의 개수(bins), 각 구간별 분포된 개수(counts), 분포를 결정하는 경계값들(bins_edges)
• counts, bins_edges = np.histogram(x, bins=7)
np.histogram(df['인구변화율'], bins=7) # 정규화가 안 되어있으니 첫번째 구간에 14개 몰림
np.histogram(df['인구변화율_정규'], bins=7) # Outlier를 조정 후 분포 형성
(array([5, 4, 4, 1, 0, 1, 2], dtype=int64),
array([-6.0500719 , -2.58365915, 0.88275361, 4.34916637, 7.81557912,
11.28199188, 14.74840463, 18.21481739]))
(array([14, 2, 0, 0, 0, 0, 1], dtype=int64),
array([ -6.0500719 , 9.09993837, 24.24994864, 39.39995891,
54.54996919, 69.69997946, 84.84998973, 100. ]))
행정구역별 인구 변화 분석
히스토그램과 pd.cut을 이용한 카테고라이즈
• pd.cut(x=데이터, bins=[경계값들, ], labels=[경계값 기준의 레이블링 값들,], include_lowest=True)
• bins 옵션에는 np.histogram으로 추출된 경계값 리스트를 입력
• labels 옵션에는 분포 구간에 대한 레이블 값 (입력이 없으면 분포 구간의 경계값 MIN, MAX 값으로 태깅)
bin_labels = [ i for i in range(7) ]
pd.cut(x=df['인구변화율_정규'], bins=bin_edges, labels=bin_labels, include_lowest=True)
강원도 1
경기도 5
경상남도 2
경상북도 1
광주광역시 1
대구광역시 0
대전광역시 1
부산광역시 0
서울특별시 0
세종특별자치시 6
울산광역시 2
인천광역시 3
전라남도 0
전라북도 0
제주특별자치도 6
충청남도 2
충청북도 2
Name: 인구변화율_정규, dtype: category
Categories (7, int64): [0 < 1 < 2 < 3 < 4 < 5 < 6]
행정구역별 인구 변화 분석
SVG 기반 대한민국 지도 시각화
bin_labels = [ i for i in range(7) ]
df['카테고리'] = pd.cut(x=df['인구변화율_정규'], bins=bin_edges, labels=bin_labels, include_lowest=True)
color_list = ['#F50057','#FF40AB','#E1BEE7','#CE93D8','#BA68C8','#9C27B0','#6A1B9A']
# 광역시도명 기반 태그 추출
# 카테고리번호를 color_list 요소로 배경색 세팅
for name, row in df.iterrows():
p = soup.find('path', {'id': name } )
c = color_list[ row['카테고리'] ]
p['fill'] = c
SVG(soup.prettify())
서울시 아파트 현황 분석
지역별 아파트 개수 분석
• seoul-district.svg 구별명으로 접근 용이하게 수정함 (https://github.com/sh2orc/datascience)
• 서울시 동별 정보, 아파트 세부 정보 출처 (부동산지인 https://aptgin.com)
from IPython.display import SVG # jupyter에서 SVG 출력용
from bs4 import BeautifulSoup as bs # SVG 태그 접근 : beautifulsoup
import pandas as pd
df_dong = pd.read_csv('지인_동정보' , dtype=str)
df_dong.head()
CODE C_NAME DONG
LAWD_APT_CNT_TO
TAL
NAME NAME2 NAME3 SIGUNGU STATE_NUM mcd
116801030
0
개포동 개포동 23.0 서울특별시 강남구 개포동 강남구 개포동 서울시 강남구 NaN 11680103
116801080
0
논현동 논현동 22.0 서울특별시 강남구 논현동 강남구 논현동 서울시 강남구 NaN 11680108
116801060
0
대치동 대치동 35.0 서울특별시 강남구 대치동 강남구 대치동 서울시 강남구 NaN 11680106
116801180
0
도곡동 도곡동 34.0 서울특별시 강남구 도곡동 강남구 도곡동 서울시 강남구 NaN 11680118
116801050
0
삼성동 삼성동 33.0 서울특별시 강남구 삼성동 강남구 삼성동 서울시 강남구 NaN 11680105
서울시 아파트 현황 분석
지역별 아파트 개수 분석
df_dong['LAWD_APT_CNT_TOTAL'] = df_dong.LAWD_APT_CNT_TOTAL.astype(float)
tf = df_dong[df_dong.NAME3=='서울시'].groupby('SIGUNGU').sum()
tf.columns = ['아파트수']
아파트수
SIGUNGU
강남구 330.0
강동구 170.0
강북구 60.0
강서구 307.0
관악구 125.0
광진구 108.0
구로구 243.0
금천구 79.0
노원구 232.0
도봉구 130.0
동대문구 165.0
동작구 131.0
마포구 211.0
서대문구 126.0
서초구 263.0
.... .....
서울시 아파트 현황 분석
지역별 아파트 개수 분석
counts, bin_edges = np.histogram(tf['아파트수'], bins=10)
bin_labels = list(range(10))
tf['카테고리'] = pd.cut(x=tf['아파트수'], bins=bin_edges, labels=bin_labels, include_lowest=True)
color_map = ['#F9E79F', '#F4D03F', '#F5B041', '#F1C40F', '#EDBB99',
'#F5B7B1', '#F1948A', '#EC7063', '#E74C3C', '#CB4335']
for name, row in tf.iterrows():
p = soup.find('path' ,{'id': name })
c = color_map[ row['카테고리'] ]
p['fill'] = c
SVG(soup.prettify())
• 히스토그램(np.histogram)을 이용한 pd.cut 기반 카테고라이즈
서울시 아파트 현황 분석
재건축 가능 아파트 분석
• 아파트 현황 데이터(지인_아파트단지)를 활용하여 동별 정보(지인_동정보) 데이터에 Merge
df_apt = pd.read_csv('지인_아파트단지', dtype=str)
bldg_nm house_cnt lawd_cd pk_apt_detail pk_apt_master pk_ent_master search_dt
SH대치1단지아파트 1616 1168010300.0 73780 16965 0 1992.1
개포6차우성 270 1168010300.0 10218 2533 0 1987.11
개포메트하임(O/T) 102 1168010300.0 161078 40178 0 2018.12
개포우성3차 405 1168010300.0 10094 2501 0 1984.12
... ... ... ... ... ... ...
화성발안엘에이치1단지 608 4159025900.0 275648 58358 0 2019.08
• 동별 정보(gin_dong)의 CODE 값과 lawd_cd 값이 같다는 것을 파악 가능
CODE C_NAME DONG LAWD_APT_CNT_TOTAL NAME NAME2 NAME3 SIGUNGU mcd
1168010300 개포동 개포동 23.0 서울특별시 강남구 개포동 강남구 개포동 서울시 강남구 11680103
1168010800 논현동 논현동 22.0 서울특별시 강남구 논현동 강남구 논현동 서울시 강남구 11680108
1168010600 대치동 대치동 35.0 서울특별시 강남구 대치동 강남구 대치동 서울시 강남구 11680106
1168011800 도곡동 도곡동 34.0 서울특별시 강남구 도곡동 강남구 도곡동 서울시 강남구 11680118
1168010500 삼성동 삼성동 33.0 서울특별시 강남구 삼성동 강남구 삼성동 서울시 강남구 11680105
서울시 아파트 현황 분석
재건축 가능 아파트 분석
• df_apt 데이터프레임의 lawd_cd 오른쪽 끝에 .0 같은 불필요한 값 제거 후 CODE 컬럼으로 할당
* read_csv( dtype=str )을 입력하지
df_apt['CODE'] = df_apt.lawd_cd.apply(lambda x : x.rstrip('0').rstrip('.'))
bldg_nm house_cnt lawd_cd pk_apt_detail pk_apt_master pk_ent_master search_dt CODE
SH대치1단지아파트 1616 1168010300.0 73780 16965 0 1992.1 1168010300
개포6차우성 270 1168010300.0 10218 2533 0 1987.11 1168010300
개포래미안포레스트 2296 1168010300.0 309876 64935 6181 2020.09 1168010300
개포메트하임(O/T) 102 1168010300.0 161078 40178 0 2018.12 1168010300
개포우성3차 405 1168010300.0 10094 2501 0 1984.12 1168010300
... ... ... ... ... ... ... ...
트윈테라스타워(O/T) 814 4159025900.0 231596 53342 0 2019.01 4159025900
한우물마을_휴먼시아5단지 1150 4159025900.0 67148 15599 0 2009.11 4159025900
한우물마을_휴먼시아6단지 1330 4159025900.0 67158 15601 0 2009.11 4159025900
화성라일플로리스3차(O/T) 538 4159025900.0 127262 32931 0 2016.07 4159025900
화성발안엘에이치1단지 608 4159025900.0 275648 58358 0 2019.08 4159025900
• df_apt와 df_dong 데이터프레임을 Merge 후 서울시 아파트만 필터링
df = pd.merge(df_apt, df_dong, how='left', on='CODE')
df = df[df.NAME3=='서울시']
서울시 아파트 현황 분석
재건축 가능 아파트 분석
• 2020년 12월 기준으로 30년 이상 된 아파트 추출
df[df.search_dt < '1990.12']
bldg_nm house_cnt pk_apt_detail pk_apt_master search_dt CODE C_NAME DONG ... NAME NAME2 NAME3 SIGUNGU mcd
개포6차우성 270 10218 2533 1987.11 1168010300 개포동 개포동 ...
서울특별시 강
남구 개포동
강남구 개포동 서울시 강남구 11680103
개포우성3차 405 10094 2501 1984.12 1168010300 개포동 개포동 ...
서울특별시 강
남구 개포동
강남구 개포동 서울시 강남구 11680103
개포주공1단
지
5040 39060 8961 1982.06 1168010300 개포동 개포동 ...
서울특별시 강
남구 개포동
강남구 개포동 서울시 강남구 11680103
개포주공5단
지
940 12523 3086 1983.1 1168010300 개포동 개포동 ...
서울특별시 강
남구 개포동
강남구 개포동 서울시 강남구 11680103
개포주공6단
지
1060 12606 3102 1983.1 1168010300 개포동 개포동 ...
서울특별시 강
남구 개포동
강남구 개포동 서울시 강남구 11680103
... ... ... ... ... ... ... ... ... ... ... ... ... ...
한신 1362 35929 8354 1987.12 1126010100 면목동 면목동 ...
서울특별시 중
랑구 면목동
중랑구 면목동 서울시 중랑구 11260101
우성 189 211608 1626 1975.12 1126010400 묵동 묵동 ...
서울특별시 중
랑구 묵동
중랑구 묵동 서울시 중랑구 11260104
장미 100 17474 4372 1983.1 1126010400 묵동 묵동 ...
서울특별시 중
랑구 묵동
중랑구 묵동 서울시 중랑구 11260104
상봉오피스텔
(O/T)
133 378788 6872 1988.04 1126010200 상봉동 상봉동 ...
서울특별시 중
랑구 상봉동
중랑구 상봉동 서울시 중랑구 11260102
세광 210 365065 1628 1986.08 1126010300 중화동 중화동 ...
서울특별시 중
랑구 중화동
중랑구 중화동 서울시 중랑구 11260103
tf = df[df.search_dt < '1990.12']
서울시 아파트 현황 분석
재건축 가능 아파트 분석
• 2020년 12월 기준으로 30년 이상 된 아파트 추출 분석
tf['아파트수'] = 1
tf.groupby('SIGUNGU').sum().sort_values('아파트수',ascending=False)
아파트수
SIGUNGU
강남구 64
서초구 50
영등포구 47
노원구 44
송파구 42
구로구 37
강동구 30
도봉구 27
용산구 21
양천구 21
광진구 14
성동구 13
서대문구 13
관악구 12
강서구 11
마포구 10
금천구 10
동대문구 9
은평구 8
.... ....
서울시 아파트 현황 분석
재건축 가능 아파트 분석
• 2020년 12월 기준으로 30년 이상 된 아파트 추출 분석
tf = tf.groupby('SIGUNGU').sum().sort_values('아파트수',ascending=False)
counts, bin_edges = np.histogram(tf['아파트수'], bins=10)
bin_labels = list(range(10))
tf['카테고리'] = pd.cut(x=tf['아파트수'], bins=bin_edges, labels=bin_labels, include_lowest=True)
for name, row in tf.iterrows():
p = soup.find('path', {'id': name })
c = color_map[ row['카테고리'] ]
p['fill'] = c
SVG(soup.prettify())
강남구 매매 실거래 분석
동별 아파트 평균 매매 변화 분석
• 아파트 단지 하위 아파트 세부 구조별 정보
df_apt_detail = pd.read_csv('지인_아파트단지세부')
bldg_nm lawd_cd ... contract_extent reside_public_nm
private_main_cd_n
m
reside_public_rep_
extent
SH대치1단지아파트 1168010300 ... 36.250 복도계단 아파트 8.810
SH대치1단지아파트 1168010300 ... 36.360 복도계단 아파트 8.810
SH대치1단지아파트 1168010300 ... 46.580 복도계단 아파트 9.620
SH대치1단지아파트 1168010300 ... 56.720 복도계단 아파트 13.090
흥덕마을_경남아너
스빌13단지
4146311100 ... 203.023 계단실,승강기,벽체 아파트 29.488
df_apt_sale = pd.read_csv('지인_아파트_매매')
• 세부 구조별 매매 거래내역 현황
price_c price yyyymm pk_apt_detail
42,000 (130동 11층) 42000 2017-12-08 19517
39,000 (130동 0층) 39000 2017-12-12 19517
42,000 (130동 0층) 42000 2017-12-28 19517
40,000 (130동 0층) 40000 2018-01-18 19517
40,000 (130동 17층) 40000 2018-01-26 19517
• df_dong 데이터프레임에서 [지역코드, '동이름', '시군구'] 정보로 '강남구'만 추출
• df_apt_detail (아파트 세부정보)에서 '아파트'만 추출
• Inner Join을 통해 강남구 하위 아파트로 병합
tf_dong = df_dong[['CODE','DONG','SIGUNGU']]
tf_dong = tf_dong[tf_dong.SIGUNGU=='강남구']
tf_apt_detail = df_apt_detail[df_apt_detail.private_main_cd_nm=='아파트']
강남아파트 = pd.merge( tf_apt_detail, tf_dong, left_on='lawd_cd', right_on='CODE')
강남아파트 = 강남아파트[['bldg_nm','CODE','DONG','contract_extent','pk_apt_detail']]
bldg_nm CODE DONG contract_extent pk_apt_detail
SH대치1단지아파트 1168010300 개포동 36.25 73780.0
SH대치1단지아파트 1168010300 개포동 36.36 73781.0
SH대치1단지아파트 1168010300 개포동 46.58 73782.0
... ... ... ... ...
한보미도맨션1차,2차 1168010600 대치동 0.00 177997.0
한보미도맨션1차,2차 1168010600 대치동 0.00 177998.0
현대 1168010600 대치동 104.78 16701.0
현대 1168010600 대치동 105.58 16702.0
강남구 매매 실거래 분석
동별 아파트 평균 매매 변화 분석
• 강남아파트와 실거래 매매가를 Join 후 NULL 값 대상 제거
• 날짜컬럼은 yyyymm에 년월일 데이터로 존재하므로 조정 필요
• 크기기준 (소형, 중형, 대형)으로 구분하는 데이터 카테고라이즈화
tf = pd.merge(강남아파트, df_apt_sale, on='pk_apt_detail')
tf = tf.dropna()
tf['yyyymmdd'] = tf.yyyymm
tf['yyyymm'] = tf.yyyymmdd.apply(lambda x:x[:7])
tf['크기기준'] =tf.contract_extent.apply(lambda x: '소형' if x <= 60 else 
'중형' if x > 60 and x <= 85 else '대형' )
bldg_nm CODE DONG contract_extent pk_apt_detail price yyyymm yyyymmdd 크기기준
경남1 1168010300 개포동 97.92 29856.0 195000 2020-03 2020-03-05 대형
경남1 1168010300 개포동 97.92 29856.0 190000 2020-04 2020-04-01 대형
... ... ... ... ... ... ... ... ...
현대 1168010600 대치동 104.78 16701.0 198000 2020-07 2020-07-28 대형
현대 1168010600 대치동 105.58 16702.0 150000 2019-05 2019-05-10 대형
현대 1168010600 대치동 105.58 16702.0 145000 2019-05 2019-05-10 대형
현대 1168010600 대치동 105.58 16702.0 155000 2019-07 2019-07-02 대형
현대 1168010600 대치동 105.58 16702.0 220000 2019-12 2019-12-15 대형
강남구 매매 실거래 분석
동별 아파트 평균 매매 변화 분석
• 개별 데이터에 대해 소형, 중형, 대형으로 카테고라이즈화가 끝났고, 수치 데이터인 매매가 존재
• seaborn boxplot을 이용하여 동별 매매가 변동폭을 확인 가능
import seaborn as sns
sns.boxplot(data=tf, x='DONG', y='price', hue='크기기준')
강남구 매매 실거래 분석
동별 아파트 평균 매매 변화 분석
• 삼성동 기준으로 아파트들의 매매가 변동폭 : x 좌표를 bldg_nm, y 좌표는 price로 지정
• 아파트명이 너무길기 때문에 rotation 45도 지정
fig = plt.figure(figsize=(20,10))
chart = sns.boxplot(data=tf[tf.DONG=='삼성동'], x='bldg_nm', y='price', hue='크기기준')
chart.set_xticklabels(chart.get_xticklabels(), rotation=45)
강남구 매매 실거래 분석
동별 아파트 평균 매매 변화 분석
• pivot 테이블을 이용하여 년월 기준 동별, 크기기준으로 그룹화하여 매매 평균값 구함
rf = tf.pivot_table(index='yyyymm', columns=['DONG','크기기준']).fillna(method='ffill') #NaN값은 이전 값으로
rf = rf[['price']]
rf.columns = pd.MultiIndex.from_tuples([c[1:] for c in rf.columns ]) # 컬럼명 클린징
sns.heatmap(rf)
강남구 매매 실거래 분석
동별 아파트 평균 매매 변화 분석
• 개포동을 대상으로 세부 아파트, 계약평형 기준으로 pivot 테이블 구성
rf = tf[tf.DONG=='개포동'][['bldg_nm','contract_extent','price','yyyymm']]
rf_pivot = pd.pivot_table(rf, index='yyyymm', columns=['bldg_nm','contract_extent'])
강남구 매매 실거래 분석
동별 아파트 평균 매매 변화 분석
price
bldg_nm 개포6차우성 ... 현대2 현대3
contract_extent 62.43 75.09 88.14 ... 107.23 107.75 160.73 165.46 197.27 107.25 160.51 196.46
yyyymm
2017-12 96500.0 NaN
132500.0
00000
... 170000.0 NaN
180000.0
00000
NaN 210000.0 NaN 190000.0
243333.3
33333
2018-01 97500.0 115000.0
134200.0
00000
... 170000.0 NaN
199285.7
14286
195000.0 222500.0
180000.0
00000
185000.0
245000.0
00000
2018-02 NaN 120000.0
142333.3
33333
... NaN NaN
190000.0
00000
192500.0 230000.0
180000.0
00000
NaN NaN
2018-03 118000.0 NaN
149000.0
00000
... 178800.0 NaN
190000.0
00000
190000.0 225000.0
180000.0
00000
NaN NaN
2018-04 107500.0 152000.0
156000.0
00000
... 175750.0 NaN
210000.0
00000
190000.0 NaN
178333.3
33333
NaN NaN
rf_pivot.columns = pd.MultiIndex.from_tuples( [c[1:] for c in rf_pivot.columns] )
• 컬럼명 클린징 (price 삭제)
• 컬럼은 (아파트명, 계약면적)으로 되어있으므로 특정 아파트명으로 1차 접근하면 계약면적들이 나타남
fig = plt.figure(figsize=(25,10))
ax = plt.subplot(111)
ax.plot( rf_pivot['개포자이'].fillna(method='ffill') ) # NaN 값은 이전 값으로 채움
ax.set_xticklabels(rf_pivot['개포자이'].index, rotation=45)
ax.legend(rf_pivot['개포자이'].columns)
plt.show()
강남구 매매 실거래 분석
동별 아파트 평균 매매 변화 분석
• 개포자이 계약면적 249.68에 대한 회귀분석선 생성
rf_pivot['개포자이'].fillna(method='ffill',inplace=True)
xr = np.array(range(len(rf_pivot['개포자이'][249.68].index)))
yr = rf_pivot['개포자이'][249.68].tolist()
fp = np.polyfit(xr, yr, 1) # 1차 회귀식 계수 생성
fx = np.poly1d(fp) #회귀식 생성
regress = fx(xr) #회귀분석 값 데이터 생성
강남구 매매 실거래 분석
동별 아파트 평균 매매 변화 분석
array([162925.45787546, 164630.02118289, 166334.58449033, 168039.14779777,
169743.7111052 , 171448.27441264, 173152.83772008, 174857.40102751,
176561.96433495, 178266.52764238, 179971.09094982, 181675.65425726,
183380.21756469, 185084.78087213, 186789.34417957, 188493.907487 ,
190198.47079444, 191903.03410187, 193607.59740931, 195312.16071675,
197016.72402418, 198721.28733162, 200425.85063906, 202130.41394649,
203834.97725393, 205539.54056137, 207244.1038688 , 208948.66717624,
210653.23048367, 212357.79379111, 214062.35709855, 215766.92040598])
ax = plt.subplot(111)
ax.plot(rf_pivot['개포자이'].fillna(method='ffill'))
ax.set_xticklabels(rf_pivot['개포자이'].index, rotation=45)
ax.plot(regress, '--', linewidth=5)
legends = rf_pivot['개포자이'].columns.tolist()
legends.append('249.68 회귀분석선')
ax.legend(legends)
plt.show()
강남구 매매 실거래 분석
동별 아파트 평균 매매 변화 분석
4. 자연어처리 분석
VISA 보고서 분석
자연어처리 기반의 EDA 접근
• 특정 회사 작성된 보고서나 문서에서 가장 많이 언급되는 키워드를 분석하면 전략 파악 가능
• 특정 회사의 문서 뿐만 아니라 특정 기간 범위 내의 기사들을 분석하면 시장 트렌드 분석 가능
• Innovations for Cashless World, VISA, 2017 레포트(PDF) 분석 예정
• 사용 라이브러리
pip install pypdf2 nltk wordcloud gensim
라이브러리 설명
pypdf2 pdf 파일을 분석하여 텍스트 형태로 변경을 위한 라이브러리
nltk 영문 자연어처리를 위한 라이브러리
wordcloud 텍스트에 대한 워드 클라우드 분석 라이브러리
gensim 단어들의 연관분석(word2vec)을 위한 라이브러리
VISA 보고서 분석
PDF 파일의 텍스트 추출
• PDF 파일 라이브러리 : pypdf2
• PDF 파일을 로드하여 contents 리스트에 텍스트로 저장
import pypdf2 as pypdf
contents = []
with open('visa-innovations-for-a-cashless-world-2017-report.pdf', 'rb') as f:
pdf = pypdf.PdfFileReader(f) # pdf 객체 생성
num_of_pages = pdf.getNumPages() # pdf 객체의 전체 페이지
for num_page in range(1, num_of_pages):
page = pdf.getPage(num_page) # 페이지 객체
if page.extractText(): # 텍스트 추출
contents.append(page.extractText())
VISA 보고서 분석
가장 많이 거론된 단어 분석
• 목표 : 추출된 전체 텍스트에서 단어들만 추출하여 가장 많이 거론된 단어를 확인
• 영문 자연어처리 라이브러리 nltk 활용
import nltk
from nltk.tokenize import word_tokenize #워드 토큰 객체
words = [ word_tokenize(page.lower()) for page in contents] # 소문자로 변환 후 워드 추출
words
from itertools import chain
words = list(chain.from_iterable(words))
words
[['001the', 'last', 'few', 'years', 'have', 'witnessed', 'dramatic', 'changes', 'in', 'our', ... ]]
• 단어별 카운팅을 전처리 작업을 위해 chain을 이용하여 1차원 리스트로 변환
['001the', 'last', 'few', 'years', 'have', 'witnessed', 'dramatic', 'changes', 'in', 'our', ... ]
VISA 보고서 분석
정규화와 불용어
• 단어 정규화(Nomalization)
• 불용어 (stopword) : 자주 등장하지만 큰 의미가 없는 단어들 (예) in, how, for, 조사, 접미사 등
from nltk.corpus import stopwords #불용어
from nltk.stem.wordnet import WordNetLemmatizer #Lemmartizer
_stopwords = set(stopwords.words('english')) #영어
_lemmatize = WordNetLemmatizer() #Lemmatizer 객체
words = [ w for w in words if w not in _stopwords ] #불용어 제거
words = [ w for w in words if w not in '!~@#$%^&*().,;:<>[]{}/+-?'"' ] #특수문자 제거
words = [ _lemmatize.lemmatize(w) for w in words] #정규화 (Lemmatization)
words
['001the', 'last', 'year', 'witnessed', 'dramatic', 'change', 'industry', 'rise', 'digital', 'payment', ...
Lemmatization 단어의 기본 사전형 단어로 복원 having > have, was > is
Stemming 기본형과 상관없이 단어 특정 기준으로 자름 having > hav, was > wa
VISA 보고서 분석
np.unique 이용한 단어, 단어건수 추출
• 단어의 출현빈도 건수는 numpy.unique 함수의 return_counts 이용
• np.unique 함수를 통해 리턴되는 값은 Unique 요소, 요소의 건수들의 각각의 np.array
import numpy as np
_words = np.array(words) # 리스트 > np array로 변환
word_arr, count_arr = np.unique(_words, return_counts=True) #Unique 요소, 건수 > np array로
word_ds=[]
for w, c in zip(word_arr, count_arr): #zip 함수를 통해 두 개의 이터러블 접근
word_ds.append( (w,c) )
words_ds
[("''", 2),
("'s", 10),
('-17-year-olds', 1),
('//tracxn.com', 1),
('//www.getkite.co', 1),
('/personal', 1),
('001the', 1),......
VISA 보고서 분석
상위 10개 단어 확인 (튜플 리스트 정렬)
• 정렬은 sorted 함수 이용. 대상이 객체일 경우 key= 옵션에 lambd를 이용하여 지정
• word_ds는 튜플(단어, 건수)로 구성된 리스트, 건수인 offset 1이 정렬의 키가 됨
• 내림차수 정렬은 reverse=True 옵션을 지정
sorted(word_ds, key=lambda x:x[1]) #오름차수 정렬
sorted(word_ds, key=lambda x:x[1], reverse=True) #내림차수 정렬
word_ds = sorted(word_ds, key=lambda x:x[1], reverse=True) #내림차수 정렬
word_ds[:10]
• 내림차수 정렬 후 상위 10개 확인
[('payment', 271),
('consumer', 115),
('visa', 112),
('card', 89),
('digital', 69),
('innovation', 68),
('new', 65),
('mobile', 64),
('use', 62),
('technology', 57)]
워드클라우드
wordcloud 생성 방법 #1
• 워드클라우드는 wordcloud 라이브러리 이용
• raw 텍스트를 입력하여 객체 생성 가능 - WordCloud 객체의 generate_from_text 함수 이용
from wordcloud import WordCloud
import matplotlib.pyplot as plt
wc = WordCloud()
wc = wc.generate_from_text('hi hi play game hi game')
#plt.imshow에 전달하면 차트로 출력
fig = plt.figure(figsize=(10, 10))
plt.imshow(wc)
plt.show()
워드클라우드
wordcloud 생성 방법 #2
• 워드클라우드는 wordcloud 라이브러리 이용
• 딕셔너리를 통해서도 객체 생성 가능 - WordCloud 객체의 generate_from_frequencies 함수 이용
from wordcloud import WordCloud
import matplotlib.pyplot as plt
wc = WordCloud()
wc = wc.generate_from_frequencies( {'hi':2, 'play':5, 'game':3, 'start':1} )
#plt.imshow에 전달하면 차트로 출력
fig = plt.figure(figsize=(10, 10))
plt.imshow(wc, interpolation="bilinear")
plt.show()
워드클라우드
VISA 워드 데이터셋을 워드 클라우드로
• VISA 워드 데이터셋(튜플 리스트)를 딕셔너리로 변경하여 출력
• 리스트 표현식과 동일하게 딕셔너리 내에서도 for~loop 표현 가능
word_dict = { _tuple[0]:_tuple[1] for _tuple in word_ds } # key(단어):value(건수) 형태로 변경
wc = WordCloud()
wc = wc.generate_from_frequencies( word_dict )
fig = plt.figure(figsize=(10, 10))
plt.imshow(wc)
plt.show()
워드클라우드
VISA 워드 데이터셋을 워드 클라우드로
• visa와 payment 단어를 제외하고 다시 워드클라우드 생성
• VISA 보고서에서 digital, consumer, card, innovation, technology가 눈에 띔
#워드 데이터셋에서 visa 단어와 payment를 제거
word_dict.pop('visa')
word_dict.pop('payment')
wc = wc.generate_from_frequencies( word_dict )
fig = plt.figure(figsize=(10, 10))
plt.imshow(wc)
plt.show()
워드클라우드
VISA 워드 데이터셋을 워드 클라우드로
• WordCloud 객체에 폰트, 크기, 배경색, random 상태 개수 등 옵션을 지정 가능
• random_state는 상위 기준 단어들을 정규화 역할 (Outlier에 의해 뭍힐 뻔한 단어 부각)
font_path ="C:/Windows/Fonts/malgun.ttf"
wc = WordCloud(
font_path = font_path,
width = 800,
height = 800,
random_state=25,
background_color='white'
)
wc = wc.generate_from_frequencies( word_dict )
fig = plt.figure(figsize=(10, 10))
plt.imshow(wc, interpolation='bilinear')
plt.axis('off') #차트에서 축 표시 숨김
plt.show()
워드클라우드
이미지 마스킹 효과 적용
• 이미지 객체를 np.array 로 변경하여 mask 지정 가능
• twitter.png 파일의 검은색 영역에 단어들이 표시 됨
from PIL import Image
_mask = np.array(Image.open('twitter.png'))
wc = WordCloud( font_path = font_path,
width = 800, height = 800, random_state=25,
background_color='white' ,
mask = _mask )
wc = wc.generate_from_frequencies( word_dict )
fig = plt.figure(figsize=(10, 10))
plt.imshow(wc, interpolation='bilinear')
plt.axis('off') #차트에서 축 표시 숨김
plt.show()
fig.savefig('visa_with_twitter.png') # 파일로 저장
twitter.png
워드클라우드
• 베이즈 이론 (Bayes Theory)
• P(A∩B) = P(B∩A)
• P(A∩B) = P(A) P(B | A)
• P(B∩A) = P(B) P(A | B)
• P(A) P(B | A) = P(B)P(A | B)
∴ P(A|B) =
P A P(B|A)
P(B)
=
P(A∩B)
P(B)
베이지안 이론
사건의 연속 확률 추정 : 조건부 확률
• 문서 내 단어들이 배치될 때 서로 이전 단어들의 존재를 확률적으로 판단하면 다음에 무엇이 올지 추정 가능
• P(WA | WB ) = 단어 B가 나타난 뒤 단어 A가 나타날 확률
• 사후확률이 일어날 가능성을 높히는 값은 사전확률, Likehood이므로 Likehood가 높을 수록 확률은 상승
P(A|B) =
𝐏 𝑨 𝐏(𝐁|𝐀)
𝐏(𝐁)
사후확률
(Posterior Probability)
관찰확률
(Marginal Probability)
사전 확률
(Prior Probability)
가능도
(Likehood)
• 베이즈 이론 (Bayes Theory)
• 날씨와 비의 관계 (총 20일)
맑음 흐림
비 옴 2일 10일 12일
안 옴 5일 3일 8일
7일 13일
• 비가 오는데 맑을 확률은?
P(맑음|비) = = = 0.35 (35%)
P(비)
P(맑음) P(비|맑음)
• P(맑음) = 7/20 = 0.35
• P(비) = 12/20 = 0.6
• P(비|맑음) = 2/7 = 0.285
0.6
0.35 x 0.6
베이지안 이론
사건의 연속 확률 추정 : 조건부 확률
베이지안 이론
Naive Bayesian
• 나이브 베이지안(Naive Bayesian) : 단순하게 모든 사건은 독립적으로 서로 영향을 끼치지 않는다 가정
확률적으로 정확하지 않아도 유의미한 확률 결과 도출할 수 있음
날씨가 좋았나 바람이 불었나 기압이 높았나 온도가 높았나 계
YES NO YES NO YES NO YES NO
비옴 2 6 6 2 5 3 3 5 8
안옴 8 4 2 10 7 5 3 9 12
• 오늘 날씨가 좋고, 바람이 불지 않고, 기압은 높고, 온도가 낮다면 - 비가 올까 안 올까?
• 비올 확률 P(비 | 날씨, ~바람, 기압, ~온도) = P(비) P(날씨, ~바람, 기압, ~온도|비)
P(날씨, ~바람, 기압, ~온도)
≒ P(비) P(날씨|비) P(~바람|비) P(기압|비) P(~온도|비)
= (8/20) * (2/8) * (2/8) * (5/8) * (5/8) = 0.009766
• 비 안 올 확률 P(~비 | 날씨, ~바람, 기압, ~온도)
≒ P(~비) P(날씨|~비) P(~바람|~비) P(기압|~비) P(~온도|~비)
= (12/20) * (8/12) * (10/12) * (7/12) * (9/12) = 0.145833
비가 안 올 것으로 예상
N-Gram 분석과 언어 모델링
확률적 언어 모델링 개념
• 확률 언어 모델(PLM)은 m 개의 단어들인 w1, w2, …, wm 가 문서(Document)를 이룰 때 베이지안 룰 적용
• N-Gram 모델 : 단어의 등장에 대한 조건부 확률 기준이 전체 단어의 구성이 아닌 N 개로 축소
• N-Grame 모델 종류 3가지
• 유니그램 모델 (Unigram model) : 단어가 서로 완전히 독립적이라고 가정
P(w1, w2, …, wm) = P(w1) P(w2) P(w3) … P(wm) = ς𝑖=1
𝑚
P(wi)
• 바이그램 모델 (Bigram Nodel 혹은 Markov Model) : 단어 출현의 확률이 직전 단어에 의존하는 확률
P(w1, w2, …, wm ) = P(w1 ,w2) P(w2 ,w3) P(w3 ,w4) … P(wm -1 , wm ) = P(w1) ς𝑖=2
𝑚
P(wi|wi−1)
• N그램 모델 (N gram-Model) : 단어의 출현이 이전 n-1 개의 단어에 의존하는 경우의 확률
P(w1, w2, …, wm ) = P(w1) ς𝑖=𝑛
𝑚
P(wi|wi−1 , … , wi−n)
• nltk 패키지의 ngram 객체 이용
• 조건부 확률을 추정은 문장의 시작(SS)과 끝이라는 조건(SE)을 표시 필요
from nltk import word_tokenize
from nltk.util import ngrams
tokens = word_tokenize("hello data science. hello world")
_ngrams = ngrams(tokens, 2) # bigram 생성
_bigrams = ngrams(tokens, 2, pad_left=True, pad_right=True, # bigram 생성 (토큰)
left_pad_symbol="SS", right_pad_symbol="SE")
ngram_list = [ ngram for ngram in _ngrams ]
ngram_list
[('hello', 'data'),
('data', 'science'),
('science', '.'),
('.', 'hello'),
('hello', 'world')]
bigram_list = [ bigram for bigram in _bigrams ]
bigram_list
[('SS', 'hello'),
('hello', 'data'),
('data', 'science'),
('science', '.'),
('.', 'hello'),
('hello', 'world'),
('world', 'SE')]
N-Gram 분석과 언어 모델링
ngram 기본 구현
• ConditionalFreqDist 클래스 이용 - 문맥별 단어 빈도 측정
• 문맥별 단어 빈도 측정을 기반으로 단어의 조건부 확률 추정이 가능함
from nltk import ConditionalFreqDist
import re
pages = [ re.sub('(s+|n)',' ', page ) for page in contents] # VISA 보고서 중복 공백/라인구분자 제거
full_text = ''.join(pages) # 전체 텍스트
word_list = word_tokenize(full_text) # 단어 토큰화
bigrams = [ ngram for ngram in ngrams(word_list, 2, pad_left=True, pad_right=True,
left_pad_symbol="SS", right_pad_symbol="SE") ]
cfd = ConditionalFreqDist(bigrams)
cfd['payment'].most_common(5) # payment 다음으로 가장 많이 위치한 단어 상위 5개
[('experiences', 6),
('process', 5),
('technology', 5),
('ecosystem', 5),
('options', 4)]
cfd['payment'] #payment 단어와 단어별 빈도 수
FreqDist({'experiences': 6, 'process': 5, 'technology': 5, 'ecosystem': 5, 'options': 4,
'technologies': 4, 'and': 4, 'security': 3, '.': 3, ',': 3, ...})
N-Gram 분석과 언어 모델링
bigram 기반 단어 빈도 분석
• ConditionalProbDist 클래스- 문맥별 단어 빈도 측정 기반으로 조건부 확률을 추정하는 트레이닝
• 트레이닝 후 조건부 확률의 값을 보거나 샘플 문장을 입력해서 문장의 로그 확률 추출 가능
• MLE (Maximum Likelihood Estimation) = 최대 가능도 추정치
from nltk import ConditionalProbDist, MLEProbDist
cpd = ConditionalProbDist(cfd, MLEProbDist) # MLE 확률 이용한 확률 추정 트레이닝
cpd['payment'].prob('process') # payment 다음에 process가 올 확률
0.04716981132075472
cpd['digital'].prob('payment') # digtal 다음에 payment 가 올 확률
0.07692307692307693
N-Gram 분석과 언어 모델링
단어의 조건부 확률
• ConditionalProbDist의 .generate()를 이용한 다음에 단어의 생성
• 트레이닝된 확률적 언어모델을 이용한 문장 생성 (챗봇 기본)
docs = [word_tokenize(page) for page in pages] #페이지별 단어별 토큰화
bigrams = [] #bigram 튜플 리스트
for doc in docs:
bigrams.extend([('SS', doc[0])]) #문맥 시작 토큰
bigrams.extend([(doc[i-1], doc[i]) for i in range(1, len(doc))])
bigrams.extend([(doc[-1],'SE')]) #문맥 종료 토큰
def generate_sentence():
current = 'SS' #문맥 시작 토큰
sentence = []
while True:
word = cpd[current].generate() #지정된 단어의 다음에 위치할 단어 생성
if word == 'SE' : break #문맥 종료 토큰
sentence.append(' ' + word)
current = word
return "".join(sentence)
N-Gram 분석과 언어 모델링
조건부 확률 기반 문장 생성
단어 연관 분석
Word2Vec
• 인공신경망을 기반으로 한 단어들에 대한 분산 표현(Distributed Representation) 딥러닝 기법
• 단어들의 의미를 여러 차원에다가 분산하여 표현하므로 단어들간 유사도 계산 가능
• Word2Vec에는 CBOW와 Skip-Gram 두 가지 방식 존재 (자세한 것은 데이터과학 레벨3 강의)
• CBOW (Continous Bag of Words) : 주변에 있는 단어들을 이용하여, 특정 위치의 단어를 예측 방법
• Skip-Gram : 특정 위치의 단어를 기준으로 주변 단어들을 예측 방법
• genism 라이브러리 이용하여 모델 생성
from gensim.models import word2vec
from nltk.corpus import stopwords
lemmatizer = WordNetLemmatizer()
stopword = set(stopwords.words('english'))
sentences=[]
for doc in docs:
sentences.append( [ lemmatizer.lemmatize(word) for word in doc if word not in stopword] )
# size = 벡터의 차원 , window = 윈도우 크기, hs = 1 softmax 이용, sg = 0(CBOW), 1(Skip-gram)
model = word2vec.Word2Vec(sentences, size=50, window=2, min_count=30, hs=1, sg=1)
단어 연관 분석
Word2Vec
• word2vec 모델의 활용
# word2vec 생성 50차원, 윈도우 사이즈 2, hs(softmax이용), sg는 skip-gram 이용
model = word2vec.Word2Vec(sentences, size=50, window=2, min_count=10, hs=1, sg=1)
model.wv.vocab.keys() # 단어들의 구성 확인
model.wv.similarity('consumer','card') # consumer 단어와 card 단어의 유사도
model.wv.most_similar('digital') # digital 단어와 가장 유사한 단어들
dict_keys(['year', 'industry', 'digital', 'payment', '.', 'people', 'around', 'world', 'use', .... ])
0.9974686
[('app', 0.9989895820617676),
('get', 0.9989762902259827),
('digital', 0.9987824559211731),
('data', 0.9987360835075378),
('million', 0.9987350106239319),
('APIs', 0.9987294673919678),
('also', 0.9987239837646484),
('wallet', 0.9987033009529114),
('The', 0.9987030625343323),
('seamless', 0.9986488223075867)]
단어 연관 분석
Word2Vec 시각화
• word2vec는 N개의 고차원으로 구성되어 있으므로 X, Y축으로 표현하려면 2차원으로 축소 필요
• 시각화를 위한 차원의 축소는 t-SNE(Stochastic Neighbor Embedding) 확률적 차원 축소 이용
from sklearn.manifold import TSNE
import pandas as pd
vocab = list(model.wv.vocab) # 단어 키
x = model[vocab] # 단어별 벡터값
tsne = TSNE(n_components=2) # 임베딩 공간 차원 (2차원)
x_tsne = tsne.fit_transform(x) # t-SNE 변환 벡터 값
df = pd.DataFrame(x_tsne, index=vocab, columns=['x','y'])
df.plot(kind='bar')
단어 연관 분석
Word2Vec 시각화
• word2vec는 N개의 고차원으로 구성되어 있으므로 X, Y축으로 표현하려면 2차원으로 축소 필요
• 시각화를 위한 차원의 축소는 t-SNE(Stochastic Neighbor Embedding) 확률적 차원 축소 이용
from sklearn.manifold import TSNE
import pandas as pd
# matplotlib로 시각화
fig = plt.figure(figsize=(20,20))
ax = fig.add_subplot(111)
ax.scatter(df['x'], df['y'])
for word, pos in df.iterrows():
ax.annotate(word, pos) #인덱스/ROW별 값
인공지능
머신러닝
패턴인식
딥러닝
이후 과정을 통해 배울 지식
이후 과정을 통해 배울 지식
Q&A

More Related Content

What's hot

웨어러블 환경에서의 모션 인식: 모션센서 기반의 웨어러블 기기 제어기술
웨어러블 환경에서의 모션 인식: 모션센서 기반의 웨어러블 기기 제어기술웨어러블 환경에서의 모션 인식: 모션센서 기반의 웨어러블 기기 제어기술
웨어러블 환경에서의 모션 인식: 모션센서 기반의 웨어러블 기기 제어기술
Jonghoon Seo
 
機械学習チュートリアル@Jubatus Casual Talks
機械学習チュートリアル@Jubatus Casual Talks機械学習チュートリアル@Jubatus Casual Talks
機械学習チュートリアル@Jubatus Casual Talks
Yuya Unno
 

What's hot (20)

Partial least squares回帰と画像認識への応用
Partial least squares回帰と画像認識への応用Partial least squares回帰と画像認識への応用
Partial least squares回帰と画像認識への応用
 
지식그래프 개념과 활용방안 (Knowledge Graph - Introduction and Use Cases)
지식그래프 개념과 활용방안 (Knowledge Graph - Introduction and Use Cases)지식그래프 개념과 활용방안 (Knowledge Graph - Introduction and Use Cases)
지식그래프 개념과 활용방안 (Knowledge Graph - Introduction and Use Cases)
 
Kaggleのテクニック
KaggleのテクニックKaggleのテクニック
Kaggleのテクニック
 
scikit-learnを用いた機械学習チュートリアル
scikit-learnを用いた機械学習チュートリアルscikit-learnを用いた機械学習チュートリアル
scikit-learnを用いた機械学習チュートリアル
 
상상을 현실로 만드는, 이미지 생성 모델을 위한 엔지니어링
상상을 현실로 만드는, 이미지 생성 모델을 위한 엔지니어링상상을 현실로 만드는, 이미지 생성 모델을 위한 엔지니어링
상상을 현실로 만드는, 이미지 생성 모델을 위한 엔지니어링
 
파이썬 Numpy 선형대수 이해하기
파이썬 Numpy 선형대수 이해하기파이썬 Numpy 선형대수 이해하기
파이썬 Numpy 선형대수 이해하기
 
[DL輪読会]Batch Renormalization: Towards Reducing Minibatch Dependence in Batch-...
[DL輪読会]Batch Renormalization: Towards Reducing Minibatch Dependence in Batch-...[DL輪読会]Batch Renormalization: Towards Reducing Minibatch Dependence in Batch-...
[DL輪読会]Batch Renormalization: Towards Reducing Minibatch Dependence in Batch-...
 
웨어러블 환경에서의 모션 인식: 모션센서 기반의 웨어러블 기기 제어기술
웨어러블 환경에서의 모션 인식: 모션센서 기반의 웨어러블 기기 제어기술웨어러블 환경에서의 모션 인식: 모션센서 기반의 웨어러블 기기 제어기술
웨어러블 환경에서의 모션 인식: 모션센서 기반의 웨어러블 기기 제어기술
 
Scaling Instruction-Finetuned Language Models
Scaling Instruction-Finetuned Language ModelsScaling Instruction-Finetuned Language Models
Scaling Instruction-Finetuned Language Models
 
3次元レジストレーション(PCLデモとコード付き)
3次元レジストレーション(PCLデモとコード付き)3次元レジストレーション(PCLデモとコード付き)
3次元レジストレーション(PCLデモとコード付き)
 
機械学習チュートリアル@Jubatus Casual Talks
機械学習チュートリアル@Jubatus Casual Talks機械学習チュートリアル@Jubatus Casual Talks
機械学習チュートリアル@Jubatus Casual Talks
 
TIBCO Spotfire
TIBCO SpotfireTIBCO Spotfire
TIBCO Spotfire
 
Graph Database Meetup in Seoul #1. What is Graph Database? (그래프 데이터베이스 소개)
Graph Database Meetup in Seoul #1. What is Graph Database? (그래프 데이터베이스 소개)Graph Database Meetup in Seoul #1. What is Graph Database? (그래프 데이터베이스 소개)
Graph Database Meetup in Seoul #1. What is Graph Database? (그래프 데이터베이스 소개)
 
[DL輪読会]Real-Time Semantic Stereo Matching
[DL輪読会]Real-Time Semantic Stereo Matching[DL輪読会]Real-Time Semantic Stereo Matching
[DL輪読会]Real-Time Semantic Stereo Matching
 
Faster R-CNN: Towards real-time object detection with region proposal network...
Faster R-CNN: Towards real-time object detection with region proposal network...Faster R-CNN: Towards real-time object detection with region proposal network...
Faster R-CNN: Towards real-time object detection with region proposal network...
 
CVPR2018のPointCloudのCNN論文とSPLATNet
CVPR2018のPointCloudのCNN論文とSPLATNetCVPR2018のPointCloudのCNN論文とSPLATNet
CVPR2018のPointCloudのCNN論文とSPLATNet
 
ResNetの仕組み
ResNetの仕組みResNetの仕組み
ResNetの仕組み
 
確率モデルを用いた3D点群レジストレーション
確率モデルを用いた3D点群レジストレーション確率モデルを用いた3D点群レジストレーション
確率モデルを用いた3D点群レジストレーション
 
DeBERTaV3: Improving DeBERTa using ELECTRA-Style Pre-Training with Gradient-D...
DeBERTaV3: Improving DeBERTa using ELECTRA-Style Pre-Training with Gradient-D...DeBERTaV3: Improving DeBERTa using ELECTRA-Style Pre-Training with Gradient-D...
DeBERTaV3: Improving DeBERTa using ELECTRA-Style Pre-Training with Gradient-D...
 
SmoothGrad: removing noise by adding noise
SmoothGrad: removing noise by adding noiseSmoothGrad: removing noise by adding noise
SmoothGrad: removing noise by adding noise
 

Similar to 파이썬 데이터과학 레벨2 - 데이터 시각화와 실전 데이터분석, 그리고 머신러닝 입문 (2020년 이태영)

Pyconkr2019 features for using python like matlab
Pyconkr2019 features for using python like matlabPyconkr2019 features for using python like matlab
Pyconkr2019 features for using python like matlab
Intae Cho
 
[SICP] 4.4 Logic Programming : 논리로 프로그램 짜기
[SICP] 4.4 Logic Programming : 논리로 프로그램 짜기[SICP] 4.4 Logic Programming : 논리로 프로그램 짜기
[SICP] 4.4 Logic Programming : 논리로 프로그램 짜기
종빈 오
 

Similar to 파이썬 데이터과학 레벨2 - 데이터 시각화와 실전 데이터분석, 그리고 머신러닝 입문 (2020년 이태영) (20)

R intro
R introR intro
R intro
 
R 스터디 첫번째
R 스터디 첫번째R 스터디 첫번째
R 스터디 첫번째
 
R 스터디 네번째
R 스터디 네번째R 스터디 네번째
R 스터디 네번째
 
Python+numpy pandas 2편
Python+numpy pandas 2편Python+numpy pandas 2편
Python+numpy pandas 2편
 
Python
PythonPython
Python
 
파이썬 스터디 2주차
파이썬 스터디 2주차파이썬 스터디 2주차
파이썬 스터디 2주차
 
Pyconkr2019 features for using python like matlab
Pyconkr2019 features for using python like matlabPyconkr2019 features for using python like matlab
Pyconkr2019 features for using python like matlab
 
R 프로그램의 이해와 활용 v1.1
R 프로그램의 이해와 활용 v1.1R 프로그램의 이해와 활용 v1.1
R 프로그램의 이해와 활용 v1.1
 
Python programming for Bioinformatics
Python programming for BioinformaticsPython programming for Bioinformatics
Python programming for Bioinformatics
 
4. stack
4. stack4. stack
4. stack
 
[SOPT] 데이터 구조 및 알고리즘 스터디 - #01 : 개요, 점근적 복잡도, 배열, 연결리스트
[SOPT] 데이터 구조 및 알고리즘 스터디 - #01 : 개요, 점근적 복잡도, 배열, 연결리스트[SOPT] 데이터 구조 및 알고리즘 스터디 - #01 : 개요, 점근적 복잡도, 배열, 연결리스트
[SOPT] 데이터 구조 및 알고리즘 스터디 - #01 : 개요, 점근적 복잡도, 배열, 연결리스트
 
강의자료3
강의자료3강의자료3
강의자료3
 
자료구조02
자료구조02자료구조02
자료구조02
 
Python 활용: 이미지 처리와 데이터 분석
Python 활용: 이미지 처리와 데이터 분석Python 활용: 이미지 처리와 데이터 분석
Python 활용: 이미지 처리와 데이터 분석
 
Java advancd ed10
Java advancd ed10Java advancd ed10
Java advancd ed10
 
★강의교재_데이터 분석을 위한 통계와 확률_v2.pptx
★강의교재_데이터 분석을 위한 통계와 확률_v2.pptx★강의교재_데이터 분석을 위한 통계와 확률_v2.pptx
★강의교재_데이터 분석을 위한 통계와 확률_v2.pptx
 
R과 기초통계 : 02.기술통계-자료나타내기
R과 기초통계 : 02.기술통계-자료나타내기R과 기초통계 : 02.기술통계-자료나타내기
R과 기초통계 : 02.기술통계-자료나타내기
 
[SOPT] 데이터 구조 및 알고리즘 스터디 - #02 : 스택, 큐, 수식 연산
[SOPT] 데이터 구조 및 알고리즘 스터디 - #02 : 스택, 큐, 수식 연산[SOPT] 데이터 구조 및 알고리즘 스터디 - #02 : 스택, 큐, 수식 연산
[SOPT] 데이터 구조 및 알고리즘 스터디 - #02 : 스택, 큐, 수식 연산
 
From MATLAB User to Python User
From MATLAB User to Python UserFrom MATLAB User to Python User
From MATLAB User to Python User
 
[SICP] 4.4 Logic Programming : 논리로 프로그램 짜기
[SICP] 4.4 Logic Programming : 논리로 프로그램 짜기[SICP] 4.4 Logic Programming : 논리로 프로그램 짜기
[SICP] 4.4 Logic Programming : 논리로 프로그램 짜기
 

More from Tae Young Lee

20141214 빅데이터실전기술 - 유사도 및 군집화 방법 (Similarity&Clustering)
20141214 빅데이터실전기술 - 유사도 및 군집화 방법 (Similarity&Clustering) 20141214 빅데이터실전기술 - 유사도 및 군집화 방법 (Similarity&Clustering)
20141214 빅데이터실전기술 - 유사도 및 군집화 방법 (Similarity&Clustering)
Tae Young Lee
 

More from Tae Young Lee (9)

2016년 비씨카드 신입사원 선배특강 20160719
2016년 비씨카드 신입사원 선배특강 201607192016년 비씨카드 신입사원 선배특강 20160719
2016년 비씨카드 신입사원 선배특강 20160719
 
파이썬 데이터과학 레벨1 - 초보자를 위한 데이터분석, 데이터시각화 (2020년 이태영)
파이썬 데이터과학 레벨1 - 초보자를 위한 데이터분석, 데이터시각화 (2020년 이태영) 파이썬 데이터과학 레벨1 - 초보자를 위한 데이터분석, 데이터시각화 (2020년 이태영)
파이썬 데이터과학 레벨1 - 초보자를 위한 데이터분석, 데이터시각화 (2020년 이태영)
 
파이썬 데이터과학 1일차 - 초보자를 위한 데이터분석, 데이터시각화 (이태영)
파이썬 데이터과학 1일차 - 초보자를 위한 데이터분석, 데이터시각화 (이태영)파이썬 데이터과학 1일차 - 초보자를 위한 데이터분석, 데이터시각화 (이태영)
파이썬 데이터과학 1일차 - 초보자를 위한 데이터분석, 데이터시각화 (이태영)
 
20141214 빅데이터실전기술 - 유사도 및 군집화 방법 (Similarity&Clustering)
20141214 빅데이터실전기술 - 유사도 및 군집화 방법 (Similarity&Clustering) 20141214 빅데이터실전기술 - 유사도 및 군집화 방법 (Similarity&Clustering)
20141214 빅데이터실전기술 - 유사도 및 군집화 방법 (Similarity&Clustering)
 
2016317 파이썬기초_파이썬_다중설치부터_Jupyter를이용한프로그래밍_이태영
2016317 파이썬기초_파이썬_다중설치부터_Jupyter를이용한프로그래밍_이태영2016317 파이썬기초_파이썬_다중설치부터_Jupyter를이용한프로그래밍_이태영
2016317 파이썬기초_파이썬_다중설치부터_Jupyter를이용한프로그래밍_이태영
 
20150306 파이썬기초 IPython을이용한프로그래밍_이태영
20150306 파이썬기초 IPython을이용한프로그래밍_이태영20150306 파이썬기초 IPython을이용한프로그래밍_이태영
20150306 파이썬기초 IPython을이용한프로그래밍_이태영
 
20141223 머하웃(mahout) 협업필터링_추천시스템구현
20141223 머하웃(mahout) 협업필터링_추천시스템구현20141223 머하웃(mahout) 협업필터링_추천시스템구현
20141223 머하웃(mahout) 협업필터링_추천시스템구현
 
20141111 파이썬으로 Hadoop MR프로그래밍
20141111 파이썬으로 Hadoop MR프로그래밍20141111 파이썬으로 Hadoop MR프로그래밍
20141111 파이썬으로 Hadoop MR프로그래밍
 
20141029 하둡2.5와 hive설치 및 예제
20141029 하둡2.5와 hive설치 및 예제20141029 하둡2.5와 hive설치 및 예제
20141029 하둡2.5와 hive설치 및 예제
 

파이썬 데이터과학 레벨2 - 데이터 시각화와 실전 데이터분석, 그리고 머신러닝 입문 (2020년 이태영)

  • 1. 파이썬 데이터과학 이태영 se2n@naver.com 파이썬을 이용한 데이터 분석, 그리고 머신러닝 실전 입문 레벨-2
  • 2. 이태영 구글 ‘데이터과학 파이썬‘ 분야 SEO 국내 1위 (경력) 2015 BC FEP 실시간 승인 거래 분석 시스템 설계/개발/구축 2015 BC 집현전 대상 ‘오픈소스를 활용한 빅데이터 플랫폼 구축’ 2018 BC R&D Cell 최우수상 ‘AI 기반 서비스 플랫폼 구축’ 2020 BC 차세대프로젝트 Scalable FEP/MCI 시스템 구축 (특허/등록건) 2012 고객 단말기의 맥 어드레스 정보를 이용한 결제 방법 및 시스템 2013 고객 단말기의 맥 어드레스 정보를 이용한 결제 방법 및 시스템 2014 카드 상품 추천 방법 및 카드사 서버 2014 사용 업종 예측을 위한 카드 사용 패턴 분석 방법 및 수행 서버 2015 가맹점 개인화 추천 방법 및 가맹점 추천 서버 (논문) 2017 Scalable 네트워크 아키텍처와 In-memory 컴퓨팅에 기반한 실시간 결제 분석 시스템, 고려대. 2018 Abnormal Payment Transaction Detection Scheme based on Scalable Architecture and Redis Cluster, IEEE. (자격) 2020 Algorithms Specialization, Stanford University. 2020 Applied Data Science Specialization, University of Michigan. 무슨 자격으로 강의를 하나요? @관심사 : Scalable Architecture, Machine Learning, Object Detection, Visualization, Data Analysis, Pattern Recognition #BCCard #IT기획팀 #신기술 #전략기획
  • 3. 자료를 공개하는 이유 # 유명해지고 싶다 # 놀면 뭐하니 # 강의는 취미 # 특허도 취미 # 데이터사이언티스트 # 풀스택개발자 # 비씨카드 # 데이터분석왕 # 이태영
  • 4. 독서백편의자현(讀書百遍義自見) 삽질할 용기 강의자료 100번도 말고 딱 3번만 복습 그리고 궁금하면 질문! 모든 데이터셋은 https://github.com/sh2orc/datascience 등록되어 있습니다.
  • 5. 이번 과정을 통해 배울 지식 1. 데이터과학 입문 • 데이터분석 워크플로우 • EDA(Exploratory Data Analysis) 2. 데이터 시각화 • matplotlib • seaborn • SVG 지도 시각화 3. 실전, 데이터분석 • 코스피 주가 종목 분석 • 서울시 대기오염 분석 • 행정구역 인구 변화 분석 (지도 기반) • 서울시 아파트 현황 분석 • 강남구 아파트 매매 분석 4. 자연어처리 분석 • VISA 보고서 분석 • 워드 클라우드 (Word Cloud) • 베이지안 이론(Bayesian Rule) • N-Gram 분석과 언어 모델링 • 단어 연관 분석 (Word2Vec)
  • 7. 데이터과학 입문 데이터분석 워크플로우1) Aim and Scope Data Elaboration 데이터 교정 Data Collection 데이터 수집 Data Input Data Managing Factor Analysis 1D Exploration 2D Exploration 3D Exploration Data Clustering Data Synthesizing 데이터합성 Data Communicating 데이터소통 Decision Making Decision Communicating EDA (탐색적 데이터 분석) Explorartory Data Analysis 1) Exploratory And Multivariate Data Analysis, Michel Jambu, 1991.
  • 8. 데이터과학 입문 EDA (Explorartory Data Analysis) • 데이터과학 과정의 핵심적인 부분으로 데이터에 대한 이해를 높이는 것 • 모델링에 앞서 선행되는 작업으로 데이터의 분포나 변수간 관계 파악 • EDA의 기본 도구는 도표(plot), 그래프(graph), 요약통계(summary statistics) • 데이터에 관한 직관적 접근을 통해 측정된 값(변수)들의 관계를 이해하고 예측 • 데이터의 시각화를 이용하지만 EDA는 데이터 시각화로서 끝나지 않으며 인사이트를 찾는 행위 • 단 한 번의 시각화나 수치 분석이 아닌 다양한 각도에서 데이터 접근이 필요함 "탐색적 데이터분석은 우리가 존재한다고 믿는 것들은 물론이고 존재하지 않는다고 믿는 것들을 발견하려는 태도, 유연성, 그리고 자발성이다." - Doing Data Science 중 "'잘못된 질문'에 대한 '확실한 답'은 항상 결론이 확실할 수 있으나 종종 결론이 애매 모호하게 나긴 하지만 '정확한 질문'에 대한 '대략적인 답이 더 낫다' - 존 튜키
  • 10. Matplotlib 기초 개념 • Matplotlib • 산업계, 교육계에서 널리 사용되고 있는 수치 해석 소프트웨어 • 2차원 데이터를 시각화하기 위한 패키지 • MATLAB과 유사한 사용자 인터페이스 • 그래프의 종류, 축, 눈금선 그래프 이름 등 그림 요소의 상세한 서식 설정 가능 • 다양한 출력 형식(PNG,SVG,JPG 등)으로 저장 가능 %matplotlib inline import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) data = [0, 1] ax.plot(data) plt.show() fig.savefig('image.png') #image.png로 저장
  • 11. Matplotlib Figure와 Subplot • 핵심 개념 : Figure와 Subplot Figure Subplot (Axes) Subplot (Axes) Figure 서브 플롯 (그래프영역) 작성 하는 틀 Subplot 그래프를 작성하기 위한 영역 Axes Figure 안의 (Sub)Plot들은 각각의 Axes 객체 속함 Axis 플롯의 가로 축이나 세로 축을 의미 Axis Axis
  • 12. Matplotlib Figure와 Subplot • add_subplot() 메소드 • add_subplot(지정위치 값)에서 지정위치 값은 3자리 숫자 • 지정위치 값은 순서대로 [총 행수], [총 열수], [서브플롯 번호] 의미 import matplotlib.pyplot as plt fig = plt.figure() ax1 = fig.add_subplot(221) #2행 2열 1번 ax2 = fig.add_subplot(222) #2행 2열 2번 ax3 = fig.add_subplot(223) #2행 2열 3번 ax1.text(.2, .5, 'ax1(221)', fontsize=15) ax2.text(.2, .5, 'ax2(222)', fontsize=15) ax3.text(.2, .5, 'ax3(223)', fontsize=15) plt.show()
  • 13. Matplotlib Figure와 Subplot • add_subplot() 메소드 • add_subplot(지정위치 값)에서 지정위치의 3자리 숫자를 콤마(,)로 를 구분 가능 • add_subplot([총 행수], [총 열수], [서브플롯 번호]) 가능 import matplotlib.pyplot as plt fig = plt.figure() ax1 = fig.add_subplot(2,2,1) #2행 2열 1번 ax2 = fig.add_subplot(2,2,2) #2행 2열 2번 ax3 = fig.add_subplot(2,2,3) #2행 2열 3번 ax1.plot([0,1]) # Y축값 (0, 1) ax2.plot([1,0]) # Y축값 (1, 0) ax3.plot([1,1]) # Y축값 (1, 1) plt.show()
  • 14. Matplotlib Figure와 Subplot • subplots() 메소드 • pyplot.subplots() 메소드를 이용해 Figure 생성과 Subplot 배치를 동시 설정 • pyplot.subplots() 메소드의 리턴 값은 figure와 axes 객체 배열 • axes[열 인덱스, 행 인덱스] • 인덱스는 0부터 시작하는 점을 참고 import matplotlib.pyplot as plt fig, axes = plt.subplots(2, 2) #2x2 Axes 배열 생성 axes[0, 0].plot([0,1]) # Y축값 (0, 1) axes[0, 1].plot([1,0]) # Y축값 (1, 0) axes[1, 0].plot([1,1]) # Y축값 (1, 1) plt.show()
  • 15. Matplotlib 꺾은선 그래프 • Axes.plot([x], y, [fmt], data=None, **kwargs) 메소드 • plot() 메소드의 파라미터가 하나일 경우 Y 값으로 설정되고, X 값은 자동적으로 지정 • plot() 메소드에 사용되는 데이터형 • 파이썬 기본 1차원 구조체(리스트, 튜플) • numpy.ndarray • pandas.Series import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) x = [0, 2, 4] y = [0, 4, 2] ax.plot(x, y) plt.show()
  • 16. Matplotlib 좌표에 값 표시 • Axes.annotate( "value", xy=(float, float) ) 메소드 • annotate() 메소드를 이용하여 특정 위치 좌표에 값 표현 가능 • xy 옵션에는 x, y 좌표값에 대한 float 튜플 입력 import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) x = [0, 2, 4] y = [0, 4, 2] ax.plot(x, y) ax.annotate('0', xy=(0, 0)) ax.annotate('2', xy=(2, 4)) ax.annotate('4', xy=(4, 2)) plt.show()
  • 17. Matplotlib 꺾은선 그래프 • 여러 개의 선을 그리는 경우 • 1개의 서브플롯에 여러 개의 그래프를 그릴 수 있음 • Axes 객체에 plot()을 여러 번 호출 import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) x = [0, 1, 2] y1 = [0, 4, 3] y2 = [3, 2, 0] ax.plot(x, y1) ax.plot(x, y2) plt.show()
  • 18. Matplotlib 꺾은선 그래프 • 하루치 거래 승인 꺾은선 그래프 • pandas의 Series를 지정하여 그리기 import matplotlib.pyplot as plt import pandas as pd df = pd.read_csv('trns_1day_series') fig = plt.figure(figsize=(10, 4)) # 그래프 크기 ax = fig.add_subplot(111) ax.plot(df.index, df.APPROVAL, label='승인') # 승인건수 ax.plot(df.index, df.REJECT , label='거절') # 거절건수 ax.set_title('1일 거래 건수 현황') # 차트 타이틀 ax.set_ylabel('건수') # Y축 레이블 ax.set_xlabel('시간') # X축 레이블 ax.legend() #범례 유효화 plt.show()
  • 19. Matplotlib 차트 한글 폰트 지정 • 맑은 고딕체 폰트 확인 from matplotlib import rcParams rcParams['font.sans-serif'] = 'Malgun Gothic' rcParams['font.weight'] = 'regular' rcParams['axes.titlesize'] = 15 rcParams['ytick.labelsize'] = 12 rcParams['xtick.labelsize'] = 12 import matplotlib.font_manager as fm font_list = fm.findSystemFonts(fontpaths=None, fontext='ttf') [(f.name, f.fname) for f in fm.fontManager.ttflist if 'Malgun' in f.name] Out[]: [('Malgun Gothic', 'C:WindowsFontsmalgun.ttf'), ('Malgun Gothic', 'C:WindowsFontsmalgunsl.ttf'), ('Malgun Gothic', 'C:WindowsFontsmalgunbd.ttf')] • 맑은 고딕체 폰트 지정
  • 20. Matplotlib 차트 한글 폰트 지정 (CentOS) • 나눔 스퀘어 폰트 확인 및 차트 폰트 사용 지정 import matplotlib.font_manager as fm, rc [ f.fname for f in fm.fontManager.ttflist if 'Nanum' in f.name] Out[]: [ '/usr/share/fonts/nanumfont/NanumSquareL.ttf', '/usr/share/fonts/nanumfont/NanumSquareR.ttf', .... ] font_path = '/usr/share/fonts/nanumfont/NanumSqaureR.ttf' font_name = fm.FontProperties(fname=font_path).get_name() rc('font', family = font_name) • 나눔 스퀘어(https://hangeul.naver.com/2017/nanum) 폰트 설치 (TTF파일을 아래 디렉토리로 복사) /usr/share/fonts/nanumfont ~/.pyenv/versions/3.6.10/envs/py36/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf/ • 캐쉬 디렉토리 제거 및 폰트 캐쉬 갱신 rm -rf ~/.cache fc-cache
  • 21. Matplotlib 꺾은선 그래프 • 그래프 스타일 적용 옵션 • linestyle = solid, dashed, dotted, dashdotted 등 그래프 선의 형태 • color = black, grey, red, blue 등 그래프의 색깔 • marker = o , >, ^ 등 좌표에 해당하는 값 부분을 표시하는 마커 color linestyle
  • 22. Matplotlib 꺾은선 그래프 • 그래프 스타일 적용 • color = 'r' 대표 16색에 대해서는 앞글자 1개만 지정해도 됨 • linestyle = 'dashed' 선의 스타일을 결정 • marker = 'o' 마커의 타입을 결정 import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) x = [0, 1, 2] y1 = [0, 4, 3] y2 = [3, 2, 0] ax.plot(x, y1, color='g', linestyle='dashed', marker='o') ax.plot(x, y2, color='r', linestyle='dotted', marker='^') plt.show()
  • 23. Matplotlib 꺾은선 그래프 • 하루치 거래 승인 꺾은선 그래프 • 선 그래프의 스타일 적용 import matplotlib.pyplot as plt import pandas as pd df = pd.read_csv('trns_1day_series') fig = plt.figure(figsize=(10, 4)) ax = fig.add_subplot(111) ax.plot(df.index, df.APPROVAL, label='승인', linestyle='dotted', c='g') # 승인건수 ax.plot(df.index, df.REJECT , label='거절', linestyle='dashed', c='r') # 거절건수 ax.set_title('1일 거래 건수 현황') # 차트 타이틀 ax.set_ylabel('건수') # Y축 레이블 ax.set_xlabel('시간') # X축 레이블 #범례 유호화 ax.legend() plt.show()
  • 24. Matplotlib 막대 그래프 • Axes.bar(*args, data=None, **kwargs) 메소드 • 막대 그래프는 수량을 막대의 길이로 나타낸 그래프 • 파라미터로 X, Y 값을 지정 • tick_label = [] 에서 배열 인자로 눈금에 대한 레이블 지정 가능 import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) x = [1, 2] y = [3, 5] labels = ['A', 'B'] ax.bar(x, y, tick_label=labels) plt.show()
  • 25. Matplotlib 막대 그래프 • Axes.barh(*args, data=None, **kwargs) 메소드 • 막대 그래프를 수평으로 나타내도록 한다. • 입력 값은 bar() 메소드와 동일 import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) x = [1, 2] y = [3, 5] labels = ['A', 'B'] ax.barh(x, y, tick_label=labels) plt.show()
  • 26. Matplotlib 막대 그래프 • 실패한 막대 그래프의 그룹화 • 여러 번의 Axes.bar(x, y) 호출에서 X 좌표 위치가 동일할 경우 덮어 씌워짐 • BAR 차트에서 데이터 그룹화를 위해서는 표현을 위한 전략 필요 import matplotlib.pyplot as plt import pandas as pd df = pd.read_csv('trns_1day_series') s_mean, s_max = df.mean() , df.max() fig = plt.figure() ax = fig.add_subplot(111) ax.bar([1,2,3,4], s_mean, label='평균') #X축 좌표 = [1,2,3,4] ax.bar([1,2,3,4], s_max , label='최대') #X축 좌표 = [1,2,3,4] plt.show()
  • 27. Matplotlib 막대 그래프 • 데이터를 각각 표현하는 방법 • '평균' 데이터들의 좌표를 1씩 공간을 만들고, 그 사이에 '최대' 데이터들을 위치 • '평균' 데이터들의 X좌표 = [1,3,5,7] • '최대' 데이터들의 X좌표 = [2,4,6,8] import matplotlib.pyplot as plt import pandas as pd df = pd.read_csv('trns_1day_series') s_mean, s_max = df.mean() , df.max() fig = plt.figure() ax = fig.add_subplot(111) ax.bar([1,3,5,7], s_mean, label='평균') ax.bar([2,4,6,8], s_max, label='최대') ax.legend() plt.show() 서로 X 축의 좌표를 침범하지 않게 한다
  • 28. Matplotlib 막대 그래프 • 같은 인덱스는 붙이고, 다른 인덱스는 멀리. • 두 '평균' 데이터, '최대' 데이터의 X좌표는 각각 1, 2부터 시작 • 차트 폭(width)을 1로 지정하여 '평균'과 '최대' 그래프를 붙임 • 각각의 X좌표는 3씩 증가시키면 인덱스별 분류가 좀더 쉽게 인식 import matplotlib.pyplot as plt import pandas as pd df = pd.read_csv('trns_1day_series') s_mean, s_max = df.mean() , df.max() fig = plt.figure() ax = fig.add_subplot(111) ax.bar([1,4,7,10], s_mean, width=1, label='평균') ax.bar([2,5,8,11], s_max, width=1, label='최대') ax.legend() plt.show() 남은 문제 - 레이블을 카테고리화를 시켜야 한다.
  • 29. Matplotlib 막대 그래프 • X 축의 레이블 표시 기준 변경 • 각 데이터셋은 4가지 데이터 기준으로 표현 (SEND, RECV, APPROVAL, REJECT) • X좌표에 분류된 데이터 중심 값을 4개 지정하여 표시 • set_xticks([X축 값1, X축 값2,…,… ]) : 여기에 지정된 X축 값만 레이블로 나타남 df = pd.read_csv('trns_1day_series') s_mean, s_max = df.mean() , df.max() fig = plt.figure() ax = fig.add_subplot(111) ax.bar([1,3,5,7], s_mean, label='평균') ax.bar([2,4,6,8], s_max, label='최대') ax.set_xticks([1.5, 4.5, 7, 11]) ax.legend() plt.show()
  • 30. Matplotlib 막대 그래프 • X좌표의 레이블 카테고리 값 지정 • X좌표의 tick 값을 숫자가 아닌 카테고리 지정 값으로 변경 • set_xticklabels([카테고리 값1, 카테고리 값2, …, ]) • set_xticks() 메소드가 먼저 호출된 이후 지정되어야 함 df = pd.read_csv('trns_1day_series') s_mean, s_max = df.mean() , df.max() fig = plt.figure() ax = fig.add_subplot(111) ax.bar([1,3,5,7], s_mean, label='평균') ax.bar([2,4,6,8], s_max, label='최대') ax.set_xticks([1.5, 4.5, 7, 11]) ax.set_xticklabels(['SEND','RECV','APPROVAL','REJECT']) ax.legend() plt.show()
  • 31. Matplotlib 두 개 축을 가진 그래프 • 두 개의 Y축 기준을 나타내는 그래프 • Y 축을 LEFT 사이드와 RIGHT 사이드로 2개 축 지정 • twinx() : X 축의 기준을 공유하여 2개 Y축을 가질 경우 • twiny() : Y 축의 기준을 공유하여 2개 X축을 가질 경우 fig = plt.figure(figsize=(10, 4)) ax1 = fig.add_subplot(111) ax2 = ax1.twinx() # X축 공유하는 Y축 분리 ax1.plot(df.index, df.APPROVAL, label='승인', color='green' ) ax2.bar(df.index, df.REJECT , label='거절', color='purple' ) ax1.set_title('1일 거래 건수 현황') ax1.set_ylabel('승인 건수') #Y1축 레이블 ax2.set_ylabel('거절 건수') #Y2축 레이블 ax1.set_xlabel('시간') ax1.legend(loc=2) #범례 위치 지정 ax2.legend(loc=1) #범례 위치 지정 plt.show()
  • 32. Matplotlib 산점도 그래프 • 점(scatter) 그래프 • Axes.scatter(x, y, …) 메소드 사용 • X축과 Y축에 수량이나 크기 등을 표시하기 위해 적합 • 일반적으로 데이터 분포 상황을 확인할 때 많이 활용 fig = plt.figure(figsize=(10, 4)) ax1 = fig.add_subplot(111) ax2 = ax1.twinx() # X축 공유하는 Y축 분리 ax1.plot(df.index, df.APPROVAL , label='승인', color='green') ax2.scatter(df.index, df.REJECT , label='거절', color='purple' ) ax1.set_title('1일 거래 건수 현황') ax1.set_ylabel('승인 건수') #Y1축 레이블 ax2.set_ylabel('거절 건수') #Y2축 레이블 ax1.set_xlabel('시간') ax1.legend(loc=2) #범례 위치 지정 ax2.legend(loc=1) #범례 위치 지정 plt.show()
  • 33. Matplotlib 원 그래프 • 원(circle) 그래프 • Axes.pie(x, labels=[], …) 메소드 사용 • 배열 X는 필수, labels 와 같은 옵션들에 의해 스타일이 결정 from matplotlib import rcParams import matplotlib.pyplot as plt rcParams['font.sans-serif'] = 'Malgun Gothic' rcParams['font.weight'] = 'regular' rcParams['axes.titlesize'] = 15 fig = plt.figure(figsize=(5, 5)) ax = fig.add_subplot(111) label_list = ['승인','입금','제휴'] dataset = [50, 100, 30] ax.pie(dataset, labels=label_list) plt.show()
  • 34. Seaborn 기초 개념 • 시각화와 통계 기능을 보다 편리하게 제공 • 시각화 기능은 Matplotlib 패키지를 기반으로 개발되어 편리한 시각화 기능 • 통계적 기능은 Statsmodel 패키지를 기반으로 개발되어 편리한 분석 기능 • 샘플 데이터를 제공하여 교육용 데이터가 풍부하게 제공 • 단순 그래프부터 히트맵까지 다양한 시각화 기능 제공함 import matplotlib.pyplot as plt import pandas as pd import seaborn as sns df = pd.read_csv('trns_1day_series') df.describe() sns.boxplot(data=df) #박스플롯으로 표시 SEND RECV APPROVAL REJECT count 1440 1440 1440 1440 mean 10274.083 10274.832 10062.035 212.04792 std 6683.457 6683.4421 6584.3905 135.07823 min 769 769 714 16 25% 3580.75 3579.25 3469 84 50% 11115 11133.5 10901.5 210.5 75% 15745 15729.25 15451 305 max 24859 24911 24565 907
  • 35. Seaborn 박스 플롯 • 카테고리 기준으로 데이터 변화를 표현할 때 유리 • 표현할 때는 카테고리를 명확하게 구분 지어야 함 • 어떤 기준으로 데이터의 수치를 표현할지! • 카테고리 기준은 hue 옵션에 지정하면 됨 (hue 사용 시 X축, Y축 기준은 필수) df = pd.read_csv('titanic.csv', sep='t') df.head() sns.boxplot(x='Survived', y='Age', hue='Sex', data=df) #성별 기준으로, 생존여부 기준으로 나이 분포 PassengerI d Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabi n Embarked 0 1 0 3 Braund, Mr. Owen Harris male 22 1 0 A/5 21171 7.25 NaN S 1 2 1 1 Cumings, Mrs. John Bradley (Florence Bri Th. .. female 38 1 0 PC 17599 71.2833 C85 C 2 3 1 3 Heikkinen, Miss. Laina female 26 0 0 STON/O2. 310128 2 7.925 NaN S 3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35 1 0 113803 53.1 C123 S 4 5 0 3 Allen, Mr. William Henry male 35 0 0 373450 8.05 NaN S
  • 36. Seaborn 박스 플롯 #기관코드별 정상(APPROVAL)/거절(REJECT) 처리시간 분포 시각화 df = pd.read_csv('trns_msg_log/trns_msg_log', sep=':', dtype=str) #거래 로그 DataFrame s_df = df[df.TRNS == '1'] #SEND 거래 r_df = df[df.TRNS == '2'] #RECV 거래 tf = pd.merge(s_df, r_df, on=['FIRM_CODE','SEQ']) tf['APPROVAL'] = tf.RESP_CODE_y.isin(['00','01']) #정상 여부 # SEND와 RECV 전문 처리시간 tf['S_DATETIME'] = pd.to_datetime(tf.TIME_x, format='%H%M%S') tf['R_DATETIME'] = pd.to_datetime(tf.TIME_y, format='%H%M%S') tf['TIME_GAP'] = tf.R_DATETIME - tf.S_DATETIME tf['TIME_GAP'] = tf.TIME_GAP.dt.seconds #시간을 초 단위 정수로 변환 #승인/거절 카테고리 기준으로, 기관별 처리시간 분포 sns.boxplot(x='FIRM_CODE', y='TIME_GAP', hue='APPROVAL', data=tf)
  • 37. Seaborn 회귀분석 그래프 • lmplot() 메소드를 이용하여 회귀분석 판별 • hue 옵션 사용을 통해 기준을 세분화 하여 시각화 가능 df = pd.read_csv('titanic.csv', sep='t') #나이별 운임료 회귀분석 sns.lmplot(x='Age',y='Fare', data=df) #생존여부 기준으로 나이별 운임료 회귀분석 sns.lmplot(x='Age',y='Fare', hue='Survived', data=df)
  • 38. Seaborn 회귀분석 그래프 • tips 데이터셋을 이용하여 전체 지불금액(total_bill)과 팁(tip) 상관관계 분석 df = sns.load_dataset('tips') df.head() #생별 기준으로 전체 지불금액과 팀의 상관관계 회귀분석 sns.lmplot(x='total_bill', y='tip', hue='sex', data=df) hue ='smoker'로 했을 경우 total_bill tip sex smoker day time size 0 16.99 1.01 Female No Sun Dinner 2 1 10.34 1.66 Male No Sun Dinner 3 2 21.01 3.5 Male No Sun Dinner 3 3 23.68 3.31 Male No Sun Dinner 2 4 24.59 3.61 Female No Sun Dinner 4
  • 39. Seaborn 히트맵(Heatmap) • 두 개의 카테고리에 해당되는 값의 변화와 분포를 나타낼 때 유리 • DataFrame에서 인덱스와 칼럼이 카테고리 값이 됨 • DataFrame 이용 시 pivot(index, columns, values) 메소드를 이용하여 변조 필요 df = pd.read_csv('titanic.csv', sep='t') #생존자 기준으로 Age, Sex, Fare를 그룹화하여 건수를 추출 tf = df[df.Survived==1].groupby(['Age','Sex','Fare']).count().reset_index() tf = tf[['Age','Sex','Fare','Pclass']] tf = tf.rename(columns={'Pclass':'Count'}) zf = tf.pivot('Age','Fare', 'Count').fillna(0) sns.heatmap(zf) # 연령, 운임에 따른 승객수 현황 Age Sex Fare Count 0 0.83 male 29 1 1 3 female 41.5792 1 2 4 female 16.7 1 3 5 female 27.75 1 4 12 male 11.2417 1
  • 40. Seaborn 히트맵(Heatmap) • df.pivot()의 경우 중복이나 값이 없을 때 아래 에러가 발생 ValueError: Index contains duplicate entries, cannot reshape • pd.pivot_table의 경우는 index의 중복이 있어도 해결 가능 • pd.pivot_table의 경우 aggfunc 옵션이 제공되어 np.sum, np.mean 등 그룹함수 사용 가능 df = pd.read_csv('titanic.csv', sep='t') tf = df.groupby(['Age','Sex','Survived']).count().reset_index().rename(columns={'Pclass':'Count'}) tf = tf[['Age','Sex','Survived','Count']] # 좌측 인덱스가 Age(연령), 상단 칼럼은 Survived(생존여부)로 한 사람수를 나타내는 DataFrame으로 변조 zf = pd.pivot_table(tf,index='Age',columns='Survived',values='Count', aggfunc=np.sum).fillna(0) sns.heatmap(zf) pd.pivot_table(index='Sex', columns='Survived', values='Count', aggfunc=np.sum)
  • 41. 대한민국 지도 시각화 SVG 기반 지도 시각화 • 웹 SVG 태그 기반으로 대한민국 지도상의 시각화 방법 • SVG 태그 요소에 접근하여 색상을 변경하는 방식 • BeautifulSoup4 이용 (pip install bs4) • south-korea.svg 지역명으로 접근 용이하게 수정해놨음 (https://github.com/sh2orc/datascience) from IPython.display import SVG # jupyter에서 SVG 출력용 from bs4 import BeautifulSoup as bs # SVG 태그 접근 : beautifulsoup map_south_svg = None with open('south-korea.svg','r', encoding='utf-8') as f: map_south_svg = f.read() <svg> <path id="광역시/도명" fill="#도형색깔" stroke="#윤곽선색깔" /> </svg> south-korea.svg 구조
  • 42. SVG(soup.prettify()) #출력 p = soup.find('path',{'id':'경기도'}) p['fill'] = '#ff2277' # 태그 fill 속성 = 핑크색 p = soup.find('path',{'id':'인천광역시'}) p['fill'] = '#22ff77' # 태그 fill 속성 = 연두색 대한민국 지도 시각화 SVG 기반 지도 시각화 • soup.find 함수를 통해 특정 태그에 접근 가능 • 태그마다 id별 지역명을 세팅해놨으므로 한글로 접근 가능 soup.select('svg > path[id]')[0].attrs['id'] #svg 태그 하위 path 태그(id 속성을 가진)를 모두 선택 '서울특별시' p = soup.find('path',{'id':'서울특별시'}) p['fill'] = '#2277ff' #태그 fill 속성 = 청색
  • 43. 대한민국 지도 시각화 서울시 구 단위 시각화 map_seoul = None with open('seoul-district.svg', 'r', encoding='utf-8') as f: map_seoul = f.read() soup = bs(map_seoul) p = soup.find('path', {'id' : '영등포구' }) p['fill'] = '#99cc33' SVG(soup.prettify()) • seoul-district.svg 지역구명으로 접근이 가능 확인 • BeautifulSoup 이용하여 영등포구 색상 변경 (테스트용)
  • 44. 대한민국 지도 시각화 CairoSVG를 이용한 이미지로 변환 (Windows) • cairosvg 파이썬 라이브러리 설치 (pip install cairosvg) • Uniconvertor 2.0 설치 (https://sk1project.net/uc2/download/) • [시스템속성 - 환경변수 - 시스템변수 - Path] Uniconvertor의 dll 패스 추가 C:Program FilesUniConvertor-2.0rc4dlls
  • 45. 대한민국 지도 시각화 CairoSVG를 이용한 이미지로 변환 (Windows) import io from PIL import Image import cairosvg in_mem = io.BytesIO() #메모리 버퍼 cairosvg.svg2png(bytestring=soup.select('svg')[0].encode('utf-8'), write_to=in_mem) img = Image.open(in_mem) # img 객체로 저장 (notebook에서 img 변수 직접 확인 가능) img.save('seoul-img.png') #파일명으로 저장 • cairosvg.svg2png (bytestring=, write_to= )로 사용 • write_to= 문자로 입력 시 해당 파일명로 저장됨, 파일명이 아닌 ByteIO 객체 입력시 해당 객체로 저장 • bytestring= 에는 svg 태그 하위 내용이 입력되며 문자열은 byte로 변환 필수 • 이미지 프로세싱을 하기 위해서는 Pillow(PIL)의 Image 객체로 변환 필요
  • 47. 코스피 종목 기술 분석 LG유플러스 일별 종가 기준 분석 • 네이버 주식에서 LG유플러스(032640) 주가 스크래핑 • BeautifulSoup 라이브러리를 이용한 테이블 파싱 • 종목코드는 네이버 주가에서 종목명 옆에 나오는 값 • 기술적 분석은 가격에 모든 정보가 반영되어있다는 가정으로 진행 import pandas as pd from bs4 import BeautifulSoup as bs def scrap_page(code, page): url = f'http://finance.naver.com/item/sise_day.nhn?code={code}&page={page}' res = requests.get(url) soup = BeautifulSoup(res.text, 'lxml') df = pd.read_html(str(soup.find('table')), header=0)[0] df = df.dropna() return df
  • 48. 코스피 종목 기술 분석 LG유플러스 일별 종가 기준 분석 • scrap_page 함수 리턴되는 DataFrame는 함수 .append 이용하여 연결 • 스크래핑이 어려운 경우 LGU_190530_200729 파일 pd.read_csv 이용 import matplotlib.pyplot as plt df = pd.DataFrame() for i in range(1,30): df = df.append( scrap_page('032640', i) ) df.sort_values('날짜', inplace=True) fig = plt.figure( figsize=(20,10) ) ax = plt.subplot(111) ax.plot(df['날짜'], df['종가']) plt.show() 차트 출력은 되나 xticks가 너무 많이 나타남
  • 49. 코스피 종목 기술 분석 LG유플러스 일별 종가 기준 분석 • x축 tick 값들이 너무 많이 나타나서 xticks를 제거하는 방법 • ax.xticks([]) : axes 빈 리스트를 입력하면 x축 표시 값 삭제 fig = plt.figure( figsize=(20,10) ) ax = plt.subplot(111) ax.plot(df['날짜'], df['종가']) ax.xticks([]) # 차트에서 x-ticks 제거 plt.show()
  • 50. 코스피 종목 기술 분석 LG유플러스 일별 종가 기준 분석 • x축 tick 값들 중 특정 값만 나타나게 할 수 있다. • ax.xticks(['표시할축값', ]) : tick 리스트에 표시할 대상 값을 지정하면 해당 값에 대한 표시 가능 fig = plt.figure( figsize=(20,10) ) ax = plt.subplot(111) ax.plot(df['날짜'], df['종가']) ax.xticks(['2020.07.01','2020.07.17']) plt.show()
  • 51. 코스피 종목 기술 분석 LG유플러스 일별 종가 기준 분석 • ax.xticks(['표시할축값', ]) : tick 리스트에 표시할 대상 값을 지정하면 해당 값에 대한 표시 가능 • ax.xaxis.set_major_locator를 이용하여 표시 단위를 조정 가능 import matplotlib.ticker as ticker fig = plt.figure( figsize=(20,10) ) ax = plt.subplot(111) ax.xaxis.set_major_locator(ticker.MultipleLocator(30)) #표시 단위를 30개(일)로 표시 ax.plot(df['날짜'], df['종가']) plt.show()
  • 52. 코스피 종목 기술 분석 LG유플러스 일별 종가 기준 분석 • np.polyfit(x, y, 다항차수)를 통해 계수를 추출하고, np.poly1d(계수)를 이용하여 회귀식을 도출 • 일별 종가에 대한 회귀분석값을 만들어서 회귀분석선을 표현 import numpy as np fig = plt.figure( figsize=(20,10) ) ax = plt.subplot(111) fp = np.polyfit(df.index, df.종가, 1) fx = np.poly1d(fp) df['회귀분석'] = fx(df.index) ax.plot(df['날짜'], df['종가']) ax.plot(df['날짜'], df['회귀분석']) ax.legend(['LG유플러스']) plt.xticks(['2019.05.30','2019.12.27','2020.03.13', '2020.06.01', '2020.07.17']) plt.show()
  • 53. 코스피 종목 기술 분석 LG유플러스 일별 종가 기준 분석 • 2020.03.13 코로나-19 폭락장 이후 회귀분석선 fp = np.polyfit(df.index, df.종가, 1) fx = np.poly1d(fp) df['회귀분석'] = fx(df.index) ax.plot(df['날짜'], df['종가']) ax.plot(df['날짜'], df['회귀분석']) ax.set_title('LG유플러스') tf = df[df.날짜 > '2020.03.13'] tf = tf.reset_index() fp = np.polyfit(tf.index, tf.종가, 1) fx = np.poly1d(fp) tf['회귀분석'] = fx(tf.index) ax.plot(tf['날짜'], tf['회귀분석']) ax.legend(['종가', '회귀분석(전체)', '회귀분석(폭락이후)']) plt.show()
  • 54. 코스피 종목 기술 분석 LG유플러스 일별 종가 기준 분석 • seaborn을 이용한 회귀분석 lmplot( x=, y=, data=) 이용 • lmplot을 이용하면 편리하게 현황이 분석 가능하지만 적용된 회귀식을 알 수 없다 • x=, y= 으로 지정되는 pandas의 컬럼은 실수가 되어야 하므로 x축을 index(숫자)로 지정 tf = df[df.날짜 > '2020.03.13'] #코로나 폭락장 이후 데이터 tf = tf.reset_index() #index를 초기화 & 컬럼 'index'로 생성 (회귀분석 계산 위해) ax = sns.lmplot(x='index', y='종가', data=tf) # 사이즈 조절 방법 aspect=2, height=5 ax.set_xticklabels(tf.날짜)
  • 55. 코스피 종목 기술 분석 LG유플러스 일별 종가 기준 분석 • 3월 13일 이후 상승, 하락한 날짜를 대상으로 분류(카테고리) 후 각각의 회귀분석 • 전일비 컬럼 값이 존재하나 전일 대비 상승(+), 하락(-) 기호가 없으므로 계산 필요 #tf['전일종가'] = tf.종가.shift(1) # 종가 Series를 요소를 shift 이동 tf['전일대비증감'] = tf['종가'] - tf['전일종가'] tf['전일대비증감'].fillna(0, inplace=True) tf['증가여부'] = tf.전일대비증감.apply(lambda x : '상승' if x>=0 else '하락') sns.lmplot(x='index',y='종가', data=tf, hue='증가여부', aspect=2, height=5)
  • 56. 서울시 대기 오염 분석 미세먼지 상관 관계 분석 • 2018년 기준 지역구별 미세먼지, 이산화질소농도, 오존농도, 이산화탄소농도, 아황산가스 등 • 출처 : 서울시 열린데이터 https://data.seoul.go.kr/dataList/OA-2218/S/1/datasetView.do import pandas as pd import seaborn as sns # seaborn의 상관관계 분석차트 이용 위해 from matplotlib import rcParams rcParams['font.family'] = 'Malgun Gothic' # 폰트 맑은고딕 지정 %matplotlib inline df = pd.read_csv('일별평균대기오염도_2018.csv') 측정일시 측정소명 이산화질소농도 (ppm) 오존농도(ppm) 이산화탄소농도 (ppm) 아황산가스(pp m) 미세먼지(㎍/㎥) 초미세먼지(㎍/ ㎥) 20180101 강남구 0.033 0.010 0.6 0.006 34.0 22.0 20180101 강남대로 0.040 0.007 0.8 0.006 NaN 17.0 20180101 강동구 0.038 0.010 0.7 0.005 48.0 24.0 20180101 강변북로 0.033 0.008 0.6 0.005 48.0 15.0 20180101 강북구 0.026 0.018 0.6 0.004 38.0 18.0
  • 57. 서울시 대기 오염 분석 미세먼지 상관 관계 분석 (joinplot) • sns.jointplot을 이용하면 2개의 데이터 종류를 서로 상대적 분석을 할 때 용이 • 실수로 구성된 경우에 사용하며 sns.joinplot(x=, y=, )에서 각각 값을 지정 • sns.joinplot(kind=) 옵션으로 'scatter', 'hex' 등 존재 sns.jointplot(df['미세먼지'], df['초미세먼지'], kind='hex') sns.jointplot(df['미세먼지'], df['이산화질소농도'], kind='hex')
  • 58. 서울시 대기 오염 분석 미세먼지 상관 관계 분석 (pairplot) • 컬럼명 클린징 후 월단위 측정소 기준 컬럼별 평균 • sns.pairplot을 이용하면 데이터 상관계수를 확인 가능 df.columns = [ col.split('(')[0] for col in df.columns ] #컬럼명 클린징 ( ) 포함 제거 df['년월'] = df.측정일시.apply(lambda x : str(x)[:6]) tf = df.groupby(['년월', '측정소명']).mean() tf = tf.drop(columns='측정일시') #회귀분석 kind='reg' sns.pairplot(tf, kind='reg', size=2)
  • 59. 서울시 대기 오염 분석 미세먼지 상관 관계 분석 (pairplot) • sns.pairplot(hue= ) 옵션에 카테고리화된 데이터를 지정하면 해당 기준으로 상관관계 분석 • 대기상태를 미세먼지 기준으로 좋음, 보통, 나쁨, 매우나쁨으로 카테고리화 가능 - 미세먼지㎍/㎥ 기준 : 좋음(0~15), 보통(16~35), 나쁨(36~75), 매우나쁨(76~) tf['미세먼지'] = tf.미세먼지.fillna(method='bfill') #NaN 값이 있을 경우 직전 값으로 채움 tf['미세먼지_정규'] = tf.미세먼지.apply(lambda x:round(x)) #실수를 반올림하여 정수로 변경 tf['대기상태'] = tf.미세먼지_정규.apply(lambda x: '좋음' if x in range(0, 16) else '보통' if x in range(16,36) else '나쁨' if x in range(36,76) else '매우나쁨' ) tf.loc['201809'] 이산화질소농도 오존농도 이산화탄소농도 아황산가스 미세먼지 초미세먼지 미세먼지상태 미세먼지_정규 측정소명 강남구 0.023500 0.019533 0.363333 0.004833 16.166667 7.366667 보통 16 강남대로 0.034100 0.015069 0.453333 0.003533 24.700000 12.300000 보통 25 강동구 0.019800 0.023967 0.376667 0.003533 22.900000 9.133333 보통 23 강변북로 0.030600 0.018833 0.446667 0.003200 24.933333 10.700000 보통 25 강북구 0.012433 0.031033 0.326667 0.002200 16.266667 7.700000 보통 16 강서구 0.021233 0.029200 0.350000 0.002567 17.866667 9.100000 보통 18 공항대로 0.036433 0.017200 0.473333 0.007000 26.033333 12.366667 보통 26
  • 60. 서울시 대기 오염 분석 미세먼지 상관 관계 분석 (pairplot) sns.pairplot(tf, kind='reg', hue='대기상태', size=2)
  • 61. 서울시 대기 오염 분석 미세먼지 상관 관계 분석 (pairplot) • sns.pairplot(x_var=, y_var= ) 옵션에 각각 기준을 지정하면 특정 데이터들에 대한 상관관계 분석 가능 • [미세먼지, 초미세먼지]와 [이산화질소농도, 아황산가스]의 상관관계 분석 - 이미 각 데이터별 대기상태를 카테고리화 시켜놓았으니 유의미한 데이터 분석 가능 sns.pairplot(tf, x_vars=['미세먼지', '초미세먼지'], y_vars=['이산화질소농도', '아황산가스'], hue='대기상태', kind='reg')
  • 62. 서울시 대기 오염 분석 미세먼지 월별 현황 분석 (heatmap) • sns.headtmap()을 이용할 때 X축과 Y축을 이루는 데이터셋을 어떤 기준으로 정할지 중요 • X축을 년월, Y축을 측정소명, 표현 데이터를 미세먼지로 하여 미세먼지의 변화를 보고자 함 tf 이산화질소농도 오존농도 이산화탄소농도 아황산가스 미세먼지 초미세먼지 미세먼지_정규 대기상태 년월 측정소명 201801 강남구 0.036387 0.009355 0.603226 0.005871 42.548387 32.903226 43 나쁨 강남대로 0.058452 0.007677 0.838710 0.005484 63.566667 25.258065 64 나쁨 강동구 0.038613 0.012742 0.690323 0.005065 56.354839 35.064516 56 나쁨 강변북로 0.036065 0.009258 0.690323 0.005774 54.129032 21.064516 54 나쁨 강북구 0.030548 0.020419 0.612903 0.004903 46.806452 25.612903 47 나쁨 ... ... ... ... ... ... ... ... ... ... • 미세먼지 데이터만 필요하고, DataFrame을 인덱스는 년월, 컬럼을 측정소명으로 변경 tf[['미세먼지']].unstack() 미세먼지 측정소명 강남구 강남대로 강동구 강변북로 강북구 ... 종로 종로구 중구 중랑구 천호대로 행주 홍릉로 화랑로 년월 201801 42.548387 63.566667 56.354839 54.129032 46.806452 ... 41.689655 44.774194 44.516129 54.709677 62.580645 NaN 52.903226 49.935484 201802 50.037037 65.074074 59.555556 60.925926 49.666667 ... 47.925926 46.333333 45.777778 49.000000 63.037037 NaN 56.259259 53.962963 201803 37.100000 51.800000 44.950000 47.300000 36.800000 ... 34.600000 35.700000 34.850000 35.900000 52.700000 NaN 46.450000 44.550000
  • 63. 서울시 대기 오염 분석 미세먼지 월별 현황 분석 (heatmap) • 컬럼은 레벨 2의 멀티컬럼으로 되어있으므로 미세먼지 헤더 제거 후 측정소명만 사용하도록 변경 tf = tf[['미세먼지']].unstack() tf.columns MultiIndex([('미세먼지', '강남구'), ('미세먼지', '강남대로'), ('미세먼지', '강동구'), ('미세먼지', '강변북로'), ...... tf.columns = [ col[1] for col in tf.columns ] 강남구 강남대로 강동구 강변북로 ... 한강대로 행주 홍릉로 화랑로 년월 201801 42.548387 63.566667 56.354839 54.129032 ... 58.354839 NaN 52.903226 49.935484 201802 50.037037 65.074074 59.555556 60.925926 ... 63.407407 NaN 56.259259 53.962963 201803 37.100000 51.800000 44.950000 47.300000 ... 51.800000 NaN 46.450000 44.550000 201804 44.380952 58.333333 60.571429 58.285714 ... 60.523810 NaN 59.142857 54.476190 201805 33.000000 43.523810 41.857143 48.285714 ... 51.666667 NaN 47.047619 40.333333 201806 42.285714 48.000000 51.857143 58.000000 ... 64.571429 NaN 58.857143 48.000000 201807 21.586207 24.448276 30.517241 27.103448 ... 36.206897 NaN 33.551724 33.350000
  • 64. 서울시 대기 오염 분석 미세먼지 월별 현황 분석 (heatmap) • heatmap 출력 분석 : 미세먼지가 7~10월까지는 보통 이하를 유지 plt.figure(figsize=(30,15)) sns.heatmap(tf)
  • 65. 서울시 대기 오염 분석 미세먼지 월별 현황 분석 (heatmap) • heatmap 텍스트 표시하려면 annot= 옵션 사용 및 fmt= 옵션으로 출력 포멧 지정 sns.heatmap(tf, annot=True, fmt='.0f')
  • 66. 행정구역별 인구 변화 분석 SVG 기반 대한민국 지도 시각화 • 레벨 1과정에서 다뤘던 행정구역별 인구 변화 데이터 셋 이용 from IPython.display import SVG # jupyter에서 SVG 출력용 from bs4 import BeautifulSoup as bs # SVG 태그 접근 : beautifulsoup import pandas as pd # matplotlib로 시각화 df = pd.read_csv('행정구역_시군구_시계열_인구변화', header=[0,1], index_col=0, dtype=str) 전국 서울특별시 부산광역시 ... 제주특별자치도 총인구수 남자인구수 여자인구수 총인구수 남자인구수 여자인구수 총인구수 남자인구수 여자인구수 ... 총인구수 남자인구수 여자인구수 2011.01 50534731 25318961 25215770 10312835 5110837 5201998 3566560 1772383 1794177 ... 571468 285659 285809 2011.02 50555262 25328299 25226963 10314245 5110818 5203427 3566480 1772175 1794305 ... 571913 285883 286030 2011.03 50575130 25337290 25237840 10307783 5107011 5200772 3564873 1770952 1793921 ... 572447 286152 286295 2011.04 50594424 25346019 25248405 10301829 5103919 5197910 3563042 1769903 1793139 ... 572918 286424 286494 2011.05 50613213 25354703 25258510 10295643 5100399 5195244 3562985 1769690 1793295 ... 573459 286668 286791 ... ... ... ... ... ... ... ... ... ... ... ... ... ... 2020.01 51847509 25862863 25984646 9733509 4745088 4988421 3411819 1674202 1737617 ... 670749 337231 333518
  • 67. 행정구역별 인구 변화 분석 총 인구수 기준 변화 값 계산 • 지역별 2011년1월 - 2020년5월 인구변화 수치 • 컬럼에서 전국은 제외하고 각 지역별 총인구수의 차이 계산 import numpy as np state_arr = np.unique([col[0] for col in df.columns if col[0] !='전국']) array(['강원도', '경기도', '경상남도', '경상북도', '광주광역시', '대구광역시', '대전광역시', '부산광역시', '서울특별시', '세종특별자치시', '울산광역시', '인천광역시', '전라남도', '전라북도', '제주특별자치도', '충청남도', '충청북도'], dtype='<U7') people_dict = {} for state in state_arr: #s = 강원도, 경기도, ...., 충청북도 people_201101 = df.loc[2011.01][state]['총인구수'] people_202005 = df.loc[2020.05][state]['총인구수'] diff_people = int(people_202005) - int(people_201101) people_dict[state]= [int(people_201101), int(people_202005), diff_people]
  • 68. 행정구역별 인구 변화 분석 총 인구수 기준 변화 값 계산 • people_dict는 지역명을 key 가지는 딕셔너리 객체, key 당 3개의 요소로 구성된 배열 df = pd.DataFrame.from_dict(people_dict, orient='index', columns=['2019_05','2020_05','변화인구수']) {'강원도': [1528790, 1538639, 9849], '경기도': [11801232, 13324041, 1522809], '경상남도': [3291435, 3351347, 59912], '경상북도': [2688586, 2648760, -39826], '광주광역시': [1456308, 1455533, -775], '대구광역시': [2512071, 2429059, -83012], '대전광역시': [1504617, 1471915, -32702], ......} 2011_01 2020_05 변화인구수 강원도 1528790 1538639 9849 경기도 11801232 13324041 1522809 경상남도 3291435 3351347 59912 경상북도 2688586 2648760 -39826 광주광역시 1456308 1455533 -775 대구광역시 2512071 2429059 -83012 대전광역시 1504617 1471915 -32702 부산광역시 3566560 3406942 -159618 서울특별시 10312835 9724496 -588339 세종특별자치시 0 345373 345373 ..... ..... ..... .....
  • 69. 행정구역별 인구 변화 분석 총 인구수 기준 변화 값 계산 • 인구변화율 계산을 해보면 세종특별시 같이 폭증한 값이 존재. *이를 Outlier라고 함. • 상대적 비교와 같이 구분 지을 때 너무 값이 차이나면 이를 줄이기 위한 정규화가 필요 df['인구변화율'] = (df['2020_05'] - df['2011_01']) / df['2020_05'] * 100 2011_01 2020_05 변화인구수 인구변화율 강원도 1528790 1538639 9849 0.640111 경기도 11801232 13324041 1522809 11.429033 경상남도 3291435 3351347 59912 1.787699 경상북도 2688586 2648760 -39826 -1.503571 광주광역시 1456308 1455533 -775 -0.053245 대구광역시 2512071 2429059 -83012 -3.417455 대전광역시 1504617 1471915 -32702 -2.221732 부산광역시 3566560 3406942 -159618 -4.685081 서울특별시 10312835 9724496 -588339 -6.050072 세종특별자치시 0 345373 345373 100.000000 울산광역시 1127337 1143148 15811 1.383110 인천광역시 2761122 2950063 188941 6.404643 전라남도 1916912 1855945 -60967 -3.284957 전라북도 1868745 1810097 -58648 -3.240047 제주특별자치도 571468 670793 99325 14.807101 충청남도 2076239 2118510 42271 1.995317 충청북도 1550474 1596710 46236 2.895704
  • 70. 행정구역별 인구 변화 분석 DataFrame quantile 이용한 임계치 기반 정규화 • pandas의 quantile 함수를 통해 백분위 수를 구할 수 있음 • 94% 백분위 값을 초과하는 Outlier 값은 치환하여 조정 limit = df['인구변화율'].quantile(0.94) # 94% 해당하는 값 df['인구변화율_정규'] = df['인구변화율'].apply(lambda x : limit if x > limit else x) 2011_01 2020_05 변화인구수 인구변화율 인구변화율_정규 강원도 1528790 1538639 9849 0.640111 0.640111 경기도 11801232 13324041 1522809 11.429033 11.429033 경상남도 3291435 3351347 59912 1.787699 1.787699 경상북도 2688586 2648760 -39826 -1.503571 -1.503571 광주광역시 1456308 1455533 -775 -0.053245 -0.053245 대구광역시 2512071 2429059 -83012 -3.417455 -3.417455 대전광역시 1504617 1471915 -32702 -2.221732 -2.221732 부산광역시 3566560 3406942 -159618 -4.685081 -4.685081 서울특별시 10312835 9724496 -588339 -6.050072 -6.050072 세종특별자치시 0 345373 345373 100.000000 18.214817 울산광역시 1127337 1143148 15811 1.383110 1.383110 인천광역시 2761122 2950063 188941 6.404643 6.404643 전라남도 1916912 1855945 -60967 -3.284957 -3.284957 전라북도 1868745 1810097 -58648 -3.240047 -3.240047 제주특별자치도 571468 670793 99325 14.807101 14.807101 충청남도 2076239 2118510 42271 1.995317 1.995317 충청북도 1550474 1596710 46236 2.895704 2.895704
  • 71. 행정구역별 인구 변화 분석 히스토그램과 pd.cut을 이용한 카테고라이즈 • 값들의 도수 분포 현황을 확인하고자 할 때 히스토그램을 활용 • 히스토그램을 확인하는 방법 : matplotlib.pyplot.hist (그래프 시각화) fig = plt.figure() ax1 = fig.add_subplot(211) #2행 1열 1번 ax2 = fig.add_subplot(212) #2행 1열 2번 #bins = 도수분포구간(7개) ax1.hist(df['인구변화율'], bins=7) ax1.legend(['인구변화율']) # bins = 도수분포구간(7개) ax2.hist(df['인구변화율_정규'], bins=7) ax2.legend(['인구변화율_정규']) plt.show()
  • 72. 행정구역별 인구 변화 분석 히스토그램과 pd.cut을 이용한 카테고라이즈 • np.histogram을 이용하여 도수 분포 현황 추출 • 분포시킬 구간의 개수(bins), 각 구간별 분포된 개수(counts), 분포를 결정하는 경계값들(bins_edges) • counts, bins_edges = np.histogram(x, bins=7) np.histogram(df['인구변화율'], bins=7) # 정규화가 안 되어있으니 첫번째 구간에 14개 몰림 np.histogram(df['인구변화율_정규'], bins=7) # Outlier를 조정 후 분포 형성 (array([5, 4, 4, 1, 0, 1, 2], dtype=int64), array([-6.0500719 , -2.58365915, 0.88275361, 4.34916637, 7.81557912, 11.28199188, 14.74840463, 18.21481739])) (array([14, 2, 0, 0, 0, 0, 1], dtype=int64), array([ -6.0500719 , 9.09993837, 24.24994864, 39.39995891, 54.54996919, 69.69997946, 84.84998973, 100. ]))
  • 73. 행정구역별 인구 변화 분석 히스토그램과 pd.cut을 이용한 카테고라이즈 • pd.cut(x=데이터, bins=[경계값들, ], labels=[경계값 기준의 레이블링 값들,], include_lowest=True) • bins 옵션에는 np.histogram으로 추출된 경계값 리스트를 입력 • labels 옵션에는 분포 구간에 대한 레이블 값 (입력이 없으면 분포 구간의 경계값 MIN, MAX 값으로 태깅) bin_labels = [ i for i in range(7) ] pd.cut(x=df['인구변화율_정규'], bins=bin_edges, labels=bin_labels, include_lowest=True) 강원도 1 경기도 5 경상남도 2 경상북도 1 광주광역시 1 대구광역시 0 대전광역시 1 부산광역시 0 서울특별시 0 세종특별자치시 6 울산광역시 2 인천광역시 3 전라남도 0 전라북도 0 제주특별자치도 6 충청남도 2 충청북도 2 Name: 인구변화율_정규, dtype: category Categories (7, int64): [0 < 1 < 2 < 3 < 4 < 5 < 6]
  • 74. 행정구역별 인구 변화 분석 SVG 기반 대한민국 지도 시각화 bin_labels = [ i for i in range(7) ] df['카테고리'] = pd.cut(x=df['인구변화율_정규'], bins=bin_edges, labels=bin_labels, include_lowest=True) color_list = ['#F50057','#FF40AB','#E1BEE7','#CE93D8','#BA68C8','#9C27B0','#6A1B9A'] # 광역시도명 기반 태그 추출 # 카테고리번호를 color_list 요소로 배경색 세팅 for name, row in df.iterrows(): p = soup.find('path', {'id': name } ) c = color_list[ row['카테고리'] ] p['fill'] = c SVG(soup.prettify())
  • 75. 서울시 아파트 현황 분석 지역별 아파트 개수 분석 • seoul-district.svg 구별명으로 접근 용이하게 수정함 (https://github.com/sh2orc/datascience) • 서울시 동별 정보, 아파트 세부 정보 출처 (부동산지인 https://aptgin.com) from IPython.display import SVG # jupyter에서 SVG 출력용 from bs4 import BeautifulSoup as bs # SVG 태그 접근 : beautifulsoup import pandas as pd df_dong = pd.read_csv('지인_동정보' , dtype=str) df_dong.head() CODE C_NAME DONG LAWD_APT_CNT_TO TAL NAME NAME2 NAME3 SIGUNGU STATE_NUM mcd 116801030 0 개포동 개포동 23.0 서울특별시 강남구 개포동 강남구 개포동 서울시 강남구 NaN 11680103 116801080 0 논현동 논현동 22.0 서울특별시 강남구 논현동 강남구 논현동 서울시 강남구 NaN 11680108 116801060 0 대치동 대치동 35.0 서울특별시 강남구 대치동 강남구 대치동 서울시 강남구 NaN 11680106 116801180 0 도곡동 도곡동 34.0 서울특별시 강남구 도곡동 강남구 도곡동 서울시 강남구 NaN 11680118 116801050 0 삼성동 삼성동 33.0 서울특별시 강남구 삼성동 강남구 삼성동 서울시 강남구 NaN 11680105
  • 76. 서울시 아파트 현황 분석 지역별 아파트 개수 분석 df_dong['LAWD_APT_CNT_TOTAL'] = df_dong.LAWD_APT_CNT_TOTAL.astype(float) tf = df_dong[df_dong.NAME3=='서울시'].groupby('SIGUNGU').sum() tf.columns = ['아파트수'] 아파트수 SIGUNGU 강남구 330.0 강동구 170.0 강북구 60.0 강서구 307.0 관악구 125.0 광진구 108.0 구로구 243.0 금천구 79.0 노원구 232.0 도봉구 130.0 동대문구 165.0 동작구 131.0 마포구 211.0 서대문구 126.0 서초구 263.0 .... .....
  • 77. 서울시 아파트 현황 분석 지역별 아파트 개수 분석 counts, bin_edges = np.histogram(tf['아파트수'], bins=10) bin_labels = list(range(10)) tf['카테고리'] = pd.cut(x=tf['아파트수'], bins=bin_edges, labels=bin_labels, include_lowest=True) color_map = ['#F9E79F', '#F4D03F', '#F5B041', '#F1C40F', '#EDBB99', '#F5B7B1', '#F1948A', '#EC7063', '#E74C3C', '#CB4335'] for name, row in tf.iterrows(): p = soup.find('path' ,{'id': name }) c = color_map[ row['카테고리'] ] p['fill'] = c SVG(soup.prettify()) • 히스토그램(np.histogram)을 이용한 pd.cut 기반 카테고라이즈
  • 78. 서울시 아파트 현황 분석 재건축 가능 아파트 분석 • 아파트 현황 데이터(지인_아파트단지)를 활용하여 동별 정보(지인_동정보) 데이터에 Merge df_apt = pd.read_csv('지인_아파트단지', dtype=str) bldg_nm house_cnt lawd_cd pk_apt_detail pk_apt_master pk_ent_master search_dt SH대치1단지아파트 1616 1168010300.0 73780 16965 0 1992.1 개포6차우성 270 1168010300.0 10218 2533 0 1987.11 개포메트하임(O/T) 102 1168010300.0 161078 40178 0 2018.12 개포우성3차 405 1168010300.0 10094 2501 0 1984.12 ... ... ... ... ... ... ... 화성발안엘에이치1단지 608 4159025900.0 275648 58358 0 2019.08 • 동별 정보(gin_dong)의 CODE 값과 lawd_cd 값이 같다는 것을 파악 가능 CODE C_NAME DONG LAWD_APT_CNT_TOTAL NAME NAME2 NAME3 SIGUNGU mcd 1168010300 개포동 개포동 23.0 서울특별시 강남구 개포동 강남구 개포동 서울시 강남구 11680103 1168010800 논현동 논현동 22.0 서울특별시 강남구 논현동 강남구 논현동 서울시 강남구 11680108 1168010600 대치동 대치동 35.0 서울특별시 강남구 대치동 강남구 대치동 서울시 강남구 11680106 1168011800 도곡동 도곡동 34.0 서울특별시 강남구 도곡동 강남구 도곡동 서울시 강남구 11680118 1168010500 삼성동 삼성동 33.0 서울특별시 강남구 삼성동 강남구 삼성동 서울시 강남구 11680105
  • 79. 서울시 아파트 현황 분석 재건축 가능 아파트 분석 • df_apt 데이터프레임의 lawd_cd 오른쪽 끝에 .0 같은 불필요한 값 제거 후 CODE 컬럼으로 할당 * read_csv( dtype=str )을 입력하지 df_apt['CODE'] = df_apt.lawd_cd.apply(lambda x : x.rstrip('0').rstrip('.')) bldg_nm house_cnt lawd_cd pk_apt_detail pk_apt_master pk_ent_master search_dt CODE SH대치1단지아파트 1616 1168010300.0 73780 16965 0 1992.1 1168010300 개포6차우성 270 1168010300.0 10218 2533 0 1987.11 1168010300 개포래미안포레스트 2296 1168010300.0 309876 64935 6181 2020.09 1168010300 개포메트하임(O/T) 102 1168010300.0 161078 40178 0 2018.12 1168010300 개포우성3차 405 1168010300.0 10094 2501 0 1984.12 1168010300 ... ... ... ... ... ... ... ... 트윈테라스타워(O/T) 814 4159025900.0 231596 53342 0 2019.01 4159025900 한우물마을_휴먼시아5단지 1150 4159025900.0 67148 15599 0 2009.11 4159025900 한우물마을_휴먼시아6단지 1330 4159025900.0 67158 15601 0 2009.11 4159025900 화성라일플로리스3차(O/T) 538 4159025900.0 127262 32931 0 2016.07 4159025900 화성발안엘에이치1단지 608 4159025900.0 275648 58358 0 2019.08 4159025900 • df_apt와 df_dong 데이터프레임을 Merge 후 서울시 아파트만 필터링 df = pd.merge(df_apt, df_dong, how='left', on='CODE') df = df[df.NAME3=='서울시']
  • 80. 서울시 아파트 현황 분석 재건축 가능 아파트 분석 • 2020년 12월 기준으로 30년 이상 된 아파트 추출 df[df.search_dt < '1990.12'] bldg_nm house_cnt pk_apt_detail pk_apt_master search_dt CODE C_NAME DONG ... NAME NAME2 NAME3 SIGUNGU mcd 개포6차우성 270 10218 2533 1987.11 1168010300 개포동 개포동 ... 서울특별시 강 남구 개포동 강남구 개포동 서울시 강남구 11680103 개포우성3차 405 10094 2501 1984.12 1168010300 개포동 개포동 ... 서울특별시 강 남구 개포동 강남구 개포동 서울시 강남구 11680103 개포주공1단 지 5040 39060 8961 1982.06 1168010300 개포동 개포동 ... 서울특별시 강 남구 개포동 강남구 개포동 서울시 강남구 11680103 개포주공5단 지 940 12523 3086 1983.1 1168010300 개포동 개포동 ... 서울특별시 강 남구 개포동 강남구 개포동 서울시 강남구 11680103 개포주공6단 지 1060 12606 3102 1983.1 1168010300 개포동 개포동 ... 서울특별시 강 남구 개포동 강남구 개포동 서울시 강남구 11680103 ... ... ... ... ... ... ... ... ... ... ... ... ... ... 한신 1362 35929 8354 1987.12 1126010100 면목동 면목동 ... 서울특별시 중 랑구 면목동 중랑구 면목동 서울시 중랑구 11260101 우성 189 211608 1626 1975.12 1126010400 묵동 묵동 ... 서울특별시 중 랑구 묵동 중랑구 묵동 서울시 중랑구 11260104 장미 100 17474 4372 1983.1 1126010400 묵동 묵동 ... 서울특별시 중 랑구 묵동 중랑구 묵동 서울시 중랑구 11260104 상봉오피스텔 (O/T) 133 378788 6872 1988.04 1126010200 상봉동 상봉동 ... 서울특별시 중 랑구 상봉동 중랑구 상봉동 서울시 중랑구 11260102 세광 210 365065 1628 1986.08 1126010300 중화동 중화동 ... 서울특별시 중 랑구 중화동 중랑구 중화동 서울시 중랑구 11260103 tf = df[df.search_dt < '1990.12']
  • 81. 서울시 아파트 현황 분석 재건축 가능 아파트 분석 • 2020년 12월 기준으로 30년 이상 된 아파트 추출 분석 tf['아파트수'] = 1 tf.groupby('SIGUNGU').sum().sort_values('아파트수',ascending=False) 아파트수 SIGUNGU 강남구 64 서초구 50 영등포구 47 노원구 44 송파구 42 구로구 37 강동구 30 도봉구 27 용산구 21 양천구 21 광진구 14 성동구 13 서대문구 13 관악구 12 강서구 11 마포구 10 금천구 10 동대문구 9 은평구 8 .... ....
  • 82. 서울시 아파트 현황 분석 재건축 가능 아파트 분석 • 2020년 12월 기준으로 30년 이상 된 아파트 추출 분석 tf = tf.groupby('SIGUNGU').sum().sort_values('아파트수',ascending=False) counts, bin_edges = np.histogram(tf['아파트수'], bins=10) bin_labels = list(range(10)) tf['카테고리'] = pd.cut(x=tf['아파트수'], bins=bin_edges, labels=bin_labels, include_lowest=True) for name, row in tf.iterrows(): p = soup.find('path', {'id': name }) c = color_map[ row['카테고리'] ] p['fill'] = c SVG(soup.prettify())
  • 83. 강남구 매매 실거래 분석 동별 아파트 평균 매매 변화 분석 • 아파트 단지 하위 아파트 세부 구조별 정보 df_apt_detail = pd.read_csv('지인_아파트단지세부') bldg_nm lawd_cd ... contract_extent reside_public_nm private_main_cd_n m reside_public_rep_ extent SH대치1단지아파트 1168010300 ... 36.250 복도계단 아파트 8.810 SH대치1단지아파트 1168010300 ... 36.360 복도계단 아파트 8.810 SH대치1단지아파트 1168010300 ... 46.580 복도계단 아파트 9.620 SH대치1단지아파트 1168010300 ... 56.720 복도계단 아파트 13.090 흥덕마을_경남아너 스빌13단지 4146311100 ... 203.023 계단실,승강기,벽체 아파트 29.488 df_apt_sale = pd.read_csv('지인_아파트_매매') • 세부 구조별 매매 거래내역 현황 price_c price yyyymm pk_apt_detail 42,000 (130동 11층) 42000 2017-12-08 19517 39,000 (130동 0층) 39000 2017-12-12 19517 42,000 (130동 0층) 42000 2017-12-28 19517 40,000 (130동 0층) 40000 2018-01-18 19517 40,000 (130동 17층) 40000 2018-01-26 19517
  • 84. • df_dong 데이터프레임에서 [지역코드, '동이름', '시군구'] 정보로 '강남구'만 추출 • df_apt_detail (아파트 세부정보)에서 '아파트'만 추출 • Inner Join을 통해 강남구 하위 아파트로 병합 tf_dong = df_dong[['CODE','DONG','SIGUNGU']] tf_dong = tf_dong[tf_dong.SIGUNGU=='강남구'] tf_apt_detail = df_apt_detail[df_apt_detail.private_main_cd_nm=='아파트'] 강남아파트 = pd.merge( tf_apt_detail, tf_dong, left_on='lawd_cd', right_on='CODE') 강남아파트 = 강남아파트[['bldg_nm','CODE','DONG','contract_extent','pk_apt_detail']] bldg_nm CODE DONG contract_extent pk_apt_detail SH대치1단지아파트 1168010300 개포동 36.25 73780.0 SH대치1단지아파트 1168010300 개포동 36.36 73781.0 SH대치1단지아파트 1168010300 개포동 46.58 73782.0 ... ... ... ... ... 한보미도맨션1차,2차 1168010600 대치동 0.00 177997.0 한보미도맨션1차,2차 1168010600 대치동 0.00 177998.0 현대 1168010600 대치동 104.78 16701.0 현대 1168010600 대치동 105.58 16702.0 강남구 매매 실거래 분석 동별 아파트 평균 매매 변화 분석
  • 85. • 강남아파트와 실거래 매매가를 Join 후 NULL 값 대상 제거 • 날짜컬럼은 yyyymm에 년월일 데이터로 존재하므로 조정 필요 • 크기기준 (소형, 중형, 대형)으로 구분하는 데이터 카테고라이즈화 tf = pd.merge(강남아파트, df_apt_sale, on='pk_apt_detail') tf = tf.dropna() tf['yyyymmdd'] = tf.yyyymm tf['yyyymm'] = tf.yyyymmdd.apply(lambda x:x[:7]) tf['크기기준'] =tf.contract_extent.apply(lambda x: '소형' if x <= 60 else '중형' if x > 60 and x <= 85 else '대형' ) bldg_nm CODE DONG contract_extent pk_apt_detail price yyyymm yyyymmdd 크기기준 경남1 1168010300 개포동 97.92 29856.0 195000 2020-03 2020-03-05 대형 경남1 1168010300 개포동 97.92 29856.0 190000 2020-04 2020-04-01 대형 ... ... ... ... ... ... ... ... ... 현대 1168010600 대치동 104.78 16701.0 198000 2020-07 2020-07-28 대형 현대 1168010600 대치동 105.58 16702.0 150000 2019-05 2019-05-10 대형 현대 1168010600 대치동 105.58 16702.0 145000 2019-05 2019-05-10 대형 현대 1168010600 대치동 105.58 16702.0 155000 2019-07 2019-07-02 대형 현대 1168010600 대치동 105.58 16702.0 220000 2019-12 2019-12-15 대형 강남구 매매 실거래 분석 동별 아파트 평균 매매 변화 분석
  • 86. • 개별 데이터에 대해 소형, 중형, 대형으로 카테고라이즈화가 끝났고, 수치 데이터인 매매가 존재 • seaborn boxplot을 이용하여 동별 매매가 변동폭을 확인 가능 import seaborn as sns sns.boxplot(data=tf, x='DONG', y='price', hue='크기기준') 강남구 매매 실거래 분석 동별 아파트 평균 매매 변화 분석
  • 87. • 삼성동 기준으로 아파트들의 매매가 변동폭 : x 좌표를 bldg_nm, y 좌표는 price로 지정 • 아파트명이 너무길기 때문에 rotation 45도 지정 fig = plt.figure(figsize=(20,10)) chart = sns.boxplot(data=tf[tf.DONG=='삼성동'], x='bldg_nm', y='price', hue='크기기준') chart.set_xticklabels(chart.get_xticklabels(), rotation=45) 강남구 매매 실거래 분석 동별 아파트 평균 매매 변화 분석
  • 88. • pivot 테이블을 이용하여 년월 기준 동별, 크기기준으로 그룹화하여 매매 평균값 구함 rf = tf.pivot_table(index='yyyymm', columns=['DONG','크기기준']).fillna(method='ffill') #NaN값은 이전 값으로 rf = rf[['price']] rf.columns = pd.MultiIndex.from_tuples([c[1:] for c in rf.columns ]) # 컬럼명 클린징 sns.heatmap(rf) 강남구 매매 실거래 분석 동별 아파트 평균 매매 변화 분석
  • 89. • 개포동을 대상으로 세부 아파트, 계약평형 기준으로 pivot 테이블 구성 rf = tf[tf.DONG=='개포동'][['bldg_nm','contract_extent','price','yyyymm']] rf_pivot = pd.pivot_table(rf, index='yyyymm', columns=['bldg_nm','contract_extent']) 강남구 매매 실거래 분석 동별 아파트 평균 매매 변화 분석 price bldg_nm 개포6차우성 ... 현대2 현대3 contract_extent 62.43 75.09 88.14 ... 107.23 107.75 160.73 165.46 197.27 107.25 160.51 196.46 yyyymm 2017-12 96500.0 NaN 132500.0 00000 ... 170000.0 NaN 180000.0 00000 NaN 210000.0 NaN 190000.0 243333.3 33333 2018-01 97500.0 115000.0 134200.0 00000 ... 170000.0 NaN 199285.7 14286 195000.0 222500.0 180000.0 00000 185000.0 245000.0 00000 2018-02 NaN 120000.0 142333.3 33333 ... NaN NaN 190000.0 00000 192500.0 230000.0 180000.0 00000 NaN NaN 2018-03 118000.0 NaN 149000.0 00000 ... 178800.0 NaN 190000.0 00000 190000.0 225000.0 180000.0 00000 NaN NaN 2018-04 107500.0 152000.0 156000.0 00000 ... 175750.0 NaN 210000.0 00000 190000.0 NaN 178333.3 33333 NaN NaN rf_pivot.columns = pd.MultiIndex.from_tuples( [c[1:] for c in rf_pivot.columns] ) • 컬럼명 클린징 (price 삭제)
  • 90. • 컬럼은 (아파트명, 계약면적)으로 되어있으므로 특정 아파트명으로 1차 접근하면 계약면적들이 나타남 fig = plt.figure(figsize=(25,10)) ax = plt.subplot(111) ax.plot( rf_pivot['개포자이'].fillna(method='ffill') ) # NaN 값은 이전 값으로 채움 ax.set_xticklabels(rf_pivot['개포자이'].index, rotation=45) ax.legend(rf_pivot['개포자이'].columns) plt.show() 강남구 매매 실거래 분석 동별 아파트 평균 매매 변화 분석
  • 91. • 개포자이 계약면적 249.68에 대한 회귀분석선 생성 rf_pivot['개포자이'].fillna(method='ffill',inplace=True) xr = np.array(range(len(rf_pivot['개포자이'][249.68].index))) yr = rf_pivot['개포자이'][249.68].tolist() fp = np.polyfit(xr, yr, 1) # 1차 회귀식 계수 생성 fx = np.poly1d(fp) #회귀식 생성 regress = fx(xr) #회귀분석 값 데이터 생성 강남구 매매 실거래 분석 동별 아파트 평균 매매 변화 분석 array([162925.45787546, 164630.02118289, 166334.58449033, 168039.14779777, 169743.7111052 , 171448.27441264, 173152.83772008, 174857.40102751, 176561.96433495, 178266.52764238, 179971.09094982, 181675.65425726, 183380.21756469, 185084.78087213, 186789.34417957, 188493.907487 , 190198.47079444, 191903.03410187, 193607.59740931, 195312.16071675, 197016.72402418, 198721.28733162, 200425.85063906, 202130.41394649, 203834.97725393, 205539.54056137, 207244.1038688 , 208948.66717624, 210653.23048367, 212357.79379111, 214062.35709855, 215766.92040598])
  • 92. ax = plt.subplot(111) ax.plot(rf_pivot['개포자이'].fillna(method='ffill')) ax.set_xticklabels(rf_pivot['개포자이'].index, rotation=45) ax.plot(regress, '--', linewidth=5) legends = rf_pivot['개포자이'].columns.tolist() legends.append('249.68 회귀분석선') ax.legend(legends) plt.show() 강남구 매매 실거래 분석 동별 아파트 평균 매매 변화 분석
  • 94. VISA 보고서 분석 자연어처리 기반의 EDA 접근 • 특정 회사 작성된 보고서나 문서에서 가장 많이 언급되는 키워드를 분석하면 전략 파악 가능 • 특정 회사의 문서 뿐만 아니라 특정 기간 범위 내의 기사들을 분석하면 시장 트렌드 분석 가능 • Innovations for Cashless World, VISA, 2017 레포트(PDF) 분석 예정 • 사용 라이브러리 pip install pypdf2 nltk wordcloud gensim 라이브러리 설명 pypdf2 pdf 파일을 분석하여 텍스트 형태로 변경을 위한 라이브러리 nltk 영문 자연어처리를 위한 라이브러리 wordcloud 텍스트에 대한 워드 클라우드 분석 라이브러리 gensim 단어들의 연관분석(word2vec)을 위한 라이브러리
  • 95. VISA 보고서 분석 PDF 파일의 텍스트 추출 • PDF 파일 라이브러리 : pypdf2 • PDF 파일을 로드하여 contents 리스트에 텍스트로 저장 import pypdf2 as pypdf contents = [] with open('visa-innovations-for-a-cashless-world-2017-report.pdf', 'rb') as f: pdf = pypdf.PdfFileReader(f) # pdf 객체 생성 num_of_pages = pdf.getNumPages() # pdf 객체의 전체 페이지 for num_page in range(1, num_of_pages): page = pdf.getPage(num_page) # 페이지 객체 if page.extractText(): # 텍스트 추출 contents.append(page.extractText())
  • 96. VISA 보고서 분석 가장 많이 거론된 단어 분석 • 목표 : 추출된 전체 텍스트에서 단어들만 추출하여 가장 많이 거론된 단어를 확인 • 영문 자연어처리 라이브러리 nltk 활용 import nltk from nltk.tokenize import word_tokenize #워드 토큰 객체 words = [ word_tokenize(page.lower()) for page in contents] # 소문자로 변환 후 워드 추출 words from itertools import chain words = list(chain.from_iterable(words)) words [['001the', 'last', 'few', 'years', 'have', 'witnessed', 'dramatic', 'changes', 'in', 'our', ... ]] • 단어별 카운팅을 전처리 작업을 위해 chain을 이용하여 1차원 리스트로 변환 ['001the', 'last', 'few', 'years', 'have', 'witnessed', 'dramatic', 'changes', 'in', 'our', ... ]
  • 97. VISA 보고서 분석 정규화와 불용어 • 단어 정규화(Nomalization) • 불용어 (stopword) : 자주 등장하지만 큰 의미가 없는 단어들 (예) in, how, for, 조사, 접미사 등 from nltk.corpus import stopwords #불용어 from nltk.stem.wordnet import WordNetLemmatizer #Lemmartizer _stopwords = set(stopwords.words('english')) #영어 _lemmatize = WordNetLemmatizer() #Lemmatizer 객체 words = [ w for w in words if w not in _stopwords ] #불용어 제거 words = [ w for w in words if w not in '!~@#$%^&*().,;:<>[]{}/+-?'"' ] #특수문자 제거 words = [ _lemmatize.lemmatize(w) for w in words] #정규화 (Lemmatization) words ['001the', 'last', 'year', 'witnessed', 'dramatic', 'change', 'industry', 'rise', 'digital', 'payment', ... Lemmatization 단어의 기본 사전형 단어로 복원 having > have, was > is Stemming 기본형과 상관없이 단어 특정 기준으로 자름 having > hav, was > wa
  • 98. VISA 보고서 분석 np.unique 이용한 단어, 단어건수 추출 • 단어의 출현빈도 건수는 numpy.unique 함수의 return_counts 이용 • np.unique 함수를 통해 리턴되는 값은 Unique 요소, 요소의 건수들의 각각의 np.array import numpy as np _words = np.array(words) # 리스트 > np array로 변환 word_arr, count_arr = np.unique(_words, return_counts=True) #Unique 요소, 건수 > np array로 word_ds=[] for w, c in zip(word_arr, count_arr): #zip 함수를 통해 두 개의 이터러블 접근 word_ds.append( (w,c) ) words_ds [("''", 2), ("'s", 10), ('-17-year-olds', 1), ('//tracxn.com', 1), ('//www.getkite.co', 1), ('/personal', 1), ('001the', 1),......
  • 99. VISA 보고서 분석 상위 10개 단어 확인 (튜플 리스트 정렬) • 정렬은 sorted 함수 이용. 대상이 객체일 경우 key= 옵션에 lambd를 이용하여 지정 • word_ds는 튜플(단어, 건수)로 구성된 리스트, 건수인 offset 1이 정렬의 키가 됨 • 내림차수 정렬은 reverse=True 옵션을 지정 sorted(word_ds, key=lambda x:x[1]) #오름차수 정렬 sorted(word_ds, key=lambda x:x[1], reverse=True) #내림차수 정렬 word_ds = sorted(word_ds, key=lambda x:x[1], reverse=True) #내림차수 정렬 word_ds[:10] • 내림차수 정렬 후 상위 10개 확인 [('payment', 271), ('consumer', 115), ('visa', 112), ('card', 89), ('digital', 69), ('innovation', 68), ('new', 65), ('mobile', 64), ('use', 62), ('technology', 57)]
  • 100. 워드클라우드 wordcloud 생성 방법 #1 • 워드클라우드는 wordcloud 라이브러리 이용 • raw 텍스트를 입력하여 객체 생성 가능 - WordCloud 객체의 generate_from_text 함수 이용 from wordcloud import WordCloud import matplotlib.pyplot as plt wc = WordCloud() wc = wc.generate_from_text('hi hi play game hi game') #plt.imshow에 전달하면 차트로 출력 fig = plt.figure(figsize=(10, 10)) plt.imshow(wc) plt.show()
  • 101. 워드클라우드 wordcloud 생성 방법 #2 • 워드클라우드는 wordcloud 라이브러리 이용 • 딕셔너리를 통해서도 객체 생성 가능 - WordCloud 객체의 generate_from_frequencies 함수 이용 from wordcloud import WordCloud import matplotlib.pyplot as plt wc = WordCloud() wc = wc.generate_from_frequencies( {'hi':2, 'play':5, 'game':3, 'start':1} ) #plt.imshow에 전달하면 차트로 출력 fig = plt.figure(figsize=(10, 10)) plt.imshow(wc, interpolation="bilinear") plt.show()
  • 102. 워드클라우드 VISA 워드 데이터셋을 워드 클라우드로 • VISA 워드 데이터셋(튜플 리스트)를 딕셔너리로 변경하여 출력 • 리스트 표현식과 동일하게 딕셔너리 내에서도 for~loop 표현 가능 word_dict = { _tuple[0]:_tuple[1] for _tuple in word_ds } # key(단어):value(건수) 형태로 변경 wc = WordCloud() wc = wc.generate_from_frequencies( word_dict ) fig = plt.figure(figsize=(10, 10)) plt.imshow(wc) plt.show()
  • 103. 워드클라우드 VISA 워드 데이터셋을 워드 클라우드로 • visa와 payment 단어를 제외하고 다시 워드클라우드 생성 • VISA 보고서에서 digital, consumer, card, innovation, technology가 눈에 띔 #워드 데이터셋에서 visa 단어와 payment를 제거 word_dict.pop('visa') word_dict.pop('payment') wc = wc.generate_from_frequencies( word_dict ) fig = plt.figure(figsize=(10, 10)) plt.imshow(wc) plt.show()
  • 104. 워드클라우드 VISA 워드 데이터셋을 워드 클라우드로 • WordCloud 객체에 폰트, 크기, 배경색, random 상태 개수 등 옵션을 지정 가능 • random_state는 상위 기준 단어들을 정규화 역할 (Outlier에 의해 뭍힐 뻔한 단어 부각) font_path ="C:/Windows/Fonts/malgun.ttf" wc = WordCloud( font_path = font_path, width = 800, height = 800, random_state=25, background_color='white' ) wc = wc.generate_from_frequencies( word_dict ) fig = plt.figure(figsize=(10, 10)) plt.imshow(wc, interpolation='bilinear') plt.axis('off') #차트에서 축 표시 숨김 plt.show()
  • 105. 워드클라우드 이미지 마스킹 효과 적용 • 이미지 객체를 np.array 로 변경하여 mask 지정 가능 • twitter.png 파일의 검은색 영역에 단어들이 표시 됨 from PIL import Image _mask = np.array(Image.open('twitter.png')) wc = WordCloud( font_path = font_path, width = 800, height = 800, random_state=25, background_color='white' , mask = _mask ) wc = wc.generate_from_frequencies( word_dict ) fig = plt.figure(figsize=(10, 10)) plt.imshow(wc, interpolation='bilinear') plt.axis('off') #차트에서 축 표시 숨김 plt.show() fig.savefig('visa_with_twitter.png') # 파일로 저장 twitter.png 워드클라우드
  • 106. • 베이즈 이론 (Bayes Theory) • P(A∩B) = P(B∩A) • P(A∩B) = P(A) P(B | A) • P(B∩A) = P(B) P(A | B) • P(A) P(B | A) = P(B)P(A | B) ∴ P(A|B) = P A P(B|A) P(B) = P(A∩B) P(B) 베이지안 이론 사건의 연속 확률 추정 : 조건부 확률 • 문서 내 단어들이 배치될 때 서로 이전 단어들의 존재를 확률적으로 판단하면 다음에 무엇이 올지 추정 가능 • P(WA | WB ) = 단어 B가 나타난 뒤 단어 A가 나타날 확률 • 사후확률이 일어날 가능성을 높히는 값은 사전확률, Likehood이므로 Likehood가 높을 수록 확률은 상승 P(A|B) = 𝐏 𝑨 𝐏(𝐁|𝐀) 𝐏(𝐁) 사후확률 (Posterior Probability) 관찰확률 (Marginal Probability) 사전 확률 (Prior Probability) 가능도 (Likehood)
  • 107. • 베이즈 이론 (Bayes Theory) • 날씨와 비의 관계 (총 20일) 맑음 흐림 비 옴 2일 10일 12일 안 옴 5일 3일 8일 7일 13일 • 비가 오는데 맑을 확률은? P(맑음|비) = = = 0.35 (35%) P(비) P(맑음) P(비|맑음) • P(맑음) = 7/20 = 0.35 • P(비) = 12/20 = 0.6 • P(비|맑음) = 2/7 = 0.285 0.6 0.35 x 0.6 베이지안 이론 사건의 연속 확률 추정 : 조건부 확률
  • 108. 베이지안 이론 Naive Bayesian • 나이브 베이지안(Naive Bayesian) : 단순하게 모든 사건은 독립적으로 서로 영향을 끼치지 않는다 가정 확률적으로 정확하지 않아도 유의미한 확률 결과 도출할 수 있음 날씨가 좋았나 바람이 불었나 기압이 높았나 온도가 높았나 계 YES NO YES NO YES NO YES NO 비옴 2 6 6 2 5 3 3 5 8 안옴 8 4 2 10 7 5 3 9 12 • 오늘 날씨가 좋고, 바람이 불지 않고, 기압은 높고, 온도가 낮다면 - 비가 올까 안 올까? • 비올 확률 P(비 | 날씨, ~바람, 기압, ~온도) = P(비) P(날씨, ~바람, 기압, ~온도|비) P(날씨, ~바람, 기압, ~온도) ≒ P(비) P(날씨|비) P(~바람|비) P(기압|비) P(~온도|비) = (8/20) * (2/8) * (2/8) * (5/8) * (5/8) = 0.009766 • 비 안 올 확률 P(~비 | 날씨, ~바람, 기압, ~온도) ≒ P(~비) P(날씨|~비) P(~바람|~비) P(기압|~비) P(~온도|~비) = (12/20) * (8/12) * (10/12) * (7/12) * (9/12) = 0.145833 비가 안 올 것으로 예상
  • 109. N-Gram 분석과 언어 모델링 확률적 언어 모델링 개념 • 확률 언어 모델(PLM)은 m 개의 단어들인 w1, w2, …, wm 가 문서(Document)를 이룰 때 베이지안 룰 적용 • N-Gram 모델 : 단어의 등장에 대한 조건부 확률 기준이 전체 단어의 구성이 아닌 N 개로 축소 • N-Grame 모델 종류 3가지 • 유니그램 모델 (Unigram model) : 단어가 서로 완전히 독립적이라고 가정 P(w1, w2, …, wm) = P(w1) P(w2) P(w3) … P(wm) = ς𝑖=1 𝑚 P(wi) • 바이그램 모델 (Bigram Nodel 혹은 Markov Model) : 단어 출현의 확률이 직전 단어에 의존하는 확률 P(w1, w2, …, wm ) = P(w1 ,w2) P(w2 ,w3) P(w3 ,w4) … P(wm -1 , wm ) = P(w1) ς𝑖=2 𝑚 P(wi|wi−1) • N그램 모델 (N gram-Model) : 단어의 출현이 이전 n-1 개의 단어에 의존하는 경우의 확률 P(w1, w2, …, wm ) = P(w1) ς𝑖=𝑛 𝑚 P(wi|wi−1 , … , wi−n)
  • 110. • nltk 패키지의 ngram 객체 이용 • 조건부 확률을 추정은 문장의 시작(SS)과 끝이라는 조건(SE)을 표시 필요 from nltk import word_tokenize from nltk.util import ngrams tokens = word_tokenize("hello data science. hello world") _ngrams = ngrams(tokens, 2) # bigram 생성 _bigrams = ngrams(tokens, 2, pad_left=True, pad_right=True, # bigram 생성 (토큰) left_pad_symbol="SS", right_pad_symbol="SE") ngram_list = [ ngram for ngram in _ngrams ] ngram_list [('hello', 'data'), ('data', 'science'), ('science', '.'), ('.', 'hello'), ('hello', 'world')] bigram_list = [ bigram for bigram in _bigrams ] bigram_list [('SS', 'hello'), ('hello', 'data'), ('data', 'science'), ('science', '.'), ('.', 'hello'), ('hello', 'world'), ('world', 'SE')] N-Gram 분석과 언어 모델링 ngram 기본 구현
  • 111. • ConditionalFreqDist 클래스 이용 - 문맥별 단어 빈도 측정 • 문맥별 단어 빈도 측정을 기반으로 단어의 조건부 확률 추정이 가능함 from nltk import ConditionalFreqDist import re pages = [ re.sub('(s+|n)',' ', page ) for page in contents] # VISA 보고서 중복 공백/라인구분자 제거 full_text = ''.join(pages) # 전체 텍스트 word_list = word_tokenize(full_text) # 단어 토큰화 bigrams = [ ngram for ngram in ngrams(word_list, 2, pad_left=True, pad_right=True, left_pad_symbol="SS", right_pad_symbol="SE") ] cfd = ConditionalFreqDist(bigrams) cfd['payment'].most_common(5) # payment 다음으로 가장 많이 위치한 단어 상위 5개 [('experiences', 6), ('process', 5), ('technology', 5), ('ecosystem', 5), ('options', 4)] cfd['payment'] #payment 단어와 단어별 빈도 수 FreqDist({'experiences': 6, 'process': 5, 'technology': 5, 'ecosystem': 5, 'options': 4, 'technologies': 4, 'and': 4, 'security': 3, '.': 3, ',': 3, ...}) N-Gram 분석과 언어 모델링 bigram 기반 단어 빈도 분석
  • 112. • ConditionalProbDist 클래스- 문맥별 단어 빈도 측정 기반으로 조건부 확률을 추정하는 트레이닝 • 트레이닝 후 조건부 확률의 값을 보거나 샘플 문장을 입력해서 문장의 로그 확률 추출 가능 • MLE (Maximum Likelihood Estimation) = 최대 가능도 추정치 from nltk import ConditionalProbDist, MLEProbDist cpd = ConditionalProbDist(cfd, MLEProbDist) # MLE 확률 이용한 확률 추정 트레이닝 cpd['payment'].prob('process') # payment 다음에 process가 올 확률 0.04716981132075472 cpd['digital'].prob('payment') # digtal 다음에 payment 가 올 확률 0.07692307692307693 N-Gram 분석과 언어 모델링 단어의 조건부 확률
  • 113. • ConditionalProbDist의 .generate()를 이용한 다음에 단어의 생성 • 트레이닝된 확률적 언어모델을 이용한 문장 생성 (챗봇 기본) docs = [word_tokenize(page) for page in pages] #페이지별 단어별 토큰화 bigrams = [] #bigram 튜플 리스트 for doc in docs: bigrams.extend([('SS', doc[0])]) #문맥 시작 토큰 bigrams.extend([(doc[i-1], doc[i]) for i in range(1, len(doc))]) bigrams.extend([(doc[-1],'SE')]) #문맥 종료 토큰 def generate_sentence(): current = 'SS' #문맥 시작 토큰 sentence = [] while True: word = cpd[current].generate() #지정된 단어의 다음에 위치할 단어 생성 if word == 'SE' : break #문맥 종료 토큰 sentence.append(' ' + word) current = word return "".join(sentence) N-Gram 분석과 언어 모델링 조건부 확률 기반 문장 생성
  • 114. 단어 연관 분석 Word2Vec • 인공신경망을 기반으로 한 단어들에 대한 분산 표현(Distributed Representation) 딥러닝 기법 • 단어들의 의미를 여러 차원에다가 분산하여 표현하므로 단어들간 유사도 계산 가능 • Word2Vec에는 CBOW와 Skip-Gram 두 가지 방식 존재 (자세한 것은 데이터과학 레벨3 강의) • CBOW (Continous Bag of Words) : 주변에 있는 단어들을 이용하여, 특정 위치의 단어를 예측 방법 • Skip-Gram : 특정 위치의 단어를 기준으로 주변 단어들을 예측 방법 • genism 라이브러리 이용하여 모델 생성 from gensim.models import word2vec from nltk.corpus import stopwords lemmatizer = WordNetLemmatizer() stopword = set(stopwords.words('english')) sentences=[] for doc in docs: sentences.append( [ lemmatizer.lemmatize(word) for word in doc if word not in stopword] ) # size = 벡터의 차원 , window = 윈도우 크기, hs = 1 softmax 이용, sg = 0(CBOW), 1(Skip-gram) model = word2vec.Word2Vec(sentences, size=50, window=2, min_count=30, hs=1, sg=1)
  • 115. 단어 연관 분석 Word2Vec • word2vec 모델의 활용 # word2vec 생성 50차원, 윈도우 사이즈 2, hs(softmax이용), sg는 skip-gram 이용 model = word2vec.Word2Vec(sentences, size=50, window=2, min_count=10, hs=1, sg=1) model.wv.vocab.keys() # 단어들의 구성 확인 model.wv.similarity('consumer','card') # consumer 단어와 card 단어의 유사도 model.wv.most_similar('digital') # digital 단어와 가장 유사한 단어들 dict_keys(['year', 'industry', 'digital', 'payment', '.', 'people', 'around', 'world', 'use', .... ]) 0.9974686 [('app', 0.9989895820617676), ('get', 0.9989762902259827), ('digital', 0.9987824559211731), ('data', 0.9987360835075378), ('million', 0.9987350106239319), ('APIs', 0.9987294673919678), ('also', 0.9987239837646484), ('wallet', 0.9987033009529114), ('The', 0.9987030625343323), ('seamless', 0.9986488223075867)]
  • 116. 단어 연관 분석 Word2Vec 시각화 • word2vec는 N개의 고차원으로 구성되어 있으므로 X, Y축으로 표현하려면 2차원으로 축소 필요 • 시각화를 위한 차원의 축소는 t-SNE(Stochastic Neighbor Embedding) 확률적 차원 축소 이용 from sklearn.manifold import TSNE import pandas as pd vocab = list(model.wv.vocab) # 단어 키 x = model[vocab] # 단어별 벡터값 tsne = TSNE(n_components=2) # 임베딩 공간 차원 (2차원) x_tsne = tsne.fit_transform(x) # t-SNE 변환 벡터 값 df = pd.DataFrame(x_tsne, index=vocab, columns=['x','y']) df.plot(kind='bar')
  • 117. 단어 연관 분석 Word2Vec 시각화 • word2vec는 N개의 고차원으로 구성되어 있으므로 X, Y축으로 표현하려면 2차원으로 축소 필요 • 시각화를 위한 차원의 축소는 t-SNE(Stochastic Neighbor Embedding) 확률적 차원 축소 이용 from sklearn.manifold import TSNE import pandas as pd # matplotlib로 시각화 fig = plt.figure(figsize=(20,20)) ax = fig.add_subplot(111) ax.scatter(df['x'], df['y']) for word, pos in df.iterrows(): ax.annotate(word, pos) #인덱스/ROW별 값
  • 119. 이후 과정을 통해 배울 지식
  • 120. Q&A