DataFrame Functions

데이터 분포 변환
대부분의 모델은 변수가 특정 분포를 따른다는 가정을 기반으로 한다. 예를 들어 선형 모델의 경우, 종속변수가 정규분포와 유사할 경우 성능이 높아지는 것으로 알려져 있다. 자주 쓰이는 방법은 Log, Exp, Sqrt 등 함수를 이용해 데이터 분포를 변환하는 것이다.
1
2
3
4
5
6
7
8
9
import math
from sklearn import preprocessing

# 특정 변수에만 함수 적용
df['X_log'] = preprocessing.scale(np.log(df['X']+1)) # 로그
df['X_sqrt'] = preprocessing.scale(np.sqrt(df['X']+1)) # 제곱근

# 데이터 프레임 전체에 함수 적용 (단, 숫자형 변수만 있어야 함)
df_log = df.apply(lambda x: np.log(x+1))
중복된 행 제거
위, 아래 행이 모두 같은 성분을 가지는 행이 여러개 있을때, 하나만 사용하기(데이터프레임)
중복된 행이 제거되고 unique한 값만 가져올 수 있다.
1
2
3
df.drop_duplicates()

df.drop_duplicated() 는 boolean값으로 반환!
1
2
df['name'] = df['name'].apply(lambda e: e.split()[0])
df['email'].str.get(i=0) 데이터프레임이나 시리즈형식에서 문자를 나누고 [0]번째 문자만 가져오기
데이터 프레임 모든 열에 특정 스칼라값 or 특정 컬럼.value 연산
1
df[컬럼명] *= (스칼라값)  / 해당 데이터프레임 컬럼이 와도 됨
1
df[컬럼명] = df[컬럼명].div(스칼라값 or 컬럼, axis=0)
1
2


a=10, b=20, c=3

Operator Description Example
+ 더하기 a + b 30
- 빼기 a - b -10
* 곱하기 a * b 200
/ 나누기 b / a 2.0
% 나머지 b % a 0
** 제곱 a ** c 1000
// 몫 a // c 3

SQLite db view tool.md

DB Browser for SQLite

http://sqlitebrowser.org/

사이트 들어가서, 해당 OS에서 맞는 파일을 다운로드 하자. 설치 완료 후, 프로그램을 가동하여, 열기를 통해 SQLite 의 파일을 열어서 테이블 형식으로 아래와 같이 볼 수 있다.

screenshot

사이트에서 접속하여 위에 카테고리 부분에 download를 클릭 후 해당 OS에 맞는 것을 설치해주면 끝.

쉽지?

[NodeJS]_n_을_통하여_NodeJS_버전_변경하기

NodeJS의 경우 버전 변경이 굉장히 잦고 버전마다 의존성 패키지가 매우 크기 때문에 여기서는 NodeJS 버전을 간단히 변경하는 n 을 소개하도록 할게
1. npm 을 통하여 n 설치하기
우선 현재 nodejs 의 버전을 확인해 봅니다. 
1
!node -v
v12.17.0


그리고 npm 을 통하여 n 을 global 로 설치하자! (nodeJS를 컨트롤 할 수 있는 라이브러리라 아주 중요해!)
1
!sudo npm install -g n
Password:

그리고 n을 재대로 설치 되었는지 확인을 위하여 버전을 확인하도록 하자
1
2

<img width="483" alt="스크린샷 2020-05-31 오전 10 43 54" src="https://user-images.githubusercontent.com/59719711/83342570-0a01cc80-a32c-11ea-83d3-a67d05de3533.png">
2. n 을 이용하여 버전 변경하기
버전 변경방법은 매우 간단해. n 뒤에 lts, latest 혹은 버전을 적으면 끝!
1
2
3
4
5
6
7
8
# lts 버전 설치
n lts

# 최신 버전 설치
n latest

# 특정 버전 설치
n 11
마지막으로 NodeJS의 버전을 변경 후 프로젝트의 node_modules를 삭제하고 yarn 혹은 npm으로 패키지를 재설치 하거나 업그레이드 하는 것을 추천해. 안그러면 종종 오류가 발생해

wget 설치하는법

Mac OS X에서 wget을 설치하는 방법
wget는 정말 편리한 명령줄 유틸리티지만, 안타깝게도 OS X에는 포함되지 않았다. 물론  Curl은 적절한 대체물이 될 수 있지만, 종종 wget로 스크립트가 쓰여지고, curl을 사용하는 것으로 변환하는 것은 어렵고 시간이 오래 걸릴 수 있어서 wget이 선호되는 경향이 있다.

homebrew로 wget을 설치하면 된다.
1
!brew install wget
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 2 taps (homebrew/core and homebrew/cask).
==> Updated Formulae
plenv               postgresql@11       swiftformat         tomee-webprofile
postgresql          postgresql@9.5      tomee-plume
postgresql@10       postgresql@9.6      tomee-plus
==> Updated Casks
cryo                                     switchresx

Warning: wget 1.20.3_2 is already installed and up-to-date
To reinstall 1.20.3_2, run `brew reinstall wget`
1
2
3
4
!brew uninstall --force node
!brew uninstall icu4c && brew install icu4c
!brew unlink icu4c && brew link icu4c --force
!brew install node
Uninstalling node... (4,660 files, 60.3MB)
Error: Refusing to uninstall /usr/local/Cellar/icu4c/66.1
because it is required by graphviz, harfbuzz and pango, which are currently installed.
You can override this and force removal with:
  brew uninstall --ignore-dependencies icu4c
Unlinking /usr/local/Cellar/icu4c/66.1... 0 symlinks removed
Warning: Refusing to link macOS provided/shadowed software: icu4c
If you need to have icu4c first in your PATH run:
  echo 'export PATH="/usr/local/opt/icu4c/bin:$PATH"' >> /Users/wglee/.bash_profile
  echo 'export PATH="/usr/local/opt/icu4c/sbin:$PATH"' >> /Users/wglee/.bash_profile

For compilers to find icu4c you may need to set:
  export LDFLAGS="-L/usr/local/opt/icu4c/lib"
  export CPPFLAGS="-I/usr/local/opt/icu4c/include"
Updating Homebrew...
==> Downloading https://homebrew.bintray.com/bottles/node-14.3.0.catalina.bottle
==> Downloading from https://akamai.bintray.com/e3/e34c4c25365bc0f5cc245d791dd93
######################################################################## 100.0%
==> Pouring node-14.3.0.catalina.bottle.tar.gz
==> Caveats
Bash completion has been installed to:
  /usr/local/etc/bash_completion.d
==> Summary
🍺  /usr/local/Cellar/node/14.3.0: 4,659 files, 60.8MB


** 필자가 갑자기 hexo가 작동되지 않아 적잖이 당황하던 중 해결법을 찾아서 이것도 공유해.
!brew uninstall --force node
!brew uninstall icu4c && brew install icu4c
!brew unlink icu4c && brew link icu4c --force
!brew install node

노드 언인스톨 후 재설치하면 문제 없이 작동한다.

파이썬에서 설치되어있는 라이브러리 버전 체크하기

파이썬을 사용하다 보면 사용하고자 하는 라이브러리 버전에 따라 같은 라이브러리임에도 불구하고 명령어가 다른 경우가 있어. 그럴 경우 설치된 라이브러리의 버전을 알아야 거기에 맞게 진행을 할 수 있겠지?

이때, 설치한 라이브러리들의 버전이 무엇인지부터 먼저 확인해보자!

1
pip freeze
anaconda-client==1.7.2
anaconda-navigator==1.9.12
appnope==0.1.0
asn1crypto==1.3.0
attrs==19.3.0
autopep8==1.5.2
autopy==4.0.0
backcall==0.1.0
backports.functools-lru-cache==1.6.1
backports.tempfile==1.0
backports.weakref==1.0.post1
beautifulsoup4==4.6.0
bleach==3.1.0
boto==2.49.0
boto3==1.13.12
botocore==1.16.12
branca==0.4.0
bs4==0.0.1
cachetools==4.0.0
certifi==2020.4.5.1
cffi==1.14.0
chardet==3.0.4
chart-studio==1.0.0
click==7.1.1
cloudpickle==1.3.0
clyent==1.2.2
colorama==0.4.3
colorlover==0.3.0
conda==4.8.3
conda-build==3.18.9
conda-package-handling==1.6.0
conda-verify==3.4.2
configobj==5.0.6
cryptography==2.8
cufflinks==0.17.3
cvxpy==1.0.31
cycler==0.10.0
cytoolz==0.10.1
dask==2.14.0
decorator==4.4.2
defusedxml==0.6.0
dill==0.3.1.1
docutils==0.15.2
dpkt==1.9.2
ecos==2.0.7.post1
entrypoints==0.3
et-xmlfile==1.0.1
filelock==3.0.12
finance-datareader==0.9.6
folium==0.10.1
funcy==1.14
future==0.18.2
gensim==3.8.3
glob2==0.7
google-api-core==1.16.0
google-auth==1.12.0
google-auth-oauthlib==0.4.1
google-cloud-bigquery==1.24.0
google-cloud-core==1.3.0
google-resumable-media==0.5.0
googleapis-common-protos==1.51.0
idna==2.9
imageio==2.8.0
importlib-metadata==1.5.0
inflect==4.1.0
ipykernel==5.1.4
ipython==7.13.0
ipython-genutils==0.2.0
ipywidgets==7.5.1
jaraco.itertools==5.0.0
jdcal==1.4.1
jedi==0.16.0
Jinja2==2.11.1
jmespath==0.10.0
joblib==0.14.1
JPype1==0.7.5
jsonschema==3.2.0
jupyter-client==6.1.2
jupyter-core==4.6.3
jupyterthemes==0.20.0
kiwisolver==1.2.0
konlpy==0.5.2
lesscpy==0.14.0
libarchive-c==2.8
lief==0.9.0
lxml==4.5.0
MarkupSafe==1.1.1
matplotlib==3.2.1
missingno==0.4.2
mistune==0.8.4
mkl-fft==1.0.15
mkl-random==1.1.0
mkl-service==2.3.0
more-itertools==8.2.0
mpmath==1.1.0
multiprocess==0.70.9
navigator-updater==0.2.1
nbconvert==5.6.1
nbformat==5.0.4
netifaces==0.10.9
networkx==2.4
nltk==3.5
notebook==6.0.3
numexpr==2.7.1
numpy==1.18.1
oauthlib==3.1.0
olefile==0.46
opencv-python==4.2.0.34
openpyxl==3.0.3
osqp==0.6.1
packaging==20.3
pandas==1.0.3
pandas-gbq==0.13.1
pandocfilters==1.4.2
parso==0.6.2
patsy==0.5.1
pexpect==4.8.0
pgmpy==0.1.10
picklable-itertools==0.1.1
pickleshare==0.7.5
Pillow==7.0.0
pkginfo==1.5.0.1
plotly==4.5.0
pluggy==0.13.1
ply==3.11
prometheus-client==0.7.1
prompt-toolkit==3.0.4
protobuf==3.11.3
psutil==5.7.0
ptyprocess==0.6.0
py==1.8.1
pyasn1==0.4.8
pyasn1-modules==0.2.8
pycodestyle==2.5.0
pycosat==0.6.3
pycparser==2.20
pydata-google-auth==0.3.0
Pygments==2.6.1
pyLDAvis==2.1.2
PyMySQL==0.9.3
pyOpenSSL==19.1.0
pyparsing==2.4.7
pyrsistent==0.16.0
PySocks==1.7.1
pytest==5.4.2
python-dateutil==2.8.1
python-xlib==0.27
pytz==2019.3
PyWavelets==1.1.1
PyYAML==5.3.1
pyzmq==18.1.1
QtPy==1.9.0
regex==2020.5.14
requests==2.23.0
requests-file==1.4.3
requests-oauthlib==1.3.0
retrying==1.3.3
rsa==4.0
ruamel-yaml==0.15.87
s3transfer==0.3.3
schedule==0.6.0
scikit-image==0.16.2
scikit-learn==0.22.2.post1
scipy==1.4.1
scs==2.1.2
seaborn==0.10.0
selenium==3.141.0
Send2Trash==1.5.0
six==1.14.0
sklearn==0.0
smart-open==2.0.0
soupsieve==2.0
soynlp==0.0.493
SQLAlchemy==1.3.16
statsmodels==0.11.0
sympy==1.5.1
terminado==0.8.3
testpath==0.4.4
toolz==0.10.0
torch==1.5.0
tornado==6.0.4
tqdm==4.44.1
traitlets==4.3.3
tweepy==3.8.0
urllib3==1.25.8
wcwidth==0.1.9
webencodings==0.5.1
wget==3.2
widgetsnbextension==3.5.1
wordcloud==1.7.0
xlrd==1.2.0
xmltodict==0.12.0
zipp==2.2.0
Note: you may need to restart the kernel to use updated packages.
1
2


1
2


1
2


1
2


1
2


1
2


어때? 쉽지? 물론 특정 라이브러리를 잡아서 하는 방법도 있지만, 여기서 소개하는 방법은 설치된 모든 라이브러리의 버전을 확인할 수 있는 방법이야. 파이썬 라이브러리 종류가 매우 많은데 이 명령어 하나로 모든 설치된 라이브러리의 버전을 확인할 수 있으니까 상당히 편리한 것 같네.

Data Analytic on Football

[숫자는 거짓말하지 않는다: 왜 축구 클럽들이 그렇게 애널리틱스를 중요하게 생각할까(The numbers don’t lie: why football clubs place such importance on analytics)]

WEST_HAM-main2-large_trans++01hEHXp48ZjlCwDoPtrE-G07QTvTgRHNz-gQ-gQnMTo

웨스트 햄의 로리 캠벨은 빅 클럽에서 핵심 결정에 정보를 제공하는 떠오르는 축구 애널리스트들 중의 하나이다.

선수들이 떠난 한참 후의 웨스트 햄 유나이티드의 채드웰 헬스 훈련장의 조용한 구석에서 로리 캠벨은 컴퓨터 화면을 응시하고 있다. 이것이 보비 무어와 제프 허스트 경의 두 번째 집이었던 이래로 그 주변의 거주지들은 오직 피상적으로 변했을 뿐이나, 필드 밖의 준비의 복잡성은 완전히 바뀌고 있다.

캠벨은 웨스트 햄의 기술 스카우트이자 분석가이다. 옥스포드 졸업생이자, 알라스테어 캠벨의 아들들 중 하나인 그는 성공적인 포커 선수였으며, 약간의 선수 경험과 코칭 배경을 가졌다. 그의 초점은 축구에 관한 무한한 통계적이 데이터들을 이해하는 것이며, 그래서 클럽의 핵심적인 의사 결정자들에게 무엇이 정말 중요한지를 전달하는 것이다.

WEST_HAM-epa-large_trans++ZgEkZX3M936N5BQK4Va8RWtT0gK_6EfZT336f62EI5U

은골로 칸테는 올시즌의 영입이고 축구 애널리틱스의 승리이다.

더구나, 축구의 가장 효과적인 분석 작업들 중 몇몇과 단순히 구매력을 거의 반영하지 않고 있는 프리미어 리그 테이블 사이의 잠재적인 상관 관계는 분명하다. 레스터 시티와 웨스트 햄은 오늘 만나 경기를 갖지만, 예를 들어 어떻게 그들이, 만체스터 유나이티드가 마루앙 펠라이니, 안더 에레라 그리고 바스티안 슈바인슈타이거에 7천만 파운드를 쏟아부을 때, 은골로 칸테, 디미트리 파예 그리고 리야드 마레즈를 천 6백만 파운드에 발견해냈을까? 그리고 무엇이 토튼햄 핫스퍼가 델리 알리와 에릭 다이어로 이끌었는지 혹은 사우스햄튼을 사디오 마네와 버질 반 다이크로 이끌었을까? 왜 팀들이 전에 없이 적은 크로스를 하고 있을까? 무엇이 레스터의 독특한 특징일까? 왜 펩 과르디올라와 같은 감독들이 먼 거리에서의 슈팅을 장려하지 않을까? 그리고 모든 시즌들 중에서 가장 놀라운, 테이블이 거짓말을 하지 않는다는 것은 정말 사실일까?

WEST_HAM-epa-large_trans++ZgEkZX3M936N5BQK4Va8RWtT0gK_6EfZT336f62EI5U

캠벨은 웨스트 햄의 기술 스카우트이자 애널리스트이다.

애널리틱스는 최소한 부분적인 답을 제공한다. 비록 캠벨이 분석의 가치가 여전히 의사결정의 기저를 구성하고 있는 경험, 직관, 본질적인 지식과 접촉들을 대체한다기 보다는 보조하는 것이라고 확신하지만 말이다. 그는 “비효율적인 어떤 시장도 기회입니다.”라고 말한다. “축구가 재능을 가치 평가하는 세트나 동의된 방식을 갖고 있지 않고 너무나 임의적이라는 사실은 기회입니다. 통계와 애널리틱스는 차이가 있습니다. 통계는 당신에게 일어난 사건들에 대해서 말해줍니다. 그들은 맥락없이는 아무 것도 의미하지 않습니다.

analytics2-large_trans++qVzuuqpFlyLIwiB6NTmJwfSVWeZ_vEN7c6bHu2jJnT8

레스터의 직접적인 스타일은 그들을 뚜렷한 프리미어 리그 아웃라이어로 만들었다.

“애널리틱스는 그러한 통계들을 미래의 퍼포먼스를 예측하기 위해 해석하는 것입니다. 당신은 모든 것을 측정할 수 있습니다. 어려운 것은 무엇이 중요한지를 알아내는 것입니다. 한가지 좋은 것은 축구는 꽤 단순하다는 것입니다. 모든 것은 결국에는 어떻게든 골과 연관되어 있습니다, 그것이 우리의 득점 기회를 늘려주거나 아니면 실점을 막아주거나요. 그것은 또한 감독이 팀이 어떻게 플레이하기를 원하는 틀 안에서 통합니다.”

보다 더 많은 통찰들이 사우스햄튼의 훈련시설에서 발견될 수 있다. 가장 놀라운 곳은 클럽의 34세의 스카우팅과 선수선발 이사인 로스 윌슨이 자리잡고 있는 방이다. 그의 바로 앞에는 15개의 일련의 화면 앞에서 젊은 스태프들의 팀이 정보들을 처리하고 있다. 몇몇은 축구 분석의 특정 분야에서의 학위를 보유한 인턴들이다. 윌슨의 오른쪽에는 보다 희끗희끗한 머리를 가진 관계자인 로드 루딕과 같은 사람이 있다. 그는 뉴포트의 필드에서 뛰던 8살의 가레스 베일을 발견한 스카우트이다. 윌슨의 왼쪽에는 “블랙 박스”라는 단어가 미스테리하게 걸려있는 문이 있다.

1111

폴 미첼은 사우스햄튼에서 토튼햄으로 이동해서 선수선발 및 분석 팀장이 되었다.

사우스햄튼은 이 미니-시네마에 쓰이는 맞춤형 소프트웨어를 꾸준히 수정하고 있다. 그 소프트웨어는 몇번의 클릭들 만으로 전세계에 있는 어떤 선수에 대한 것도 볼 수 있다. 다른 클럽들은 비슷한 기술을 개발 중이며, 수학적으로 재능들을 골라내는 사람들 사이에서, 이적 시장이 떠오르고 있다. 아스날은 올 해 벤 뤼글워스를 레스터로부터 빼냈고, 미국 기반의 분석 회사인 statDNA를 2백만 파운드에 사들였다. 마우리시오 포체티노와 함께, 토튼햄은 그들의 선수선발과 분석 팀장인 폴 미첼을 사우스햄튼에서 선발했다. 부상으로 27세에 선수 커리어를 끝냈던 미첼은 이렇게 말한다. “저는 한 번 좋은 경기를 가질 때 다른 80경기에서는 그렇게 좋지 않다는 간단한 이론을 발견했습니다.”

포커에서처럼, 캠벨은 선수 선발을 “당신의 베팅의 경제적인 리스크를 가용한 정보를 가지고 관리하는 것”이라고 부른다. 하지만 다른 점은 그의 산업의 다른 멤버들과의 미팅이 분명히 핵심적이라는 것을 강조한다. 과거의 축구에서의 혁신의 시도가 주저앉은 곳에는 종종 의사소통의 실수나 개인간의 충돌들에 기반한다.

클라이브 우드와드 경은 보통 생각되는 것보다 해리 레드납과 더 나은 관계를 가지고 있다. 하지만 거기에 루퍼트 로, 데이브 바셋, 데니스 와이즈와 사이먼 클리포드를 더하면 당신이 그것이 어디서 잘못되었는지 파악하기 위해서 에르큘 포와드의 추리력까지 필요하지도 않다. 애널리틱스가 차이를 만들어내는 곳에는 주로 문화가 정립된다. “당신이 플레이할 필요가 있는 클럽들 중에는 전통이 깊이 배어있는 클럽들이 있을 것입니다. 하지만 운이 좋게도 내가 있었던 클럽들은 사고방식이 매우 열려있었습니다.” 윌슨이 말한다.

캠벨은 이렇게 더한다: “애널리틱스 세계가 힘겨워하는 부분은 전통적인 축구 세계로의 다리를 놓는 것입니다. 정보를 더 침투시키기 위해서요. 수학적인 측면에서는 완벽히 논리적으로 말이되는 많은 정보들을 주고 수십년간 발전해 온 스포츠가 그것을 하루 아침에 받아들이기를 기대하는 것은 사실 꽤 건방진 것이다. 나는 이것이 가장 큰 도전으로 남아있다고 말하고 싶다. 정보를 전달할 수 있기 위해서는 당신은 역학관계와 당신과 함께 일하는 사람들의 성격들을 이해해야만 한다. 나는 그것이 왜 애널리틱스가 다른 비지니스에서 그랬던 것처럼 축구에 침투하지 못한 이유라고 생각한다.”

45

아스날 감독 아슨 벵거는 또한 애널리틱스를 수용해오고 있다.

하지만 이것은 변하고 있다. 캠벨은 그가 슬래븐 빌리치와 선수 선발 디렉터인 토니 헨리 아래에서 일할 수 있어서 매우 운이 좋았다고 말한다. 그리고 모두의 역할에 분명함이 있었다. 그들이 원하는 것은 간단히 그들의 결정을 도와줄 정보에 대한 믿을만한 평가였다. 나이 많은 감독들 역시 접근하고 있다. 클라우디오 라니에리는 한 예이다. 아슨 벵거는 올 시즌 공식자리에서 아스날의 “기대 골 값 (xG)”에 대해 언급하면서 충격을 촉발시켰다. 그것은 팀이 통계적으로 얼마나 자주 득점할 수 있는지에 대한 스포츠 베팅과 애널리틱스에서 핵심적인 측정값이다.

보루시아 도르트문트의 코치 토마스 투헬은 xG에 대해 더 배우기 위해 매튜 베넘을 찾아갔다. 베넘은 스포츠 베팅에서 수백만을 벌었고 그 이후로 브렌트포드와 FC밋츌란을 사들였다. 선수를 개인적으로 관찰하기 위해 폭넓게 움직이는 캠벨과 마찬가지로, 베넘은 축구처럼 낮은 득점을 가진 스포츠에서의 어떤 수학 모델의 뚜렷한 변동성을 보완하기 위한 “눈으로 하는 스카우팅”의 중요성을 강조한다. 포커처럼, 랜덤과 통제불가능한 사건들이 판단들을 형성하는데 서두르는 가운데에 종종 간과하는 부분적인 역할을 한다.

캠벨은 이렇게 말한다. “이것은 축구를 흥미롭게 만드는 것입니다만 예측불가능은 항상 심각한 비효율을 동반합니다. 운을 불평하는 프로 포커 선수들은 편협한 것입니다. 운이라는 것은 그들이 사는 것을 가능케하는 것입니다. 만약 내가 정말 나쁜 선수와 포커를 친다면, 그는 100번 중에 40번을 이길 것입니다. 만약 내가 개리 카스파로프와 체스를 둔다면 그가 100번을 이기겠죠. 체스 선수들은 베팅으로 돈을 벌지 않습니다. 왜냐하면 아무도 그들에게 돈을 걸지 않으니까요.”

WEST_HAM-reuters-large_trans++oQmI6CCYeWXI2SDtPW01M2FxAL8YkdOPBcsmeEiEP3A

레스터의 동화같은 시즌은 통계적인 모델들이 틀렸음을 입증해오고 있다.

애널리틱스는 점점 더 많은 의견들로 가득찬 현재 지형 안에서 목소리를 내기 위해 싸우고 있다. 캠벨은 이렇게 말한다. “아슨 벵거는 우리가 수직적에서 수평적인 사회로 움직이고 있다고 말했습니다. 수직적인 것은 꼭대기에 리더가 있고 모두가 따르는 것입니다. 수평적인 것은 정보와 의견들에 폭격을 당하는 리더를 가진 것입니다. 그것이 리더가 어떤 것이 중요하고 어떤 것이 노이즈인지를 구분하는 것이 정말 중요한 부분입니다.”

그러면 처음 질문으로 돌아가 보자. 칸테, 마네 그리고 파예는 궁극적으로 기민한 축구적인 결정들이었다. 하지만 애널리틱스 커뮤니티의 기저에 있는 퍼포먼스 지표들의 승리였다. 분명한 통계적인 증거는 크로스들이 스루 볼 보다 적은 확률의 전술이라는 것이고 먼 거리에서의 슈팅은 더 나은 포지션으로 패스하는 것 보다 적은 골을 생산한다는 것이다.

수학 교수이자 사커매틱스의 저자 데이빗 섬터에 따르면, 레스터와 리그의 다른 팀들과의 충격적인 차이는 어떻게 그들이 상대적으로 길고 직선적인 패스들로 볼을 전방으로 빠르게 움직이는지이다.

그러면 테이블은 절대 거짓말하지 않는다는 클리셰는 거짓일까? 글쎄, 아마도 그것은 진실 전부를 말하지는 않는다. 거의 모든 xG모델은 아스날이 사실 엄청난 기회를 놓쳤고 선두에 있었어야 한다고 말하고 있다. 대부분의 모델은 만약 이번 시즌이 무한한 경기 수를 가졌을 때 레스터가 4위에서 8위 사이에 놓고 있다. 분산과 운은, 38경기 프로그램에서 상당한 양으로 남아있다. 여전히 그 차이들은 좁고, 만약 지난 해가 어떤 것도 새로 증명하는 것이 아니라면, 열심히 일하는 것과 스마트함이 클럽의 은행 계좌의 사이즈 보다 더 중요할 수 있다.

출 처 : http://www.telegraph.co.uk/football/2016/04/16/the-numbers-dont-lie-why-football-clubs-place-such-importance-on/

leverage-outliar-cooks_distance_anova

1
import statsmodels.api as sm

레버리지 (leverage)

독립변수의 전체 데이터가 아닌 개별적인 데이터 표본 하나하나가 회귀분석 결과에 미치는 영향력은 레버리지 분석이나 아웃라이어 분석을 통해 알 수 있다.
레버리지(leverage)는 실제 종속변수값  𝑦 가 예측치(predicted target)  𝑦̂  에 미치는 영향을 나타낸 값이다. self-influence, self-sensitivity 라고도 한다.
1
2
3
4
5
6
7
8
from sklearn.datasets import load_boston

boston = load_boston()

dfx = pd.DataFrame(boston.data, columns=boston.feature_names)
dfy = pd.DataFrame(boston.target, columns=["MEDV"])
df = pd.concat([dfx,dfy],axis=1)
df

CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT MEDV
0 0.00632 18.0 2.31 0.0 0.538 6.575 65.2 4.0900 1.0 296.0 15.3 396.90 4.98 24.0
1 0.02731 0.0 7.07 0.0 0.469 6.421 78.9 4.9671 2.0 242.0 17.8 396.90 9.14 21.6
2 0.02729 0.0 7.07 0.0 0.469 7.185 61.1 4.9671 2.0 242.0 17.8 392.83 4.03 34.7
3 0.03237 0.0 2.18 0.0 0.458 6.998 45.8 6.0622 3.0 222.0 18.7 394.63 2.94 33.4
4 0.06905 0.0 2.18 0.0 0.458 7.147 54.2 6.0622 3.0 222.0 18.7 396.90 5.33 36.2
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
501 0.06263 0.0 11.93 0.0 0.573 6.593 69.1 2.4786 1.0 273.0 21.0 391.99 9.67 22.4
502 0.04527 0.0 11.93 0.0 0.573 6.120 76.7 2.2875 1.0 273.0 21.0 396.90 9.08 20.6
503 0.06076 0.0 11.93 0.0 0.573 6.976 91.0 2.1675 1.0 273.0 21.0 396.90 5.64 23.9
504 0.10959 0.0 11.93 0.0 0.573 6.794 89.3 2.3889 1.0 273.0 21.0 393.45 6.48 22.0
505 0.04741 0.0 11.93 0.0 0.573 6.030 80.8 2.5050 1.0 273.0 21.0 396.90 7.88 11.9

506 rows × 14 columns

1
2
3
dfX = sm.add_constant(dfx)
df0 = pd.concat([dfX, dfy],axis=1)
df0

const CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT MEDV
0 1.0 0.00632 18.0 2.31 0.0 0.538 6.575 65.2 4.0900 1.0 296.0 15.3 396.90 4.98 24.0
1 1.0 0.02731 0.0 7.07 0.0 0.469 6.421 78.9 4.9671 2.0 242.0 17.8 396.90 9.14 21.6
2 1.0 0.02729 0.0 7.07 0.0 0.469 7.185 61.1 4.9671 2.0 242.0 17.8 392.83 4.03 34.7
3 1.0 0.03237 0.0 2.18 0.0 0.458 6.998 45.8 6.0622 3.0 222.0 18.7 394.63 2.94 33.4
4 1.0 0.06905 0.0 2.18 0.0 0.458 7.147 54.2 6.0622 3.0 222.0 18.7 396.90 5.33 36.2
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
501 1.0 0.06263 0.0 11.93 0.0 0.573 6.593 69.1 2.4786 1.0 273.0 21.0 391.99 9.67 22.4
502 1.0 0.04527 0.0 11.93 0.0 0.573 6.120 76.7 2.2875 1.0 273.0 21.0 396.90 9.08 20.6
503 1.0 0.06076 0.0 11.93 0.0 0.573 6.976 91.0 2.1675 1.0 273.0 21.0 396.90 5.64 23.9
504 1.0 0.10959 0.0 11.93 0.0 0.573 6.794 89.3 2.3889 1.0 273.0 21.0 393.45 6.48 22.0
505 1.0 0.04741 0.0 11.93 0.0 0.573 6.030 80.8 2.5050 1.0 273.0 21.0 396.90 7.88 11.9

506 rows × 15 columns

statsmodels를 이용한 레버리지 계산
레버리지 값은 RegressionResults 클래스의 get_influence 메서드로 다음과 같이 구할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from sklearn.datasets import make_regression

# 100개의 데이터 생성
X0, y, coef = make_regression(n_samples=100, n_features=1, noise=20,
coef=True, random_state=1)

# 레버리지가 높은 가상의 데이터를 추가
data_100 = (4, 300)
data_101 = (3, 150)
X0 = np.vstack([X0, np.array([data_100[:1], data_101[:1]])])
X = sm.add_constant(X0) #상수항 추가
y = np.hstack([y, [data_100[1], data_101[1]]])

plt.figure(figsize=(14,6))
plt.scatter(X0, y, s=30)
plt.xlabel("x")
plt.ylabel("y")
plt.title("가상의 회귀분석용 데이터")
plt.show()
output_6_0
1
2
3
model = sm.OLS(pd.DataFrame(y), pd.DataFrame(X))
result = model.fit()
print(result.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                      0   R-squared:                       0.936
Model:                            OLS   Adj. R-squared:                  0.935
Method:                 Least Squares   F-statistic:                     1464.
Date:                Thu, 14 May 2020   Prob (F-statistic):           1.61e-61
Time:                        14:22:53   Log-Likelihood:                -452.71
No. Observations:                 102   AIC:                             909.4
Df Residuals:                     100   BIC:                             914.7
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
0              3.2565      2.065      1.577      0.118      -0.840       7.353
1             78.3379      2.048     38.260      0.000      74.276      82.400
==============================================================================
Omnibus:                       16.191   Durbin-Watson:                   1.885
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               36.807
Skew:                          -0.534   Prob(JB):                     1.02e-08
Kurtosis:                       5.742   Cond. No.                         1.14
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.


선형회귀 결과에서 get_influence 메서드를 호출하면 영향도 정보 객체를 구할 수 있고, 이 객체는 hat_matrix_diag 속성으로 레버리지 벡터의 값을 가지고도 있어
1
2
3
4
5
6
7
8
influence = result.get_influence()
hat = influence.hat_matrix_diag

plt.figure(figsize=(14,6))
plt. stem(hat)
plt.axhline(0.02, c = 'g', ls = '--') # c = color , ls = linestyle
plt.title('각 데이터의 레버리지 값')
plt.show()
/opt/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:5: UserWarning: In Matplotlib 3.3 individual lines on a stem plot will be added as a LineCollection instead of individual lines. This significantly improves the performance of a stem plot. To remove this warning and switch to the new behaviour, set the "use_line_collection" keyword argument to True.
  """
output_9_1
그래프를 그리는 코드에서 0.02의 값은 레버리지 평균값을 구하는 공식 독립변수의 갯수 / 데이터의 갯수 로 구하면 된다
1
![스크린샷 2020-05-14 오후 2 31 46](https://user-images.githubusercontent.com/59719711/81926278-b2215100-961c-11ea-9613-c5ba582d5de0.png)
1
2
3
4
5
6
7
8
9
plt.figure(figsize=(14,6))
ax = plt.subplot()
plt.scatter(X0, y,s=30)
sm.graphics.abline_plot(model_results=result, ax=ax)

idx = hat > 0.05
plt.scatter(X0[idx], y[idx], s=300, c="r", alpha=0.5)
plt.title("회귀분석 결과와 레버리지 포인트")
plt.show()
output_12_0
그래프를 토대로 해석을 하자면, 데이터가 혼자만 너무 작거나 너무 크게 단독으로 존재할수록 레버리지가 커짐을 알 수 있어. 이 말은 저런 데이터은 전체 회귀분석 결과값에 큰 영향을 미친다는 말이야

아웃라이어(outlier)

데이터와 동떨어진 값을 가지는 데이터, 즉 잔차가 큰 데이터를 아웃라이어(outlier)라고 하는데, 잔차의 크기는 독립 변수의 영향을 받으므로 아웃라이어를 찾으려면 이 영향을 제거한 표준화된 잔차를 계산해야 한다고 해. 무슨말인지 잘 모르겠지만 그래

statsmodels를 이용한 표준화 잔차 계산

잔차는 RegressionResult 객체의 resid 속성에 있다.
1
2
3
4
plt.figure(figsize=(14, 6))
plt.stem(result.resid)
plt.title("각 데이터의 잔차")
plt.show()
/opt/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:2: UserWarning: In Matplotlib 3.3 individual lines on a stem plot will be added as a LineCollection instead of individual lines. This significantly improves the performance of a stem plot. To remove this warning and switch to the new behaviour, set the "use_line_collection" keyword argument to True.
output_16_1
표준화 잔차는 resid_pearson 속성에 있고, 보통 표준화 잔차가 2~4보다 크면 아웃라이어로 보는게 일반적이야
1
2
3
4
5
6
plt.figure(figsize=(14,6))
plt. stem(result.resid_pearson)
plt.axhline(3, c='g', ls='--')
plt.axhline(-3, c='g', ls='--')
plt.title('각 데이터의 표준화 잔차')
plt.show()
/opt/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:2: UserWarning: In Matplotlib 3.3 individual lines on a stem plot will be added as a LineCollection instead of individual lines. This significantly improves the performance of a stem plot. To remove this warning and switch to the new behaviour, set the "use_line_collection" keyword argument to True.
output_18_1

Cook’s Distance

회귀 분석에는 레버리지 따로, 잔차의 크기가 큰 데이터가 아웃라이어가 되고 그것을 보는 따로따로의 기능도 있지만  이 두개를 동시에 보는 방법이 바로 Cook's Distance야. 아마도 Cook이라는 사람이 만들었을 가능성이..

넘어가자

동시에 보는 기준이라고 생각하면 되고, 둘중 하나만 커지더라도 이 Cook's distance 값은 커지게 돼

모든 데이터의 레버리지와 잔차를 동시에 보려면 plot_leverage_resid2 명령을 사용하는데, 이 명령은 x축으로 표준화 잔차의 제곱을 표시하고 y축으로 레버리지값을 표시한다. 

그리고 데이터 아이디가 표시된 데이터들이 레버리지가 큰 아웃라이어 야
1
2
3
4
5
6
plt.figure(figsize=(14,6))
sm.graphics.plot_leverage_resid2(result)
plt.show()

sm.graphics.influence_plot(result)
plt.show()
<Figure size 1008x432 with 0 Axes>
output_21_1 output_21_2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from statsmodels.graphics import utils

cooks_d2, pvals = influence.cooks_distance
K = influence.k_vars
fox_cr = 4 / (len(y) - K - 1)
idx = np.where(cooks_d2 > fox_cr)[0]

ax = plt.subplot()
plt.scatter(X0, y)
plt.scatter(X0[idx], y[idx], s=300, c="r", alpha=0.5)
utils.annotate_axes(range(len(idx)), idx,
list(zip(X0[idx], y[idx])), [(-20, 15)] * len(idx), size="small", ax=ax)
plt.title("Fox Recommendaion으로 선택한 아웃라이어")
plt.show()
output_22_0
보스턴 집값 예측 문제¶
보스턴 집값 문제에 아웃라이어를 적용해 보자. MEDV가 50인 데이터는 상식적으로 생각해도 이상한 데이터이므로 아웃라이어라고 판단할 수 있다. 나머지 데이터 중에서 폭스 추천공식을 사용하여 아웃라이어를 제외한 결과는 다음과 같다.
1
2
3
4
5
6
7
8
9
10
boston = load_boston()

dfx = pd.DataFrame(boston.data, columns=boston.feature_names)
dfy = pd.DataFrame(boston.target, columns=["MEDV"])
df = pd.concat([dfx,dfy],axis=1)
df

dfX = sm.add_constant(dfx)
df0 = pd.concat([dfX, dfy],axis=1)
df0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pred = result_boston.predict(dfX)

influence_boston = result_boston.get_influence()
cooks_d2, pvals = influence_boston.cooks_distance
K = influence.k_vars
fox_cr = 4 / (len(y) - K - 1)
idx = np.where(cooks_d2 > fox_cr)[0]

# MEDV = 50 제거
idx = np.hstack([idx, np.where(boston.target == 50)[0]])

ax = plt.subplot()
plt.scatter(dfy, pred)
plt.scatter(dfy.MEDV[idx], pred[idx], s=200, c="r", alpha=0.5)
utils.annotate_axes(range(len(idx)), idx,
list(zip(dfy.MEDV[idx], pred[idx])), [(-20, 15)] * len(idx), size="small", ax=ax)
plt.title("보스턴 집값 데이터에서 아웃라이어")
plt.show()
output_25_0
다음은 이렇게 아웃라이어를 제외한 후에 다시 회귀분석을 한 결과이다.
1
2
3
4
5
6
idx2 = list(set(range(len(dfX))).difference(idx))
dfX = dfX.iloc[idx2, :].reset_index(drop=True)
dfy = dfy.iloc[idx2, :].reset_index(drop=True)
model_boston2 = sm.OLS(dfy, dfX)
result_boston2 = model_boston2.fit()
print(result_boston2.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                   MEDV   R-squared:                       0.812
Model:                            OLS   Adj. R-squared:                  0.806
Method:                 Least Squares   F-statistic:                     156.1
Date:                Thu, 14 May 2020   Prob (F-statistic):          2.41e-161
Time:                        15:14:52   Log-Likelihood:                -1285.2
No. Observations:                 485   AIC:                             2598.
Df Residuals:                     471   BIC:                             2657.
Df Model:                          13                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const         18.8999      4.107      4.602      0.000      10.830      26.969
CRIM          -0.0973      0.024     -4.025      0.000      -0.145      -0.050
ZN             0.0278      0.010      2.651      0.008       0.007       0.048
INDUS         -0.0274      0.046     -0.595      0.552      -0.118       0.063
CHAS           0.9228      0.697      1.324      0.186      -0.447       2.292
NOX           -9.4922      2.856     -3.323      0.001     -15.105      -3.879
RM             5.0921      0.371     13.735      0.000       4.364       5.821
AGE           -0.0305      0.010     -2.986      0.003      -0.051      -0.010
DIS           -1.0562      0.150     -7.057      0.000      -1.350      -0.762
RAD            0.1990      0.049      4.022      0.000       0.102       0.296
TAX           -0.0125      0.003     -4.511      0.000      -0.018      -0.007
PTRATIO       -0.7777      0.098     -7.955      0.000      -0.970      -0.586
B              0.0107      0.002      5.348      0.000       0.007       0.015
LSTAT         -0.2846      0.043     -6.639      0.000      -0.369      -0.200
==============================================================================
Omnibus:                       45.944   Durbin-Watson:                   1.184
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               65.791
Skew:                           0.679   Prob(JB):                     5.17e-15
Kurtosis:                       4.188   Cond. No.                     1.59e+04
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.59e+04. This might indicate that there are
strong multicollinearity or other numerical problems.


R-squared 의 성능점수가 올라간 것을 볼 수 있어.

이렇게 어떤 특정 데이터를 가지고 회귀분석 모델링을 할 때에는 하기 전에 레버리지가 큰 데이터와 아웃라이어의 값을 이러한 절차에 의해 뽑아서 제거하고 모델링을 한다면 더욱 성능이 좋은 회귀분석 모델링을 할 수 있는거야

분산 분석

선형회귀분석의 결과가 얼마나 좋은지는 단순히 잔차제곱합(RSS: Residula Sum of Square)으로 평가할 수 없다. 변수의 단위 즉, 스케일이 달라지면 회귀분석과 상관없이 잔차제곱합도 달라지기 때문이야 ( ex.1km와 1000m)

분산 분석(ANOVA: Analysis of Variance)은 종속변수의 분산과 독립변수의 분산간의 관계를 사용하여 선형회귀분석의 성능을 평가하고자 하는 방법이다. 분산 분석은 서로 다른 두 개의 선형회귀분석의 성능 비교에 응용할 수 있으며 독립변수가 카테고리 변수인 경우 각 카테고리 값에 따른 영향을 정량적으로 분석하는데도 사용할 수 있게 돼

여러 수식들이 존재하지만 내가 이해를 못하겠고 결론은 다음과 같아.

모형 예측치의 움직임의 크기(분산,ESS)은 종속변수의 움직임의 크기(분산,TSS)보다 클 수 없어 그리고 모형의 성능이 좋을수록 모형 예측치의 움직임의 크기는 종속변수의 움직임의 크기와 비슷해진다는 점이야
F 검정을 사용한 변수 중요도 비교
F검정은 각 독립변수의 중요도를 비교하기 위해 사용할 수 있다. 방법은 전체 모형과 각 변수 하나만을 뺀 모형들의 성능을 비교하는 것인데, 이는 간접적으로 각 독립 변수의 영향력을 측정하는 것이라고 할 수 있다. 예를 들어 보스턴 집값 데이터에서 CRIM이란 변수를 뺀 모델과 전체 모델의 비교하는 검정을 하면 이 검정 결과는 CRIM변수의 중요도를 나타낸다.
1
2
3
4
5
6
model_full = sm.OLS.from_formula(
"MEDV ~ CRIM + ZN + INDUS + NOX + RM + AGE + DIS + RAD + TAX + PTRATIO + B + LSTAT + CHAS", data=df0)
model_reduced = sm.OLS.from_formula(
"MEDV ~ ZN + INDUS + NOX + RM + AGE + DIS + RAD + TAX + PTRATIO + B + LSTAT + CHAS", data=df0)

sm.stats.anova_lm(model_reduced.fit(), model_full.fit())
/opt/anaconda3/lib/python3.7/site-packages/scipy/stats/_distn_infrastructure.py:903: RuntimeWarning: invalid value encountered in greater
  return (a < x) & (x < b)
/opt/anaconda3/lib/python3.7/site-packages/scipy/stats/_distn_infrastructure.py:903: RuntimeWarning: invalid value encountered in less
  return (a < x) & (x < b)
/opt/anaconda3/lib/python3.7/site-packages/scipy/stats/_distn_infrastructure.py:1912: RuntimeWarning: invalid value encountered in less_equal
  cond2 = cond0 & (x <= _a)

df_resid ssr df_diff ss_diff F Pr(>F)
0 493.0 11322.004277 0.0 NaN NaN NaN
1 492.0 11078.784578 1.0 243.219699 10.801193 0.001087
anova_lm 명령에서는 typ 인수를 2로 지정하면 하나 하나의 변수를 뺀 축소 모형에서의 F 검정값을 한꺼번에 계산할 수 있다.
아노바 분석 - F검정
1
2
3
4
model = sm.OLS.from_formula(
"MEDV ~ CRIM + ZN + INDUS + NOX + RM + AGE + DIS + RAD + TAX + PTRATIO + B + LSTAT + CHAS", data=df0)
result = model.fit()
sm.stats.anova_lm(result, typ=2)

sum_sq df F PR(>F)
CRIM 243.219699 1.0 10.801193 1.086810e-03
ZN 257.492979 1.0 11.435058 7.781097e-04
INDUS 2.516668 1.0 0.111763 7.382881e-01
NOX 487.155674 1.0 21.634196 4.245644e-06
RM 1871.324082 1.0 83.104012 1.979441e-18
AGE 0.061834 1.0 0.002746 9.582293e-01
DIS 1232.412493 1.0 54.730457 6.013491e-13
RAD 479.153926 1.0 21.278844 5.070529e-06
TAX 242.257440 1.0 10.758460 1.111637e-03
PTRATIO 1194.233533 1.0 53.034960 1.308835e-12
B 270.634230 1.0 12.018651 5.728592e-04
LSTAT 2410.838689 1.0 107.063426 7.776912e-23
CHAS 218.970357 1.0 9.724299 1.925030e-03
Residual 11078.784578 492.0 NaN NaN
각각의 독립변수들의 전체와 비교했을 때 얼마만큼 중요도를 가지는데 정량적으로 나온 결과값이야. 여기서 주목해야할 부분은 PR>(>F)부분으로 summary에서도 나오는 p-value값을 디테일하게 풀어놓은 값이고 예를 들어 LSTAT, RM의 경우 10의 -23승, 10의 -18승으로 수치가 제일 낮은걸 알 수 있어. 그러면 이 2가지의 독립변수가 종속변수에 가장 큰 영향을 미쳤다고 해석하면 되는거야
표의 F값을 보고도 알 수 있지만 F값은 확률의 의미는 없기 때문에 단순 순위를 매기는거 라면 결정할 수 있지만 만약 귀무가설/대립가설을 accept 하냐 reject 하냐의 확률적 의미를 판단한다면 F값만으로는 불가능해
1
2


범주형을 사용한 비선형성
독립변수의 비선형성을 포착하는 또 다른 방법 중 하나는 강제로 범주형 값으로 만드는 것이다. 범주형 값이 되면서 독립변수의 오차가 생기지만 이로 인한 오차보다 비선형성으로 얻을 수 있는 이익이 클 수도 있다.

보스턴 집값 데이터에서 종속변수와 RM 변수의 관계는 선형에 가깝지만 방의 갯수가 아주 작아지거나 아주 커지면 선형모형에서 벗어난다.
1
2
3
plt.figure(figsize=(14,6))
sns.scatterplot(x="RM", y="MEDV", data=df0, s=60)
plt.show()
output_39_0
1
2
3
model_rm = sm.OLS.from_formula('MEDV ~ RM', data=df0)
result_rm = model_rm.fit()
print(result_rm.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                   MEDV   R-squared:                       0.484
Model:                            OLS   Adj. R-squared:                  0.483
Method:                 Least Squares   F-statistic:                     471.8
Date:                Thu, 14 May 2020   Prob (F-statistic):           2.49e-74
Time:                        19:28:18   Log-Likelihood:                -1673.1
No. Observations:                 506   AIC:                             3350.
Df Residuals:                     504   BIC:                             3359.
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept    -34.6706      2.650    -13.084      0.000     -39.877     -29.465
RM             9.1021      0.419     21.722      0.000       8.279       9.925
==============================================================================
Omnibus:                      102.585   Durbin-Watson:                   0.684
Prob(Omnibus):                  0.000   Jarque-Bera (JB):              612.449
Skew:                           0.726   Prob(JB):                    1.02e-133
Kurtosis:                       8.190   Cond. No.                         58.4
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.


이렇게 RM 데이터 전체를 놓고 보면 종속변수 y와 아주 큰 상관관계가 있는것으로 보이지만 위에 그래프에서 봤듯이, 방의 갯수가 아주 적거나, 많으면 선형성을 보이지 않는 구간에 대해 조금 더 디테일하게 상관관게를 보고 싶다면 RM 데이터를 강제로 범주화 시켜 RM 데이터가 가지는 비선형성을 잡을 수 있다.
1
2
3
4
5
6
7
rooms = np.arange(3,10)
labels = [str(r) for r in rooms[:-1]]
df0['CAT_RM'] = np.round(df['RM'])

plt.figure(figsize=(14,6))
sns.barplot('CAT_RM', 'MEDV', data=df0)
plt.show()
output_42_0
이렇게 하면 RM 변수으로 인한 종속변수의 변화를 비선형 상수항으로 모형화 할 수 있다. 선형모형보다 성능이 향상된 것을 볼 수 있다.
1
2
3
model_rm2 = sm.OLS.from_formula("MEDV ~ C(np.round(RM))", data=df0)
result_rm2 = model_rm2.fit()
print(result_rm2.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                   MEDV   R-squared:                       0.537
Model:                            OLS   Adj. R-squared:                  0.532
Method:                 Least Squares   F-statistic:                     115.8
Date:                Thu, 14 May 2020   Prob (F-statistic):           3.57e-81
Time:                        19:33:48   Log-Likelihood:                -1645.6
No. Observations:                 506   AIC:                             3303.
Df Residuals:                     500   BIC:                             3329.
Df Model:                           5                                         
Covariance Type:            nonrobust                                         
==========================================================================================
                             coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------------------
Intercept                 17.0200      2.814      6.049      0.000      11.492      22.548
C(np.round(RM))[T.5.0]    -2.0741      2.998     -0.692      0.489      -7.964       3.816
C(np.round(RM))[T.6.0]     2.3460      2.836      0.827      0.409      -3.226       7.918
C(np.round(RM))[T.7.0]    11.0272      2.869      3.843      0.000       5.389      16.665
C(np.round(RM))[T.8.0]    28.5425      3.093      9.228      0.000      22.466      34.619
C(np.round(RM))[T.9.0]    23.6133      4.595      5.139      0.000      14.586      32.641
==============================================================================
Omnibus:                       81.744   Durbin-Watson:                   0.799
Prob(Omnibus):                  0.000   Jarque-Bera (JB):              467.887
Skew:                           0.542   Prob(JB):                    2.51e-102
Kurtosis:                       7.584   Cond. No.                         31.1
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
시간 독립변수의 변형
독립변수가 시간인 경우에는 특정 시점에서 경과된 시간값으로 변형해야 한다. 일간 전기 사용량 데이터를 예로 들어 설명한다.
1
2
3
4
5
data = sm.datasets.get_rdataset("elecdaily", package="fpp2")

df_elec = data.data.drop(columns=["WorkDay", "Temperature"])
df_elec["Date"] = pd.date_range("2014-1-1", "2014-12-31")
df_elec.tail()

Demand Date
360 173.727990 2014-12-27
361 188.512817 2014-12-28
362 191.273009 2014-12-29
363 186.240144 2014-12-30
364 186.370181 2014-12-31
파이썬 datetime 자료형은 toordinal 명령으로 특정 시점으로부터 경과한 시간의 일단위 값을 구하거나 timestamp 메서드로 초단위 값을 구할 수 있다.
1
2
3
4
5
import datetime as dt

df_elec["Ordinal"] = df_elec.Date.map(dt.datetime.toordinal)
df_elec["Timestamp"] = df_elec.Date.map(dt.datetime.timestamp)
df_elec.tail()

Demand Date Ordinal Timestamp
360 173.727990 2014-12-27 735594 1.419606e+09
361 188.512817 2014-12-28 735595 1.419692e+09
362 191.273009 2014-12-29 735596 1.419779e+09
363 186.240144 2014-12-30 735597 1.419865e+09
364 186.370181 2014-12-31 735598 1.419952e+09
여기에서는 일단위 시간 값을 사용하여 회귀분석을 한다. 시간 값의 경우 크기가 크므로 반드시 스케일링을 해 주어야 한다.
1
2
3
model5 = sm.OLS.from_formula("Demand ~ scale(Ordinal)", data=df_elec)
result5 = model5.fit()
print(result5.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                 Demand   R-squared:                       0.031
Model:                            OLS   Adj. R-squared:                  0.028
Method:                 Least Squares   F-statistic:                     11.58
Date:                Thu, 14 May 2020   Prob (F-statistic):           0.000739
Time:                        19:35:40   Log-Likelihood:                -1709.7
No. Observations:                 365   AIC:                             3423.
Df Residuals:                     363   BIC:                             3431.
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==================================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
----------------------------------------------------------------------------------
Intercept        221.2775      1.374    160.997      0.000     218.575     223.980
scale(Ordinal)    -4.6779      1.374     -3.404      0.001      -7.381      -1.975
==============================================================================
Omnibus:                       43.105   Durbin-Watson:                   0.677
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               96.485
Skew:                           0.614   Prob(JB):                     1.12e-21
Kurtosis:                       5.199   Cond. No.                         1.00
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.


하지만 시간 독립변수는 이 외에더 다양한 특징들을 숨기고 있다. 예들 들어 연도, 월, 일, 요일 데이터를 별도의 독립변수로 분리하거나 한 달 내에서 몇번째 날짜인지 월의 시작 또는 끝인지를 나타내는 값은 모두 특징값이 될 수 있다. 판다스에서는 dt 특수 연산자를 사용하여 이러한 값을 구할 수 있다.
1
2
3
4
5
6
7
8
9
10
df_elec["Year"] = df_elec['Date'].dt.year
df_elec["Month"] = df_elec.Date.dt.month
df_elec["DayOfYear"] = df_elec.Date.dt.dayofyear
df_elec["DayOfMonth"] = df_elec.Date.dt.daysinmonth
df_elec["DayOfWeek"] = df_elec.Date.dt.dayofweek
df_elec["WeekOfYear"] = df_elec.Date.dt.weekofyear
df_elec["Weekday"] = df_elec.Date.dt.weekday
df_elec["IsMonthStart"] = df_elec.Date.dt.is_month_start
df_elec["IsMonthEnd"] = df_elec.Date.dt.is_month_end
df_elec.tail()

Demand Date Ordinal Timestamp Year Month DayOfYear DayOfMonth DayOfWeek WeekOfYear Weekday IsMonthStart IsMonthEnd
360 173.727990 2014-12-27 735594 1.419606e+09 2014 12 361 31 5 52 5 False False
361 188.512817 2014-12-28 735595 1.419692e+09 2014 12 362 31 6 52 6 False False
362 191.273009 2014-12-29 735596 1.419779e+09 2014 12 363 31 0 1 0 False False
363 186.240144 2014-12-30 735597 1.419865e+09 2014 12 364 31 1 1 1 False False
364 186.370181 2014-12-31 735598 1.419952e+09 2014 12 365 31 2 1 2 False True
이렇게 추가적인 특징값을 이용하여 구한 모형은 성능이 향상된다.
1
2
3
4
5
6
7
8
9
10
11
feature_names = df_elec.columns.tolist()
feature_names.remove("Demand")
feature_names.remove("Date")

formula = """
Demand ~ scale(Ordinal) + C(Month) + DayOfYear +
C(DayOfMonth) + C(DayOfWeek) + C(Weekday) + C(IsMonthStart) + C(IsMonthEnd)
"""
model6 = sm.OLS.from_formula(formula, data=df_elec)
result6 = model6.fit()
print(result6.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                 Demand   R-squared:                       0.537
Model:                            OLS   Adj. R-squared:                  0.511
Method:                 Least Squares   F-statistic:                     19.98
Date:                Thu, 14 May 2020   Prob (F-statistic):           4.74e-46
Time:                        19:37:49   Log-Likelihood:                -1574.8
No. Observations:                 365   AIC:                             3192.
Df Residuals:                     344   BIC:                             3273.
Df Model:                          20                                         
Covariance Type:            nonrobust                                         
===========================================================================================
                              coef    std err          t      P>|t|      [0.025      0.975]
-------------------------------------------------------------------------------------------
Intercept                  58.6105      2.423     24.188      0.000      53.844      63.377
C(Month)[T.2]              14.5730      4.587      3.177      0.002       5.551      23.595
C(Month)[T.3]              -1.2369      8.663     -0.143      0.887     -18.276      15.802
C(Month)[T.4]             -29.1875     10.239     -2.851      0.005     -49.326      -9.049
C(Month)[T.5]              23.4037     15.493      1.511      0.132      -7.069      53.876
C(Month)[T.6]              11.3667      3.758      3.024      0.003       3.974      18.759
C(Month)[T.7]              64.8095     22.750      2.849      0.005      20.063     109.556
C(Month)[T.8]              66.5692     26.490      2.513      0.012      14.467     118.671
C(Month)[T.9]              22.7687      9.491      2.399      0.017       4.100      41.437
C(Month)[T.10]             59.0491     33.895      1.742      0.082      -7.619     125.717
C(Month)[T.11]             33.4276     16.778      1.992      0.047       0.427      66.429
C(Month)[T.12]             72.2523     41.334      1.748      0.081      -9.047     153.552
C(DayOfMonth)[T.30]        38.3755     13.530      2.836      0.005      11.763      64.988
C(DayOfMonth)[T.31]         5.6620      7.806      0.725      0.469      -9.691      21.015
C(DayOfWeek)[T.1]           3.4766      1.829      1.900      0.058      -0.121       7.075
C(DayOfWeek)[T.2]           1.5756      1.821      0.865      0.387      -2.006       5.157
C(DayOfWeek)[T.3]           2.8568      1.831      1.560      0.120      -0.745       6.459
C(DayOfWeek)[T.4]           0.8832      1.831      0.482      0.630      -2.719       4.485
C(DayOfWeek)[T.5]         -12.8982      1.831     -7.045      0.000     -16.499      -9.297
C(DayOfWeek)[T.6]         -16.4623      1.829     -8.999      0.000     -20.060     -12.864
C(Weekday)[T.1]             3.4766      1.829      1.900      0.058      -0.121       7.075
C(Weekday)[T.2]             1.5756      1.821      0.865      0.387      -2.006       5.157
C(Weekday)[T.3]             2.8568      1.831      1.560      0.120      -0.745       6.459
C(Weekday)[T.4]             0.8832      1.831      0.482      0.630      -2.719       4.485
C(Weekday)[T.5]           -12.8982      1.831     -7.045      0.000     -16.499      -9.297
C(Weekday)[T.6]           -16.4623      1.829     -8.999      0.000     -20.060     -12.864
C(IsMonthStart)[T.True]     1.2012      5.781      0.208      0.836     -10.169      12.571
C(IsMonthEnd)[T.True]       4.7608      5.781      0.824      0.411      -6.609      16.131
scale(Ordinal)           -101.7884      4.209    -24.182      0.000    -110.068     -93.509
DayOfYear                   0.6769      0.085      7.926      0.000       0.509       0.845
==============================================================================
Omnibus:                      150.460   Durbin-Watson:                   0.577
Prob(Omnibus):                  0.000   Jarque-Bera (JB):             1586.415
Skew:                           1.422   Prob(JB):                         0.00
Kurtosis:                      12.809   Cond. No.                     1.05e+18
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The smallest eigenvalue is 1.49e-29. This might indicate that there are
strong multicollinearity problems or that the design matrix is singular.
1
2


1
2


Linear Regression with scale, categorical regression, and partial regression

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import matplotlib
from matplotlib import font_manager, rc
import platform

try :
if platform.system() == 'windows':
# windows의 경우
font_name = font_manager.FomntProperties(fname="c:/Windows/Font")
rc('font', family = font_name)
else:
# mac의 경우
rc('font', family = 'AppleGothic')
except :
pass

matplotlib.rcParams['axes.unicode_minus'] = False
스케일링
스크린샷 2020-05-13 오후 6 20 21
1
2


이 summary report는 어제 보스턴 집값 데이터를 활용하여 선형회귀분석을 한 결과값이야. 아랫부분의 Cond. No. 라고 쓰여져 있는 부분인데 조건수(conditional number)는 가장 큰 고유치와 가장 작은 고유치의 비율을 뜻해.
1
2
3
4
5
6
7
8
from sklearn.datasets import load_boston

boston = load_boston()

dfx = pd.DataFrame(boston.data, columns=boston.feature_names)
dfy = pd.DataFrame(boston.target, columns=["MEDV"])
df = pd.concat([dfx,dfy],axis=1)
df

CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT MEDV
0 0.00632 18.0 2.31 0.0 0.538 6.575 65.2 4.0900 1.0 296.0 15.3 396.90 4.98 24.0
1 0.02731 0.0 7.07 0.0 0.469 6.421 78.9 4.9671 2.0 242.0 17.8 396.90 9.14 21.6
2 0.02729 0.0 7.07 0.0 0.469 7.185 61.1 4.9671 2.0 242.0 17.8 392.83 4.03 34.7
3 0.03237 0.0 2.18 0.0 0.458 6.998 45.8 6.0622 3.0 222.0 18.7 394.63 2.94 33.4
4 0.06905 0.0 2.18 0.0 0.458 7.147 54.2 6.0622 3.0 222.0 18.7 396.90 5.33 36.2
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
501 0.06263 0.0 11.93 0.0 0.573 6.593 69.1 2.4786 1.0 273.0 21.0 391.99 9.67 22.4
502 0.04527 0.0 11.93 0.0 0.573 6.120 76.7 2.2875 1.0 273.0 21.0 396.90 9.08 20.6
503 0.06076 0.0 11.93 0.0 0.573 6.976 91.0 2.1675 1.0 273.0 21.0 396.90 5.64 23.9
504 0.10959 0.0 11.93 0.0 0.573 6.794 89.3 2.3889 1.0 273.0 21.0 393.45 6.48 22.0
505 0.04741 0.0 11.93 0.0 0.573 6.030 80.8 2.5050 1.0 273.0 21.0 396.90 7.88 11.9

506 rows × 14 columns

이것은 일부러 TAX변수를 크게 만들어 조건수를 증폭시켜본 데이터야
1
2
3
4
5
6
7
8
import statsmodels.api as sm
dfX = sm.add_constant(dfx)
dfX2 = dfX.copy()
dfX2["TAX"] *= 1e13
df2 = pd.concat([dfX2, dfy], axis=1)
model2 = sm.OLS.from_formula("MEDV ~ " + "+".join(boston.feature_names), data=df2)
result2 = model2.fit()
print(result2.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                   MEDV   R-squared:                       0.333
Model:                            OLS   Adj. R-squared:                  0.329
Method:                 Least Squares   F-statistic:                     83.39
Date:                Wed, 13 May 2020   Prob (F-statistic):           8.62e-44
Time:                        16:03:11   Log-Likelihood:                -1737.9
No. Observations:                 506   AIC:                             3484.
Df Residuals:                     502   BIC:                             3501.
Df Model:                           3                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept     -0.0038      0.000     -8.543      0.000      -0.005      -0.003
CRIM          -0.1567      0.046     -3.376      0.001      -0.248      -0.066
ZN             0.1273      0.016      7.752      0.000       0.095       0.160
INDUS         -0.1971      0.019    -10.433      0.000      -0.234      -0.160
CHAS           0.0034      0.000     12.430      0.000       0.003       0.004
NOX           -0.0023      0.000     -9.285      0.000      -0.003      -0.002
RM             0.0267      0.002     14.132      0.000       0.023       0.030
AGE            0.1410      0.017      8.443      0.000       0.108       0.174
DIS           -0.0286      0.004     -7.531      0.000      -0.036      -0.021
RAD            0.1094      0.018      6.163      0.000       0.075       0.144
TAX         1.077e-15   2.66e-16      4.051      0.000    5.55e-16     1.6e-15
PTRATIO       -0.1124      0.011    -10.390      0.000      -0.134      -0.091
B              0.0516      0.003     19.916      0.000       0.046       0.057
LSTAT         -0.6569      0.056    -11.790      0.000      -0.766      -0.547
==============================================================================
Omnibus:                       39.447   Durbin-Watson:                   0.863
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               46.611
Skew:                           0.704   Prob(JB):                     7.56e-11
Kurtosis:                       3.479   Cond. No.                     1.19e+17
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.19e+17. This might indicate that there are
strong multicollinearity or other numerical problems.


조건수(Conditional No.)가 1000조 수준으로 증가한 것을 볼 수 있지? 오른쪽 제일 상단에 보이는 R-squared라는 값으로 표시되는 성능지표도 크게 감소한것을 볼 수 있어. R-squared 는 이 모델 성능에 대해 몇점인지를 알려주는 기능이라고 보면 되(0.333으로 나왔으니 100점 만점에 33.3점이라는 소리야)

statsmodels에서는  scale() 이라는 명령을 사용하여 스케일링을 할 수 있는데, 이 방식으로 스케일을 하면 스케일링에 사용된 평균과 표준편차를 저장하였다가 나중에 predict() 라는 명령을 사용할 때도 같은 스케일을 사용하기 때문에 편리한 것을 알 수 있어. 다만! 스케일링을 할 때에는 카테고리 변수, 즉 범주형 데이터는 스케일링을 하지 않는다는 것에 주의 해주면 되.
1
2
3
4
5
6
feature_names = list(boston.feature_names)
feature_names.remove("CHAS")
feature_names = ['scale({})'.format(name) for name in feature_names] + ['CHAS']
model3 = sm.OLS.from_formula("MEDV ~ " + "+".join(feature_names), data=df2)
result3 = model3.fit()
print(result3.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                   MEDV   R-squared:                       0.741
Model:                            OLS   Adj. R-squared:                  0.734
Method:                 Least Squares   F-statistic:                     108.1
Date:                Wed, 13 May 2020   Prob (F-statistic):          6.72e-135
Time:                        16:11:05   Log-Likelihood:                -1498.8
No. Observations:                 506   AIC:                             3026.
Df Residuals:                     492   BIC:                             3085.
Df Model:                          13                                         
Covariance Type:            nonrobust                                         
==================================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
----------------------------------------------------------------------------------
Intercept         22.3470      0.219    101.943      0.000      21.916      22.778
scale(CRIM)       -0.9281      0.282     -3.287      0.001      -1.483      -0.373
scale(ZN)          1.0816      0.320      3.382      0.001       0.453       1.710
scale(INDUS)       0.1409      0.421      0.334      0.738      -0.687       0.969
scale(NOX)        -2.0567      0.442     -4.651      0.000      -2.926      -1.188
scale(RM)          2.6742      0.293      9.116      0.000       2.098       3.251
scale(AGE)         0.0195      0.371      0.052      0.958      -0.710       0.749
scale(DIS)        -3.1040      0.420     -7.398      0.000      -3.928      -2.280
scale(RAD)         2.6622      0.577      4.613      0.000       1.528       3.796
scale(TAX)        -2.0768      0.633     -3.280      0.001      -3.321      -0.833
scale(PTRATIO)    -2.0606      0.283     -7.283      0.000      -2.617      -1.505
scale(B)           0.8493      0.245      3.467      0.001       0.368       1.331
scale(LSTAT)      -3.7436      0.362    -10.347      0.000      -4.454      -3.033
CHAS               2.6867      0.862      3.118      0.002       0.994       4.380
==============================================================================
Omnibus:                      178.041   Durbin-Watson:                   1.078
Prob(Omnibus):                  0.000   Jarque-Bera (JB):              783.126
Skew:                           1.521   Prob(JB):                    8.84e-171
Kurtosis:                       8.281   Cond. No.                         10.6
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.


독립변수 데이터를 스케일링한것만으로 조건수의 수치가 확 내려간 것을 볼 수 있어. 어때? 쉽지?

조건수를 될 수 있으면 낮춰주는게 각 독립변수의 오차범위를 줄여줄 수 있다고 해. 그래서 큰 값의 데이터들은 스케일링을 통해 사이즈를 줄여주는 거지.
범주형 독립변수의 회귀분석
이번에는 연속형 데이터가 아닌 범주형 데이터의 회귀분석을 하는 방법에 대해 알아보자! 범주형 데이터는 측정 결과가 몇 개의 범주 또는 향목의 형태로 나타나는 자료를 말하는데 그것을 숫자로 표현한 것이라고 할 수 있어. 예를 들면 남자는 1 여자는 0 이런식이지!

아무튼..

여기서 다룰 학습은 그러한 범주형 독립변수(데이터)의 회귀분석 모델링 시 에는 앞서 배운 더미변수화가 필수라는 거야. 풀랭크(full-rank) 방식과 축소랭크(reduced-rank) 방식이 있는데 풀랭크방식에서는 더미변수의 값을 원핫인코딩(one-hot-encoding) 방식으로 지정을 하는거야

예를 들어서..

남자는 1 이고 여자는 0 이면 
남자 : d1=1, d2=0
여자 : d1=0, d2=1 이런식으로 쓴다는 거지

축소랭크 방식에서는 특정한 하나의 범주값을 기준값(reference, baseline)으로 하고 기준값에 대응하는 더미변수의 가중치는 항상 1으로 놓아 계산 하는 방법이지

무슨 말인지 어렵지? 그럼 실 데이터로 예를 들어보도록 할게.

아래의 데이터는 1920년부터 1939년까지 영국 노팅험 지역의 기온을 나타낸 데이터야. 이 데이터에서 독립 변수는 월(monath)이며 범주값으로 처리를 할거야 그리고 value로 표기된 값이 종속변수인 해당 월의 평균 기온이라고 할 수 있지. 분석의 목적은 독립변수인 월 값을 이용하여 종속변수인 월 평균 기온을 예측하는 것이야.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import datetime
from calendar import isleap

def convert_partial_year(number):
#연 단위 숫자에서 날짜를 계산하는 코드
year = int(number)
d = datetime.timedelta(days=(number - year) * (365 + isleap(year)))
day_one = datetime.datetime(year, 1, 1)
date = d + day_one
return date

df_nottem = sm.datasets.get_rdataset("nottem").data

df_nottem["date0"] = df_nottem[["time"]].applymap(convert_partial_year)
df_nottem["date"] = pd.DatetimeIndex(df_nottem["date0"]).round('60min') + datetime.timedelta(seconds=3600*24)
df_nottem["month"] = df_nottem["date"].dt.strftime("%m").astype('category')
del df_nottem["date0"], df_nottem["date"]
df_nottem

time value month
0 1920.000000 40.6 01
1 1920.083333 40.8 02
2 1920.166667 44.4 03
3 1920.250000 46.7 04
4 1920.333333 54.1 05
... ... ... ...
235 1939.583333 61.8 08
236 1939.666667 58.2 09
237 1939.750000 46.7 10
238 1939.833333 46.6 11
239 1939.916667 37.8 12

240 rows × 3 columns

박스플롯을 통해 해당 월에 종속변수데이터가 어디에 주로 모여있는지 확인을 해보는거야
1
2
df_nottem.boxplot("value", "month")
plt.show()
output_14_0
%% 범주형 독립변수의 경우 앞서 시행한 회귀분석에서 추가해준 상수항(add_constant)을 추가하지 않아.
1
2
3
4
5
6
# 풀랭크 방식
model = sm.OLS.from_formula("value ~ C(month) + 0", df_nottem)
result = model.fit()
print(result.summary())

# C()로 카테고리로 처리
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                  value   R-squared:                       0.930
Model:                            OLS   Adj. R-squared:                  0.927
Method:                 Least Squares   F-statistic:                     277.3
Date:                Wed, 13 May 2020   Prob (F-statistic):          2.96e-125
Time:                        16:28:22   Log-Likelihood:                -535.82
No. Observations:                 240   AIC:                             1096.
Df Residuals:                     228   BIC:                             1137.
Df Model:                          11                                         
Covariance Type:            nonrobust                                         
================================================================================
                   coef    std err          t      P>|t|      [0.025      0.975]
--------------------------------------------------------------------------------
C(month)[01]    39.6950      0.518     76.691      0.000      38.675      40.715
C(month)[02]    39.1900      0.518     75.716      0.000      38.170      40.210
C(month)[03]    42.1950      0.518     81.521      0.000      41.175      43.215
C(month)[04]    46.2900      0.518     89.433      0.000      45.270      47.310
C(month)[05]    52.5600      0.518    101.547      0.000      51.540      53.580
C(month)[06]    58.0400      0.518    112.134      0.000      57.020      59.060
C(month)[07]    61.9000      0.518    119.592      0.000      60.880      62.920
C(month)[08]    60.5200      0.518    116.926      0.000      59.500      61.540
C(month)[09]    56.4800      0.518    109.120      0.000      55.460      57.500
C(month)[10]    49.4950      0.518     95.625      0.000      48.475      50.515
C(month)[11]    42.5800      0.518     82.265      0.000      41.560      43.600
C(month)[12]    39.5300      0.518     76.373      0.000      38.510      40.550
==============================================================================
Omnibus:                        5.430   Durbin-Watson:                   1.529
Prob(Omnibus):                  0.066   Jarque-Bera (JB):                5.299
Skew:                          -0.281   Prob(JB):                       0.0707
Kurtosis:                       3.463   Cond. No.                         1.00
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
1
2
3
model = sm.OLS.from_formula("value ~ C(month)", df_nottem)
result = model.fit()
print(result.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                  value   R-squared:                       0.930
Model:                            OLS   Adj. R-squared:                  0.927
Method:                 Least Squares   F-statistic:                     277.3
Date:                Wed, 13 May 2020   Prob (F-statistic):          2.96e-125
Time:                        16:32:20   Log-Likelihood:                -535.82
No. Observations:                 240   AIC:                             1096.
Df Residuals:                     228   BIC:                             1137.
Df Model:                          11                                         
Covariance Type:            nonrobust                                         
==================================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
----------------------------------------------------------------------------------
Intercept         39.6950      0.518     76.691      0.000      38.675      40.715
C(month)[T.02]    -0.5050      0.732     -0.690      0.491      -1.947       0.937
C(month)[T.03]     2.5000      0.732      3.415      0.001       1.058       3.942
C(month)[T.04]     6.5950      0.732      9.010      0.000       5.153       8.037
C(month)[T.05]    12.8650      0.732     17.575      0.000      11.423      14.307
C(month)[T.06]    18.3450      0.732     25.062      0.000      16.903      19.787
C(month)[T.07]    22.2050      0.732     30.335      0.000      20.763      23.647
C(month)[T.08]    20.8250      0.732     28.450      0.000      19.383      22.267
C(month)[T.09]    16.7850      0.732     22.931      0.000      15.343      18.227
C(month)[T.10]     9.8000      0.732     13.388      0.000       8.358      11.242
C(month)[T.11]     2.8850      0.732      3.941      0.000       1.443       4.327
C(month)[T.12]    -0.1650      0.732     -0.225      0.822      -1.607       1.277
==============================================================================
Omnibus:                        5.430   Durbin-Watson:                   1.529
Prob(Omnibus):                  0.066   Jarque-Bera (JB):                5.299
Skew:                          -0.281   Prob(JB):                       0.0707
Kurtosis:                       3.463   Cond. No.                         12.9
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.


축소랭크 방식 ( +0 제거) - '기준이 되는 데이터 값에서  다른 범주형 데이터 값이 얼마나 다르냐' 의 의미로 보면 됨, 즉 1월을 기준으로 2월에는 차이가 얼마나 있느냐 를 나타내는거야. 풀랭크 방식과 축소랭크 방식의 차이를 조금은 알 수 있게된거같아.

이 이상은 내가 이해를 못했기 때문에 넘어가도록 할게.
부분회귀
만약 회귀분석을 한 후에 새로운 독립변수를 추가하여 다시 회귀분석을 한다면 그 전에 회귀분석으로 구했던 가중치의 값은 변할까 변하지 않을까? 예를 들어  𝑥1 이라는 독립변수만으로 회귀분석한 결과가 다음과 같다고 하자.
스크린샷 2020-05-13 오후 4 49 48
이 때 새로운 독립변수  𝑥2 를 추가하여 회귀분석을 하게 되면 이 때 나오는  𝑥1 에 대한 가중치  𝑤′1 가 원래의  𝑤1 과 같을까 다를까?
스크린샷 2020-05-13 오후 4 49 52
답부터 말하자면

일반적으로  𝑤′1 의 값은 원래의  𝑤1 의 값과 다르다.
1
2
3
4
5
6
7
8
9
10
11
12
from sklearn.datasets import load_boston

boston = load_boston()

dfX0 = pd.DataFrame(boston.data, columns=boston.feature_names)
dfX = sm.add_constant(dfX0)
dfy = pd.DataFrame(boston.target, columns=["MEDV"])
df = pd.concat([dfX, dfy], axis=1)

model_boston = sm.OLS(dfy, dfX)
result_boston = model_boston.fit()
print(result_boston.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                   MEDV   R-squared:                       0.741
Model:                            OLS   Adj. R-squared:                  0.734
Method:                 Least Squares   F-statistic:                     108.1
Date:                Wed, 13 May 2020   Prob (F-statistic):          6.72e-135
Time:                        18:01:08   Log-Likelihood:                -1498.8
No. Observations:                 506   AIC:                             3026.
Df Residuals:                     492   BIC:                             3085.
Df Model:                          13                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const         36.4595      5.103      7.144      0.000      26.432      46.487
CRIM          -0.1080      0.033     -3.287      0.001      -0.173      -0.043
ZN             0.0464      0.014      3.382      0.001       0.019       0.073
INDUS          0.0206      0.061      0.334      0.738      -0.100       0.141
CHAS           2.6867      0.862      3.118      0.002       0.994       4.380
NOX          -17.7666      3.820     -4.651      0.000     -25.272     -10.262
RM             3.8099      0.418      9.116      0.000       2.989       4.631
AGE            0.0007      0.013      0.052      0.958      -0.025       0.027
DIS           -1.4756      0.199     -7.398      0.000      -1.867      -1.084
RAD            0.3060      0.066      4.613      0.000       0.176       0.436
TAX           -0.0123      0.004     -3.280      0.001      -0.020      -0.005
PTRATIO       -0.9527      0.131     -7.283      0.000      -1.210      -0.696
B              0.0093      0.003      3.467      0.001       0.004       0.015
LSTAT         -0.5248      0.051    -10.347      0.000      -0.624      -0.425
==============================================================================
Omnibus:                      178.041   Durbin-Watson:                   1.078
Prob(Omnibus):                  0.000   Jarque-Bera (JB):              783.126
Skew:                           1.521   Prob(JB):                    8.84e-171
Kurtosis:                       8.281   Cond. No.                     1.51e+04
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.51e+04. This might indicate that there are
strong multicollinearity or other numerical problems.


이렇게 보면 AGE는 집값을 결정하는데 음의 상관관계를 가진다고 볼 수 있다고 할 수 있어
1
2
sns.regplot(x="AGE", y="MEDV", data=df)
plt.show()
output_25_0
plot_partregress(endog, exog_i, exog_others, data=None, obs_labels=True, ret_coords=False)

endog: 종속변수 문자열
exog_i: 분석 대상이 되는 독립변수 문자열
exog_others: 나머지 독립변수 문자열의 리스트
data: 모든 데이터가 있는 데이터프레임
obs_labels: 데이터 라벨링 여부
ret_coords: 잔차 데이터 반환 여부

하지만! 다른 독립변수에 영향을 받은 AGE가 집값에 영향을 미쳤는지에 대한 부분을 확인해보면 그래프는 다음과 같아.
AGE 데이터에 대한 부분회귀인셈이지.
1
2
3
4
5
6
7
others = list(set(df.columns).difference(set(["MEDV", "AGE"])))
p, resids = sm.graphics.plot_partregress(
"MEDV", "AGE", others, data=df, obs_labels=False, ret_coords=True
)
plt.show()

# 크게 상관이 없다는 거로 나오게 되
output_29_0
sm.graphics.plot_partregress_grid 명령을 쓰면 전체 데이터에 대해 한번에 부분회귀 플롯을 그릴 수 있어.

plot_partregress_grid(result, fig)

result: 회귀분석 결과 객체
fig: plt.figure 객체
1
2
3
4
fig = plt.figure(figsize=(8, 20))
sm.graphics.plot_partregress_grid(result_boston, fig=fig)
fig.suptitle("")
plt.show()
output_32_0
CCPR 플롯
CCPR(Component-Component plus Residual) 플롯도 부분회귀 플롯과 마찬가지로 특정한 하나의 변수의 영향을 살펴보기 위한 것이야

부분회귀분석과 비슷하지만 다른점이 하나 있는데 그것은 위에서 언급한 다른 변수에 영향을 받은 AGE가 아니라 AGE 데이터 그 자체와 집값의 상관관계를 보기위한 방법이라고 보면 되
1
2
sm.graphics.plot_ccpr(result_boston, "AGE")
plt.show()
output_34_0
CCPR 플롯에서는 부분회귀 플롯과 달리 독립변수가 원래의 값 그대로 나타난다는 점을 다시 한번 상기 시켜줄게
1
2
3
4
fig = plt.figure(figsize=(8, 15))
sm.graphics.plot_ccpr_grid(result_boston, fig=fig)
fig.suptitle("")
plt.show()
output_36_0
plot_regress_exog(result, exog_idx)

result: 회귀분석 결과 객체
exog_idx: 분석 대상이 되는 독립변수 문자열
1
2
3
fig = sm.graphics.plot_regress_exog(result_boston, "AGE")
plt.tight_layout(pad=4, h_pad=0.5, w_pad=0.5)
plt.show()
output_38_0

선형회귀분석 정리

선형회귀분석 정리
오늘의 데이터 사이언스 스쿨에서는 본격적으로 제대로 된 선형회귀분석에 대해 배울 수 있었어. 또 배운 내용을 바탕으로 파이썬을 이용하여 패키지를 이용해 직접 구현해볼 수도 있었는데, 요약된 정보들이 가지는 함축적인 의미가 있어. 길고, 어려운 내용들이었지만 간신히 맥락은 잡고 있는 것 같아 잊기 전에 빠른 정리를 통해 복습을 하려고 해. listen.

우선 선형회귀분석이란, 종속 변수 y와 한 개 이상의 독립 변수 x와의 선형 관계를 모델링하는 방법이야. 사실 이런 단어들을 이용해 설명하면 쉬운 것도 어렵게 느껴지기 마련인데, 내가 수업시간에 깨달은 선형회귀분석 내용은 아래와 같아.

스크린샷 2020-05-12 오후 6 31 31

seaborn 데이터셋에 있는 tip 데이터를 가져와봤어. 총 지출 비용, 팁의 금액, 팁을 준 사람의 성별과 흡연 여부, 요일 시간, 함께 온 인원들의 정보 나열되어 있네. 막무가내로 서로 연관성 없이 나열되어 있는 것 같은 이 데이터들 속에서 그 어떤 상관성이 있을까?
가령, 식사 인원이 많으면 많을 수록 팁의 비용이 커지거나, 저녁 타임에 오는 손님이 팁을 더 많이 준다 등 데이터를 통해 이러한 인사이트를 얻어 내야 하는 것인데, 이러한 선형회귀분석은 이러한 데이터의 성별, 흡연여부, 식사 시간대 등과 같은 데이터(독립변수, x)들이 팁(종속변수, y)에 영향을 주는지, 혹은 영향을 주지 않는지, 영향을 주면 어떤 항목이 가장 영향을 많이 주는지 알 수 있는 방법 중에 하나라고 할 수 있지.

그렇다면 팁 데이터를 벡터값 y로 놓고 나머지 벡터들, 즉 나머지 행렬 데이터를 x로 놓고 일반적으로 알고 있는 ‘y = wx’를 만들 수 있겠지? 여기서 기울기에 해당하는 ‘w’가 바로 우리가 알고 싶어 하는 가중치라는 것이야.
x의 항목들(성별, 흡연여부, 식사시간대 등) 중 어떤 항목이 팁이 많고 적음에 상관이 있는지, 즉 팁에 긍정적인 영향을 미쳐서 팁의 금액이 올라가게 하는지, 혹은 부정적인 영향을 미쳐서 팁의 금액을 내려가게 하는지, 혹은 전혀 상관이 없는지 말야.

이 때 wx를 x에 대한 함수로 나타난다면 y와 x 의 관계는 이렇게 정리할 수 있어.

image
(어렵다 참)

아무튼!

여기서 y 위의 ^와 물결표가 붙으면서 좀 더 깊게 들어가게 되는데, ^가 붙은 y를 y hat이라고 해. y는 우리가 마주하고 있는 현실 세계에서 일어난 실제 데이터이고, y hat은 예측한 가중치, w의 영향을 받은 ‘예측값’이라고 할 수 있어. 때문에 우리가 원하는 것은 어떤 값을 가질 지 모르는 가중치 w의 값을 조정하여 우리가 예측한 예측치 y hat과 실제 발생한 데이터 값 y의 차이(잔차)를 줄이는 것이라고 할 수 있지.

image (1)

언급했던 y, y hat, w 모두는 스칼라 값이 아니라 벡터 혹은 행렬의 형태를 갖추고 있어. 위의 사진에서 가중치 값 w는 이 선형회귀 모형의 모수 즉 parameter 야. 그리고 x1, x2 … 는 tip 데이터에서는 종속 변수 tip데이터를 제외한 나머지, 즉 성별, 흡연여부, 식사 시간대 등이 되는거야.

우선 선형회귀분석에 결정론적 방법과 확률론적 방법이라는 2가지 방법이 있어. 결정론적 방법은 단순하게 독립변수 x에 대응하는 종속변수 y 값을 계산하는 함수를 만들어 내는 것인 반면 확률론적 방법은 이름 그대로 x, y 뒤에 어떤 ‘확률 모형’이 숨어져 있다는 가정이 ‘추가’되는데, 이 가정이 추가됨으로써 결정론적 방법보다 더 많은 정보를 가지고 시작하게 된다고 할 수 있지.(비록 가정이라 할지라도) 더 많은 정보를 가지고 시작함으로써 결정론적 방법보다 조금 더 깊은 인사이트를 도출할 수 있어.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import matplotlib
from matplotlib import font_manager, rc
import platform

try :
if platform.system() == 'windows':
# windows의 경우
font_name = font_manager.FomntProperties(fname="c:/Windows/Font")
rc('font', family = font_name)
else:
# mac의 경우
rc('font', family = 'AppleGothic')
except :
pass

matplotlib.rcParams['axes.unicode_minus'] = False
1
2
3
4
5
6
7
8
from sklearn.datasets import load_boston

boston = load_boston()

dfx = pd.DataFrame(boston.data, columns=boston.feature_names)
dfy = pd.DataFrame(boston.target, columns=["MEDV"])
df = pd.concat([dfx,dfy],axis=1)
df

CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT MEDV
0 0.00632 18.0 2.31 0.0 0.538 6.575 65.2 4.0900 1.0 296.0 15.3 396.90 4.98 24.0
1 0.02731 0.0 7.07 0.0 0.469 6.421 78.9 4.9671 2.0 242.0 17.8 396.90 9.14 21.6
2 0.02729 0.0 7.07 0.0 0.469 7.185 61.1 4.9671 2.0 242.0 17.8 392.83 4.03 34.7
3 0.03237 0.0 2.18 0.0 0.458 6.998 45.8 6.0622 3.0 222.0 18.7 394.63 2.94 33.4
4 0.06905 0.0 2.18 0.0 0.458 7.147 54.2 6.0622 3.0 222.0 18.7 396.90 5.33 36.2
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
501 0.06263 0.0 11.93 0.0 0.573 6.593 69.1 2.4786 1.0 273.0 21.0 391.99 9.67 22.4
502 0.04527 0.0 11.93 0.0 0.573 6.120 76.7 2.2875 1.0 273.0 21.0 396.90 9.08 20.6
503 0.06076 0.0 11.93 0.0 0.573 6.976 91.0 2.1675 1.0 273.0 21.0 396.90 5.64 23.9
504 0.10959 0.0 11.93 0.0 0.573 6.794 89.3 2.3889 1.0 273.0 21.0 393.45 6.48 22.0
505 0.04741 0.0 11.93 0.0 0.573 6.030 80.8 2.5050 1.0 273.0 21.0 396.90 7.88 11.9

506 rows × 14 columns

1
sns.pairplot(df[['MEDV','RM']])
<seaborn.axisgrid.PairGrid at 0x1a2a600f90>
output_3_1
1
sns.pairplot(df[['MEDV','CRIM']])
<seaborn.axisgrid.PairGrid at 0x1a2a60d0d0>
output_4_1
1
sns.pairplot(df[['MEDV','AGE']])
<seaborn.axisgrid.PairGrid at 0x1a2adfd150>
output_5_1
1
sns.pairplot(df[['MEDV','CHAS']])
<seaborn.axisgrid.PairGrid at 0x1a2b239d50>
output_6_1
1
2
3
4
5
6
7
8
9
from sklearn.linear_model import LinearRegression

model = LinearRegression().fit(dfx, dfy)
predicted = model.predict(dfx)
plt.scatter(dfy, predicted, s=10)
plt.xlabel("실제 가격")
plt.ylabel("예측 가격")
plt.title("보스턴 주택가격 예측결과")
plt.show()
output_7_0
1
import statsmodels.api as sm
1
2
3
model = sm.OLS(dfy, dfx)
result = model.fit()
result.params
CRIM      -0.092897
ZN         0.048715
INDUS     -0.004060
CHAS       2.853999
NOX       -2.868436
RM         5.928148
AGE       -0.007269
DIS       -0.968514
RAD        0.171151
TAX       -0.009396
PTRATIO   -0.392191
B          0.014906
LSTAT     -0.416304
dtype: float64
1
print(result.summary())
                                 OLS Regression Results                                
=======================================================================================
Dep. Variable:                   MEDV   R-squared (uncentered):                   0.959
Model:                            OLS   Adj. R-squared (uncentered):              0.958
Method:                 Least Squares   F-statistic:                              891.3
Date:                Tue, 12 May 2020   Prob (F-statistic):                        0.00
Time:                        19:14:28   Log-Likelihood:                         -1523.8
No. Observations:                 506   AIC:                                      3074.
Df Residuals:                     493   BIC:                                      3128.
Df Model:                          13                                                  
Covariance Type:            nonrobust                                                  
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
CRIM          -0.0929      0.034     -2.699      0.007      -0.161      -0.025
ZN             0.0487      0.014      3.382      0.001       0.020       0.077
INDUS         -0.0041      0.064     -0.063      0.950      -0.131       0.123
CHAS           2.8540      0.904      3.157      0.002       1.078       4.630
NOX           -2.8684      3.359     -0.854      0.394      -9.468       3.731
RM             5.9281      0.309     19.178      0.000       5.321       6.535
AGE           -0.0073      0.014     -0.526      0.599      -0.034       0.020
DIS           -0.9685      0.196     -4.951      0.000      -1.353      -0.584
RAD            0.1712      0.067      2.564      0.011       0.040       0.302
TAX           -0.0094      0.004     -2.395      0.017      -0.017      -0.002
PTRATIO       -0.3922      0.110     -3.570      0.000      -0.608      -0.176
B              0.0149      0.003      5.528      0.000       0.010       0.020
LSTAT         -0.4163      0.051     -8.197      0.000      -0.516      -0.317
==============================================================================
Omnibus:                      204.082   Durbin-Watson:                   0.999
Prob(Omnibus):                  0.000   Jarque-Bera (JB):             1374.225
Skew:                           1.609   Prob(JB):                    3.90e-299
Kurtosis:                      10.404   Cond. No.                     8.50e+03
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 8.5e+03. This might indicate that there are
strong multicollinearity or other numerical problems.

데이터프레임 병합하기(merge, concat)

복수의 데이터프레임을 하나로 만드는 과정을 만져보자

1
2
df1 = pd.DataFrame({'국어':[87, 69], '수학':[77,96]}, index=['홍길동', '임꺽정'])
df1

국어 수학
홍길동 87 77
임꺽정 69 96
1
2
df2 = pd.DataFrame({'국어':[82,81], '영어':[86,90]}, index=['전봉준','장길산'])
df2

국어 영어
전봉준 82 86
장길산 81 90
1
2
df3 = pd.DataFrame({'국어':[82,81], '영어':[86,90]}, index=['전봉준','장길산'])
df3

국어 영어
전봉준 82 86
장길산 81 90

concat함수

세로로 병합하기(그냥 아래로 붙이는거)

데이터프레임끼리 컬럼이 달라도 된다. (없는 컬럼엔 NaN값으로 알아서 채워짐)
근데, 데이터프레임간에 컬럼이 서로 다르면 sort=False를 넣어줘야 경고가 발생하지 않아

[sort 파라미터는 컬럼 이름을 정렬해주는 옵션]
1
2
df_concat1 = pd.concat([df1, df2, df3], sort=False)
df_concat1

국어 수학 영어
홍길동 87 77.0 NaN
임꺽정 69 96.0 NaN
전봉준 82 NaN 86.0
장길산 81 NaN 90.0
전봉준 82 NaN 86.0
장길산 81 NaN 90.0
가로로 병합하기 (위에 언급했듯이 axis=1 옵션만 주면 되)
1
2
df_concat2 = pd.concat([df1, df2, df3], sort=False, axis=1)
df_concat2

국어 수학 국어 영어 국어 영어
홍길동 87.0 77.0 NaN NaN NaN NaN
임꺽정 69.0 96.0 NaN NaN NaN NaN
전봉준 NaN NaN 82.0 86.0 82.0 86.0
장길산 NaN NaN 81.0 90.0 81.0 90.0

쉽지?? 넘어가도록 할게

1
2


merge함수

공통 컬럼을 기준으로 병합하기 가능
1
2
3
pd.merge(df1, df2)

df1이랑 df2는 서로 겹치는 게 없어서 컬럼만 나오네

국어 수학 영어
1
2
3
4
pd.merge(df1, df2, how='outer')

서로 겹치지 않는 부분은 그냥 NaN으로 채우면서 서로 병합하는거야
방법은 how = 'outer' 파라미터를 쓰면 돼

국어 수학 영어
0 87 77.0 NaN
1 69 96.0 NaN
2 82 NaN 86.0
3 81 NaN 90.0
how 파라미터는 outer, inner만 있는게 아니야.
left, right도 있어
1
2
3
4
pd.merge(df1, df2, how='left')

왼쪽꺼를 기준으로 놓고, 오른쪽의 데이터를 가져와서 합병시키되,
오른쪽에서 가져올 데이터가 없는 자리에는 NaN값으로 채워 넣어줘

국어 수학 영어
0 87 77 NaN
1 69 96 NaN
1
2
3
pd.merge(df1, df2, how='right')

마찬가지로 이거는 오른쪽을 기준으로

국어 수학 영어
0 82 NaN 86
1 81 NaN 90
merge 함수와 비슷한 기능의 join 이라는 함수도 있어

근데 join함수는 merge랑 완전 같은 기능이라 따로 정리는 안할거야
이러한 기능이 필요할 땐 merge함수를 쓰면 되지

1
2


1
2


중복되는 데이터가 존재하는 경우의 열단위 병합(merge)

  • 어떻게든 조합을 만들어내니까 너무 걱정마
1
2
df_1 = pd.DataFrame({'아이디':['a','b','c','d'], '결제금액':[1000, 1200, 1700, 3200]})
df_1

아이디 결제금액
0 a 1000
1 b 1200
2 c 1700
3 d 3200
1
2
df_2 = pd.DataFrame({'아이디':['a','b','c','d'], '적립금':[120, 1700, 200, 320]})
df_2

아이디 적립금
0 a 120
1 b 1700
2 c 200
3 d 320
1
pd.merge(df_1, df_2)

아이디 결제금액 적립금
0 a 1000 120
1 b 1200 1700
2 c 1700 200
3 d 3200 320

일단 기본 merge를 시켜서 모든 경우의수를 다 봐
그리고 나서 수정을 하든말든 오키?

겹치는 컬럼이 2개 이상인 경우에는?

간단해. 이럴때는 ‘on’ 이라는 파라미터를 사용하면 on값을 기준으로 merge가 되

1
2
3
4
df_a = pd.DataFrame({'고객명':['길동','길산'],
'데이터':['2000','1700'],
'날짜':['2020-05-08', '2020-06-08']})
df_a

고객명 데이터 날짜
0 길동 2000 2020-05-08
1 길산 1700 2020-06-08
1
2
3
4
df_b = pd.DataFrame({'고객명':['길동','길산'],
'데이터':['21세','17세'],
})
df_b

고객명 데이터
0 길동 21세
1 길산 17세
1
pd.merge(df_a, df_b)

고객명 데이터 날짜

merge가 되지 않아. 왜냐믄 공통되는 컬럼이 2개가 되니깐 둘 다 참조를 하게되서.. 두 컬럼 사이에 교집합이 없으니 merge를 해도 소용이 없는거야

1
pd.merge(df_a, df_b, on='고객명')

고객명 데이터_x 날짜 데이터_y
0 길동 2000 2020-05-08 21세
1 길산 1700 2020-06-08 17세

자 on 파라미터로 기준을 고객명으로 줬더니 출력이 됐어.
이거를 보면 알 수 있듯이, 기준열은 아니면서 이름이 같은 열인 경우에는 _x 와 _y가 붙어

1
2


_x 랑 _y가 좀 그렇지? 그러면 컬럼명을 변경을 하자

1
2
3
xx = pd.merge(df_a, df_b, on='고객명')
xx = xx.rename(columns={'데이터_x': '금액', '데이터_y':'나이'})
xx

고객명 금액 날짜 나이
0 길동 2000 2020-05-08 21세
1 길산 1700 2020-06-08 17세

Good Job!

1
2


공통 컬럼은 존재하지 않지만, 우리가 이름이 다른 두 컬럼을 지정해서 merge하라고 명령 할수도 있어
1
df_a

고객명 데이터 날짜
0 길동 2000 2020-05-08
1 길산 1700 2020-06-08
1
2
df_b = df_b.rename(columns={'고객명':'이름'})
df_b

이름 데이터
0 길동 21세
1 길산 17세

자 해보자

1
2


1
2
merged = pd.merge(df_a, df_b, left_on='고객명', right_on='이름')
merged

고객명 데이터_x 날짜 이름 데이터_y
0 길동 2000 2020-05-08 길동 21세
1 길산 1700 2020-06-08 길산 17세
왼쪽의 고객명과 오른쪽의 이름이 같은 데이터를 병합하라는 의미네. ㅇㅋ 이렇게 되는구나. 그럼 이제 겹치는 컬럼을 지우자
1
2
merged.drop('이름',axis=1, inplace=True)
merged

고객명 데이터_x 날짜 데이터_y
0 길동 2000 2020-05-08 21세
1 길산 1700 2020-06-08 17세
1
2


??? : merge는 항상 컬럼 기준이야??

오~ 너 참 똑똑이구나?

1
2


Index를 기준으로 당연히 merge가 되

left_index, right_index 파라미터를 이용하면되는데,, 일단 해보자고

1
2


1
2
역사 = pd.DataFrame({'역사':[90,82]}, index=['필구','봉구'])
역사

역사
필구 90
봉구 82
1
2
수학 = pd.DataFrame({'수학':[81,92]}, index=['필구','맹구'])
수학

수학
필구 81
맹구 92
1
2
역사수학 = pd.merge(역사, 수학, left_index=True, right_index=True)
역사수학

역사 수학
필구 90 81

두 데이터에서 겹치는 index인 필구만 잡아서 추가해주네 ㅇㅋ?

1
2
역사수학 = pd.merge(역사, 수학, left_index=True, right_index=True, how='outer')
역사수학

역사 수학
맹구 NaN 92.0
봉구 82.0 NaN
필구 90.0 81.0
1
2


그러면 이런 경우에는 어떻게 해야하는 거야?

1
2
역사 = pd.DataFrame({'역사':[90,82]}, index=['필구','봉구'])
역사

역사
필구 90
봉구 82
1
2
수학 = pd.DataFrame({'수학':[81,92],'이름':['필구','봉구']})
수학

수학 이름
0 81 필구
1 92 봉구

이 두개를 merge하고 싶은데,
서로 참조시킬 것이 하나는 index에 있고, 다른 하나는 column으로 갖고 있잖아..

이럴때 바로 left/right_index와 left/right_on을 응용해서 쉐킷쉐킷!

1
2


1
2
역사수학_ = pd.merge(역사,수학, left_index=True, right_on='이름')
역사수학_

역사 수학 이름
0 90 81 필구
1 82 92 봉구

정리만 해주고 끝내자 힘들다!

1
2
3
역사수학_.index = 역사수학_['이름'].values
역사수학_.drop('이름', axis=1, inplace=True)
역사수학_

역사 수학
필구 90 81
봉구 82 92