안녕하세요. 우주신 입니다.

 

 

약 3년만에 포스팅을 하네요... 일을 하다보니 포스팅을 꾸준히 못 하고 있습니다..ㅠ

오늘은 블로그에서 가장 조회수가 높은 '[R] 상관분석...' 글을 Python으로 빠르게 변환 해봤습니다.

이번 포스팅과 다음 포스팅에서는 상관분석과 회귀분석에 대해 정리해보겠습니다.

 

우리는 종종 어떤 두 사건 간의 연관성을 분석해야 할 경우가 많습니다.

둘 또는 그 이상의 변수들이 서로 관련성을 가지고 변화할 때 그 관계를 분석해야 하는데,

가장 잘 알려진 방법 중 하나가 상관분석회귀분석 입니다.

 

예를 들어, GDP와 기대수명 간의 관계, 키와 몸무게 간의 관계를 보자면,

각각 두 변수 간의 선형적 관계를 상관(Correlation)이라고 하며, 이러한 관계에 대한 분석을 상관분석(correlation analysis)라고 합니다.

 

이번 예시에서는 당뇨와 그에 영향을 미치는 변수들 간의 관계를 분석해 보죠.

먼저 데이터는 sklearn에서 제공하는 datasets을 불러왔습니다.

import pandas as pd
import numpy as np

from sklearn import datasets
data = datsets.load_diabetes()

데이터가 dictionary 형태이므로 어떤 key를 가지는지 확인해보면 아래와 같이 나오고,

여기서 data, target, feature_names 세 가지 key만 쓰겠습니다. 당연히 데이터 형태의 길이가 같은지 부터 확인해야죠.

 

여기서 target이 당뇨병의 수치이고 나머지 feature names에 속하는 age, sex, bmi 등등은 변수라고 보면 됩니다.

즉, 442명의 사람들을 상대로 10가지의 특성들을 나열한거죠.

 

우리는 bmi(체질량지수) 변수와 당뇨병의 수치(target)가 어떤 관계를 가지는지 한번 살펴봅시다.

 

1. 산점도 (Scatter plot)

먼저, 상관계수를 파악하기 전에 산점도를 그려 두 변수 간에 관련성을 시각적으로 파악할 수 있습니다.

X = df.bmi.values
Y = df.index.values

import matplotlib.pyplot as plt
plt.scatter(X, Y, alpha=0.5)
plt.title('TARGET ~ BMI')
plt.xlabel('BMI')
plt.ylabel('TARGET')
plt.show()

matplotlib에서 제공하는 scatter()를 통해 그린 결과 입니다.

대략 봤을 때 두 변수는 서로 양의 관계를 이루고 있는 것 같죠?

 

 

2. 공분산(Covariance) 및 상관계수(Correlation Coefficient)

산점도를 이용하면 두 변수간의 직선적인 관계를 대략적으로 파악은 가능하지만, 두 변수 사이의 관계를 어떠한 수치로 표현하지는 않아요. 그렇기에 우리는 두 변수 간의 관계를 수치로 표현하기 위해 공분산 및 상관계수를 이용합니다.

 

공분산은 2개의 확률변수의 상관정도를 나타내는 값인데, 만약 2 개의 변수 중 하나의 값이 상승하는 경향을 보일 때 다른 값도 상승하면 공분산의 값은 양수, 반대로 다른 값이 하강하는 경향을 보이면 공분산의 값은 음수가 나옵니다.

 

여러가지 방식으로 구할 수 있는데,

직접 식을 계산하면,

더 편하게는 numpycov()를 이용하면 되죠.

두 방법 모두 비슷한 값이 나왔고 양의 값이 나온 것을 볼 수 있죠.

 

그러나 공분산은 상관관계의 상승 혹은 하강하는 경향을 이해할 수는 있으나 2개 변수의 측정 단위의 크기에 따라 값이 달라지므로 절대적 정도를 파악하기에는 한계가 있습니다. 즉, 2.15가 어느 정도의 양의 상관관계인지를 가늠하기가 쉽지 않죠.

 

그래서 공분산을 표준화 시킨 상관계수를 보다 많이 이용합니다.

상관계수는 각 변수의 표준편차를 분모로 나눠주면 되죠.

당연히, numpy는 없는게 없죠. corrcoef() 함수를 이용하면,

상관계수는 -1에서 1 사이의 값을 가지기에 0일 경우에는 두 변수 간의 선형관계가 전혀 없다는 것을 뜻 합니다.

보통 0.3과 0.7 사이이면, 뚜렷한 양적 선형관계로 0.7과 1.0 사이는 강한 양적 선형관계로 간주한다고 합니다.

(그러나 데이터의 특성과 샘플의 대표성 등 상황에 따라 상관계수 값 자체를 해석하는데 있어 정확한 기준은 없습니다)

 

위에 나온 0.58은 BMI(체질량지수)와 당뇨병수치(Target)는 뚜렷한 양적 선형관계를 이루고 있다고 볼 수 있습니다.

 

주의할 점은 상관계수 분석 자체가 특이 값에 민감하게 반응하기 때문에 데이터 pre-processing에 항상 주의를 기울여야 합니다.

또한 상관관계는 두 변수 간의 관련성을 의미할 뿐, 원인과 결과의 방향을 알려주지는 않습니다.

 

 

3. 상관계수의 검정

상관계수 값 자체가 유의미한가를 검정할 수도 있습니다. 그 중 하나로 p-value를 많이 이용하는데,

scipy 패키지의 stats.pearsonr()을 이용하면 상관계수와 p-value를 동시에 얻을 수 있습니다.

import scipy.stats as stats
stats.pearsonr(X,Y)

뒤 결과 값이 p-value인데, 귀무가설 "상관관계가 없다"에 대한 검정 결과 p-value가 3.46e-42라는 0에 아주 매우 가까운 값이 나왔으므로 귀무가설을 기각할 수 있음을 알 수 있습니다.

 

 

4. 그 외

그냥 궁금해서 나머지 변수들도 상관계수를 확인해 봤습니다.

당뇨병수치와 가장 상관관계가 높은 것은 bmi이고 age나 sex는 큰 관련이 없는 것으로 보이네요.

 

다음 시간에는 회귀분석에 대해 다뤄보겠습니다~


안녕하세요. 우주신 입니다.


저번 포스팅에 이어서 연관규칙 알고리즘의 Apriori 알고리즘에 대해 글을 쓰겠습니다.


저번 포스팅에서 연관규칙분석 개념 및 Apriori 알고리즘에 대해 알아봤으니,

이번에는 파이썬 코드를 보며 한번 더 복습해보자.

(지난 포스트의 지식을 다 안다는 전제하에 코드만 설명)


내가 테스트한 트랜잭션 데이터베이스(Transaction Database)는 아래와 같은 양식이다.

각 줄이 itemset을 구분하며, 1번 itemset은 7번 item과 14번 item으로 구성되어 있다고 보면 된다.


Apriori 알고리즘은 아래와 같은 순서로 진행된다.

1. 트랜잭션 데이터베이스를 스캔하면서 1-빈번항목집합을 구한다.

2. k-빈번항목집합을 대상으로 (k+1)-빈번항목집합을 구한다.

- Self Join과 Prune을 통해 후보(Candidate)를 구하고,
- 트랜잭션 데이터베이스를 스캔하면서 최소지지도 조건을 만족하는 후보만 도출한다.

3. 더 이상 (k+1)-빈번항목집합이 만들어지지 않을 때까지 2번 과정을 반복한다.


[메인함수]부터 보자.

193:: 파일을 실행할 때, Transaction Database(input.txt), 최소지지도(min_sup), 결과출력파일(output.txt)을 인자로 넣는다

198:: input.txt로부터 데이터를 로딩한다

200:: 빈번항목집합을 담을 set을 만들고, generate_first_frequent_set()을 통해 1-빈번항목집합을 만든다

204:: 반복문을 돌며 k-빈번항목집합을 대상으로 (k+1)-빈번항목집합을 구한다

208:: k-빈번항목집합을 대상으로 Self Join을 한다

210:: 더 이상 Self Join이 되지 않을 때는 프로그램을 종료한다

215:: Self Join 이후, Prune 과정을 거친다.

- prune() 함수 안에서 후보를 뽑고 그 후보들을 대상으로 최소지지도를 확인한 후 (k+1)-빈번항목집합까지 구한다

218:: (k+1)-빈번항목집합을 구한 후, Association Rule을 통해 지지도(Support)와 신뢰도(Confidence)를 구한다

220:: (k+1)-빈번항목집합이 생성되지 않았으면 종료하고

224:: (k+1)-빈번항목집합이 생성되었으면, frequent_set에 (k+1)-빈번항목집합을 추가하고 길이를 1 추가한다


[1-빈번항목집합을 생성하는 함수]

33:: 여기서 trxes는 전체 트랜잭션 데이터베이스를 가리킨다

34:: item_set을 딕셔너리 형태로 만들어 key = 아이템, value = 갯수로 저장한다

35:: trxes의 itemset의 item들을 방문하며

37:: item_set의 key에 없으면 value를 1로 추가하고 key가 있다면 value를 1씩 증가하며 count 한다

42:: 최소지지도 조건을 만족하지 않는 후보들은 제거하고 1-빈번항목집합을 반환한다


[최소지지도로 아이템을 거르는 함수]

53:: 인자로 받은 후보(candidate)를 바탕으로 최소지지도보다 큰 key들만 빈번항목집합(frequent_set)에 넣는다

56:: 빈번항목집합의 아이템이 하나도 없으면 종료한다


[Self Join]

78:: Self Join을 하기 위해 k-빈번항목집합을 인자로 받는다

81:: 길이가 1인 1-빈번항목집합의 경우 바로 조합이 가능하기 때문에 케이스를 나누었다

85:: 길이가 2 이상인 빈번항목집합들을 가지고 조합을 만들기 전에 중복되지 않는 모든 item을 뽑는다

92:: itertools 모듈의 combinations 함수를 이용하여 가능한 모든 조합을 만들었다


참고로 set 자료형을 쓰기 위해 아래와 같이 리스트 안의 아이템(element)들을 set으로 바꾸는 함수를 따로 만들었다


[Prune]

106:: 이전 빈번항목집합의 길이가 1일 때와 2 이상일 때 케이스를 나누어 가지치기 하였다

117:: 가지치기 원리는 Self Join한 후보들을 대상으로 각각의 itemset의 item들 중 

126:: 이전 빈번항목집합에 없는 item이 하나라도 있으면 후보에서 제외한다

135:: prune 함수에 트랜잭션 데이터베이스를 스캔하며 Count하는 기능도 함께 넣었다

142:: 최소지지도 조건에 만족하는 후보들을 대상으로 (k+1)-빈번항목집합을 반환한다


[Association Rule]

위 함수는 지지도(Support)와 신뢰도(Confidence)를 반환해준다

162:: 지지도

168:: 신뢰도


[output.txt 출력 결과]

서로 다른 두 아이템 간의 지지도(Support)와 신뢰도(Confidence)를 구하여 output.txt 파일에 저장한 결과이다.


코드를 설명하면서 다시 보니 좀 더 효율적으로 코딩할 수 있는 부분이 보이네요.

미숙한 저의 코드는 참고만 해주시고 조금이나마 도움 됐으면 싶습니다.

Full Code는 git에 올렸습니다.



수고하셨습니다.





안녕하세요. 우주신 입니다.



이번 포스팅에서는 연관규칙 알고리즘 중 가장 먼저 접하게 되는 Apriori 알고리즘에 대해 알아보겠습니다.


Apriori 알고리즘은 빈발항목집합(frequent itemsets) 및 연관규칙분석을 위한 알고리즘이다. 


먼저, 연관규칙분석이란 무엇인가?

우리는 연관규칙 분석을 통해 서로 다른 두 아이템 집합이 얼만큼 빈번히 발생하는지(연관도)를 알 수 있다.

경영학이라면 한번쯤은 들어 봤을만한 "맥주를 구매하는 고객들은 기저귀를 구매할 가능성이 높다." 예시도 연관규칙 탐색을 통해 도출된 결론으로 볼 수 있다.


연관규칙분석의 대표적인 알고리즘으로
 Apriori algorithm
 FP-growth algorithm

 DHP algorithm


등이 있는데, Apriori 알고리즘이 비교적 구현이 간단하고 성능 또한 높은 수준을 보여주어 자주 활용되고 있다.


예시를 통해 Apriori 알고리즘을 자세히 알아보자.

우선, Apriroi 알고리즘의 연관규칙 탐색을 위한 Transaction 데이터가 있어야 하고,

최소지지도(Minimum Support)를 설정해줘야 한다.


Transaction 데이터가 아래와 같이 주어지고, 최소지지도를 3으로 설정하자.


 
[Transaction Database]


 슈퍼마켓의 구매 데이터라고 가정하면, {1, 2, 3, 4}는 1번 item, 2번 item, 3번 item, 4번 item이 같이 구매되었고
이를 하나의 itemset이라고 보면 된다.


1. 위 트랜잭션 데이터베이스를 스캔하면서 1-빈번항목집합을 찾는다. 


각각의 아이템들이 3번, 6번, 4번, 5번만큼 구매가 되었고
모두 최소지지도 3보다 높기 때문에 1-빈번항목집합에 포함된다.



2. 1-빈번항목집합을 기반으로 2-빈번항목집합을 구한다.


이 때, Self-Join Prune 과정을 거쳐야 한다.

Self-Join은 {1}, {2}, {3}, {4} 아이템을 바탕으로 생성될 수 있는 길이가 2인 모든 후보를 만드는 과정이다.

{1, 2} {1,3} {1, 4} {2, 3} {2, 4} {3, 4} 가 생성될 것이다.


이렇게 생성된 후보들을 대상으로 Pruning을 하는데, 

Pruning 대상은 후보들 중 itemset의 item 중 1-빈번항목집합에 없는 item이 있으면 Pruning 할 대상이 된다.

{1, 2} {1,3} {1, 4} {2, 3} {2, 4} {3, 4}의 각 itemset의 item들은 모두 1-빈번항목집합에 포함되므로

여기서는 Pruning 된 후보가 없다.


이제, Self-Join과 Prune 과정을 거친 후보들을 대상으로 트랜잭션 데이터베이스를 스캔하면서 Count 한다.  



Count된 값이 최소지지도 3보다 큰 itemset들로 2-빈번항목집합을 구한다.


즉, {1, 2} {2, 3} {2, 4} {3, 4} itemsets들이 2-빈번항목집합이다.


여기서, Apriori 알고리즘의 원리를 알 수 있다.

{1, 3}과 {1,4}는 다음 단계의 빈번항목집합 분석에 있어 더 이상 이용되지 않는다.

왜냐하면 한 항목집합이 비빈발(infrequent)하다면 그 항목을 포함한 모든 집합(Superset) 또한 비반발하기 때문이다.

"If there is any itemset which is infrequent, its superset should not be generated!"



3. 2-빈번항목집합을 기반으로 3-빈번항목집합을 구한다.


과정은 2번 과정과 똑같다.

2-빈번항목집합을 대상으로 Self-Join과 Prune을 한다.


Self-Join: {1, 2} {2, 3} {2, 4} {3, 4}
-> {1, 2, 3} {1, 2, 4} {1, 3, 4} {2, 3, 4}


Prune: {1, 2, 3} {1, 2, 4} {1, 3, 4} {2, 3, 4}

{1, 2, 3}의 subset이 {1, 2} {1, 3} {2, 3}인데 2-빈번항목집합에 {1, 3}이 존재하지 않으므로

{1, 2, 3}은 Pruning이 된다. {1, 2, 4} {1, 3, 4}도 마찬가지 원리로 Pruning 된다. 


길이가 3인 후보 {2, 3, 4}를 대상으로 트랜잭션 데이터베이스를 스캔하며 Count 한다.


Count된 값이 최소지지도 3보다 큰 itemset들로 3-빈번항목집합을 구해야 하지만,

최소지지도를 만족하는 더 이상의 itemset이 없기 때문에 종료한다.



위의 예시를 일반화해보면,


1. 트랜잭션 데이터베이스를 스캔하면서 1-빈번항목집합을 구한다.

2. k-빈번항목집합을 대상으로 (k+1)-빈번항목집합을 구한다.

- Self Join과 Prune을 통해 후보(Candidate)를 구하고,
- 트랜잭션 데이터베이스를 스캔하면서 최소지지도 조건을 만족하는 후보만 도출한다.

3. 더 이상 (k+1)-빈번항목집합이 만들어지지 않을 때까지 2번 과정을 반복한다.



자, 그럼 위의 과정을 통해 어떤 아이템들이 빈번하게 묶이는지 알았다면,

각 아이템들 간의 연관도가 얼만큼 있는지를 어떻게 알 수 있는가?


이는 Association Rule을 적용하여 지지도(Support), 신뢰도(Confidence) 그리고 향상도(Lift)를 통해 알 수 있다.

[출처: http://www.saedsayad.com/association_rules.htm]



위 Transaction Database에서 1-item -> 2-item 간의 연관도를 구하면,

Support: 1과 2가 전체 데이터베이스에서 함께 나올 확률:: 4/7

Confidence: 1이 나왔을 때, 2가 나올 확률:: 3/3

Lift: 1, 2 item 간의 독립을 가정했을 때, P(A, B) / P(A) * P(B):: 7/6

위와 같이 계산된다.


식의 자세한 설명은 위키피디아를 참조하자.


내용이 길어진 관계로, 파이썬 코드 설명은 다음 포스팅에서 하겠습니다.

코드를 보면 한층 더 수월하게 이해하는데 도움이 될 것 같네요!




수고하셨습니다





 

  1. 박혜진 2018.09.22 19:21

    개념을 이해 하는 것에 정말 도움 되었습니다~

  2. 아디오스 2019.04.11 22:56

    감사합니다! 특히 3번째 프룬 과정에서 도움이 많이 되었어요!!
    그런데 마지막에 Support값이 1과 2가 전체 데이터베이스에서 함께 나올 확률이라면 3/7 아닐까요?
    그리고 저는 다른 글에서 Support 값은 조건절의 확률으로 알고있어서 '1이 나올 확률'로 해서 3/7을 구했는데, 어떤 것이 맞는 것인지 부가 설명을 들을 수 있을까요?

안녕하세요. 우주신 입니다.


저번 시간에 이어 matplotlib 이용하여 누적영역형차트, 원형차트 그리는 방법에 대해 포스팅 하겠습니다.


우선, 그래프를 만들 임의의 데이터를 생성하겠습니다. (정말 아무 의미 없는 값을 입력해 데이터 생성했어요;)



1. 누적영역형차트 (Stacked Area Graph)


누적영역형차트는 두 개 이상의 데이터 계열을 서로 누적하는 영역형 차트 입니다. 

특히, 제품별로 매출에 기여하는 정도를 시계열로 나열하여 한 눈에 쉽게 볼 수 있어 성과 분석을 위한 기본적인 그래프 중 하나 입니다.


plt.stackplot(beernum, price, amount, country)

-plt.stackplot() 함수 안에 4개의 리스트인 데이터를 입력했습니다. 

첫번째 데이터인 beernum이 X축의 기준이 되고 그 외의 데이터들은 순차적으로 누적되어 그래프에 표시됩니다.


출력 결과, 입력 순서대로 데이터 값이 누적되어 그려진 것을 확인할 수 있습니다.


위의 차트의 색을 바꾸고, 차트 제목 및 X축, Y축 이름을 설정 했습니다.

plt.stackplot(beernum, price, amount, country, colors = )

-colors 기능에 원하시는 색을 리스트로 입력하면 됩니다.




2. 원형차트(Pie Chart)


원형차트는 전체에 대한 각 부분의 비율을 부채꼴 모양으로 나타낸 그래프 입니다.


가격(price)을 원형 차트로 표현해보겠습니다.

plt.pie(price)

-plt.pie() 함수 안에 데이터(price)를 넣고 출력 했습니다.


가격의 데이터에 따른 비율을 색깔별로 구분하여 그려졌는데, 어떤 데이터의 비율인지 한 눈에 파악하기 애매합니다.


이를 활용하여, 맥주 넘버(beernum)에 따른 가격(price)을 원형 차트로 표현해보겠습니다.

plt.pie(price, labels=, colors=, startangle=, shadow=, explode=, autopct= )

-plt.pie() 함수 안에 주 데이터로 price를 입력하고,

labels= 기능으로 어떤 데이터를 기준으로 주 데이터를 구분할지 정합니다.

colors= 기능으로 색을 순차적으로 지정하고, startangle= 기능으로 첫 데이터(여기서는 1번 데이터)를 어떤 각도에서 그릴지 정합니다.

shadow= 기능은 말 그대로 그림자를 넣어 입체감을 줄 것인지,

explode= 파이를 밖으로 빼는 기능입니다. 여기서는 두번째 데이터를 0.1만큼 밖으로 뺐습니다.

autopct= 백분율을 그래프에 표시하는 기능입니다.


위 원형차트에 비해 더 정확하고 깔끔하게 표시된 것을 확인할 수 있습니다.




수고하셨습니다


안녕하세요. 우주신 입니다.


이번 시간에는 히스토그램과 산점도 그리는 방법에 대해 배워보겠습니다.



먼저, pandas를 이용하여 웹에서 csv 파일을 불러왔습니다.


상점 번호, 연도, 기간, p1매출액.. 등을 기준으로 데이터프레임을 만들었습니다.


이 중 p1sales의 데이터를 히스토그램과 산점도로 시각화 해보겠습니다.


1. 히스토그램 (Histogram)


plt.hist(df['p1sales'])

-plt.hist() 함수 안에 df의 열 'p1sales' 데이터를 넣었습니다. 


Y축에는 빈도수가, X축에는 매출액을 기준으로 히스토그램이 출력됐습니다.


X축 매출액의 범위를 조정해보겠습니다. 

plt.hist(df['p1sales'], list)

-list 자리에 X축 범위를 지정할 수 있습니다. list에 반복문을 활용하여 0부터 300까지 데이터를 넣은 후, 이를 X축 범위로 적용하였습니다.


첫번째 히스토그램과 비교했을 때 X축의 범위가 바뀐 것을 확인할 수 있습니다.


조금 더 이쁘게 만들어보겠습니다.

plt.hist(df['p1sales'], list, histtype='bar', rwidth=0.9)

-histtype는 히스토그램의 type를 정하는 기능이고, rwidth는 막대 그래프 간의 간격을 설정할 수 있는 기능입니다. 

그 외 더 자세한 기능은 구글링!


훨씬 더 깔끔해졌어요. 마지막으로 X축, Y축 label과 그래프의 제목을 넣어주겠습니다.


plt.xlabel(), plt.ylabel()

-말 그대로 x축 label과 y축 label의 이름을 지정해주는 함수 입니다. x축에는 'Numbers'를 y축에는 'Counting'을 입력했습니다.

plt.title()

-그래프의 메인 제목을 입력하는 함수 입니다.



2. 산점도 (Scatterplot)


산점도는 직교 좌표계에 이용해 두 개 변수 간의 관계를 나타내는 방법입니다.


매 주(Week)에 따른 매출액(p1sales) 간의 관계를 알아보겠습니다.

plt.scatter(X, Y)

-X와 Y의 자리에 각각 df['Week'] 변수와 df['p1sales'] 변수가 입력됐습니다.


X축은 기간, Y축은 매출액을 기준으로 데이터에 해당하는 점들이 찍힌 것을 확인할 수 있습니다.


더 이쁘게 만들어 보겠습니다.

plt.scatter(df['Week'], df['p1sales'], label='skitscat', color='r', s=30, marker='o')

-color는 red로 지정하였고 s는 size의 약자입니다. marker는 점의 type를 설정할 수 있습니다.





수고하셨습니다


안녕하세요. 우주신 입니다.


이번 포스팅에서는 matplotlib 모듈과 그래프를 그리는 가장 기초적인 방법에 대해 알아보겠습니다.


데이터의 단순한 나열보다는 한 눈에 파악할 수 있는 표나 그래프가 더 가치 있다고 생각하기에,

데이터의 분석만큼 중요한 부분이 시각화 입니다.


앞으로 대중적으로 쓰이는 모듈 중 하나인 matplotlib을 활용하여 다양한 그래프를 그리는 방법에 대해 끄적거려보겠습니다.


한줄 한줄 차근히 설명해보겠습니다.

import matplotlib.pyplot as plt

-우선 matplotlib을 import 해야하는데 pyplot을 함께 묶어준 이유는 거의 모든 시각화하는데 있어 pyplot을 이용하기 때문입니다. 

흔히 plt를 약자로 사용합니다. import pandas as pd는 이번 시간에 필요 없는데 그냥 습관적으로 넣어둔 것 같네요;;

혹시나 "no module named"와 같은 오류가 난다면 terminal이나 command 창을 열고 pip3 install matplotlib 입력 후 설치 해주세요.


plt.plot(x, y)

-x와 y에 데이터를 입력한 후, plt.plot(x, y)를 이용해 그래프를 그렸습니다.


plt.xlabel(), plt.ylabel()

-말 그대로 x축 label과 y축 label의 이름을 지정해주는 함수 입니다. x축에는 'Numbers'를 y축에는 'Counting'을 입력했습니다.


plt.title()

-그래프의 메인 제목을 입력하는 함수 입니다.


plt.show()

-그래프를 보여주는 창을 띄워주는 코드입니다. plt.show()를 입력하지 않고 코드를 실행 시키면 아무것도 뜨지 않습니다. 

R(R Studio)의 경우, 따로 plt.show()와 같은 코드 없이 plot 함수를 실행하면 바로 그래프가 나타나 어색했지만, 쉽게 얘기하면 앞에까지의 코드들이 다 뒷배경에 그리는 역할이라면, 이거를 앞으로 들고 나오는 역할이 plt.show() 입니다.


실행 결과 입니다. 


조금 더 그래프를 이쁘게 만들어 보겠습니다.

plt.plot(x, y, label = )

-plt.plot 함수에 label 기능을 넣어줌으로써 그래프에 대한 구분을 해줬습니다.

이는 plt.legend() 함수를 실행해야 밑의 출력 결과의 왼쪽 위 모서리처럼 범례를 표시할 수 있습니다.



그래프를 하나 더 추가하여 두 개의 그래프를 그려보겠습니다.

x2, y2에 데이터를 넣은 후, plt.plot() 함수를 통해 그래프를 그렸습니다.


아주 깔끔하게 그래프가 출력됐습니다 :)





수고하셨습니다



안녕하세요. 우주신 입니다.


오늘은 알아두면 매우 유용한 함수 pandas.Series.rolling에 대해 포스팅 하겠습니다.

데이터분석을 하다보면 일정 범위에서 규칙적으로 연산(예: 이동평균)을 해야할 일이 많습니다.

예를 들어, 날마다 일주일 간의 주가 평균을 알고 싶을 때, 매일 일일이 다 계산하는 것은 매우 비효율적 입니다.


이 때, 유용하게 쓸 수 있는 함수가 .rolling 이라고 보시면 됩니다.

예전에 이 함수를 모를 때는 for문을 이용하여 rolling 함수의 기능을 구현 하다보니 코드도 길고 실행하는 데도 시간이 꽤 걸렸던 기억이 있네요;;


우선, 이번 시간에 사용할 금융 데이터를 웹에서 불러오겠습니다.

(금융 데이터 불러오기: http://ordo.tistory.com/57)



현대차 종가 'Close' 열만 추출하여 데이터프레임 hd_close를 만들고,

print(hd_close.head())를 통해 처음 몇 개 데이터만 출력했습니다.





Series.rolling(window, min_periods=None, freq=None, center=False, win_type=None, on=None, axis=0, closed=None)


.rolling 함수에 많은 기능들이 포함되어 있지만, 주요 기능 몇가지만 살펴보겠습니다.

나머지 기능들은 https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.rolling.html 에서 확인할 수 있어요!


먼저, 데이터프레임 hd_close의 데이터들을 순차적으로 12개씩 이동평균을 내보겠습니다.

hd_close.rolling(window=12).mean()

window: 몇 개씩 연산할지 입력

.mean(): 평균내라


출력값을 보면 2010-01-19 부터 값이 나오는 것을 확인할 수 있는데, 이는 이전 12개의 데이터가 2010-01-19부터 존재하기 때문 입니다.

즉, 데이터가 12개 미만인 값들은 NaN으로 표시 됐습니다.

2010-01-19의 결과값 106875.0은 2010-01-04부터 2010-01-19까지의 현대차 주가(종가 기준)를 평균한 것 입니다.


데이터가 1개라도 존재하면 평균을 내고 싶을 때는, min_period 기능을 이용하면 됩니다.

hd_close.rolling(window=12, min_periods=1).mean()


이전 출력값과 달리 이번에는 2010-01-04부터 데이터가 1개 이상이면 모두 평균하여 계산되었습니다.


지금까지는 순차적으로 window의 개수에 따라 평균 계산되었습니다.

중간을 기준으로 이동평균하고 싶을 때는 center 기능을 이용하면 됩니다.

hd_close.rolling(window=12, center=True).mean()



출력값을 보면 2010-01-12부터 데이터가 출력이 되었고, 끝에는 2016-12-23까지 데이터가 출력이 됐습니다.

앞선 결과와 비교했을 때, NaN의 개수는 모두 11개로 같지만, center 기능을 통해 자동으로 중간을 중심으로 12개씩 계산 됐습니다.


그 외, .mean() 대신 .std()를 입력함으로써 평균 대신 분산을 이동하며 계산할 수 있습니다.

hd_close.rolling(window=12).std()







수고하셨습니다.


안녕하세요. 우주신 입니다.


데이터 분석에 있어 가장 중요한 과정은 결측값 및 특이값을 얼마나 잘 처리하는지의 유무에 달려 있다고 생각하는데요,

오늘은 pandas를 이용하여 NA, NaN 데이터를 처리하는 몇가지 방법을 포스팅 하겠습니다.


df.dropna(), df.fillna()


우선, 결측값이나 특이값을 처리하는 3가지 방법이 있습니다.


1. 무시한다

2. 제거한다

3. 다른 값으로 대체한다


먼저, pandas와 numpy를 이용해 NaN 값이 포함된 데이터프레임을 만들었습니다.




1. 첫번째 방법은 아주 쉬워요. 그냥 무시하시면 됩니다.

물론, 추후에 데이터 분석을 하는 데 있어 걸리적거리겠죠..



2. df.dropna()


NaN이 들어간 행 전체를 제거하는 방법에 대해 보겠습니다.



첫번째 줄 df.dropna()을 실행하고 출력 했습니다.

데이터프레임에 값이 존재하지 않습니다.

데이터프레임 df를 보면 모든 행에 최소 1개의 데이터가 NaN을 포함하고 있습니다.

즉, df.dropna()를 통해 NaN이 하나라도 들어가 있는 행은 그 행 전체를 제거합니다.


두번째 줄 df.dropna(how = 'all')을 실행하고 출력 했습니다.

마지막 행 빼고 모두 출력 됐습니다.

즉, how = 'all' 기능을 통해 모든 데이터 값이 NaN인 행만 제거했습니다.



3. df.fillna()


마지막으로 NaN 값을 다른 값으로 대체하는 방법에 대해 보겠습니다.


특정 값을 df.fillna() 인풋으로 입력해주면 모든 NaN 값이 다 바뀝니다.

0을 넣어봤습니다.


모든 NaN 값이 0으로 바뀐 것을 확인할 수 있습니다.


이번에는 열마다 다른 값을 입력하여 NaN 값을 변경해보겠습니다.


a에는 0이 b에는 1이 c에는 -9999로 데이터가 변경됐습니다.


연속된 NaN 값 중 몇번째 값까지 변경할지도 지정할 수 있습니다.

df.fillna(data, limit = )


각 열에서 2번째 NaN까지 값들이 변경된 것을 확인할 수 있어요.


마지막으로, df.fillna(method = ) 기능 입니다.

method = ffillmethod = bfill을 비교해 보겠습니다.

먼저, ffill을 넣었을 때,


3행을 보시면 NaN의 값이 그 앞 데이터로부터 채워진 것을 확인할 수 있어요.


bfill은 반대로,


NaN의 값이 그 뒤 데이터로부터 채워진 것을 확인할 수 있습니다.





수고하셨습니다~

  1. 학생 2021.06.03 21:29

    4년이나 지난 글이지만 덕분에 살았습니다... 감사합니다...

안녕하세요 우주신 입니다.


오늘은 pandas를 이용하여 웹에서 주가 데이터를 가져오는 방법에 대해 포스팅 하겠습니다.


datetime.datetime(), pandas_datareader.DataReader(), pd.date_range(), quandl.get()



우선, 필요한 패키지를 다 다운 받습니다.

그 후, pandas_datareader의 DataReader를 이용해 웹에서 주가 데이터를 다운 받겠습니다.


1. pandas_datareader.DataReader(ticker, online_source, start, end)


삼성전자 티커를 넣고 yahoo 웹에서 2010년 1월 1일부터 2016년 12월 31일까지 데이터를 데이터프레임 df에 입력했습니다.

여기서 online_source는 yahoo 뿐만이 아니라 Google, FRED, Fama/French 등등을 사용할 수 있습니다.


출력 결과, Open, High, Low, Close, Adj Close, Volume 순으로 삼상전자 데이터를 들고 온 것을 확인 할 수 있습니다.


종가 'Close' 열만 따로 데이터프레임 df_close에 입력 했습니다.


그리고 종가만 출력되는 것을 확인할 수 있습니다.


pd.date_range를 이용하여 start 날짜부터 end 날짜 사이 중 평일만 추려냈습니다. 

pd.date_range(start, end, freq = ' ') 

그 외 나머지 기능들은 찾아보십시오!


출력 결과,


그리고 only_weekdays의 데이터에 따라 df_close 데이터프레임을 평일 기준으로 다시 나타냈습니다.


출력 결과,



2. quandl.get(TICKER, trim_start = 'date', authtoken = api_key)


데이터(특히, 금융데이터)를 다운 받는 다른 방법으로 quandl 모듈도 많이 사용합니다.

이것 또한 아주 간단한데요, 우선 import quandl 꼭 해주셔야 합니다. 

오류가 나는 경우, 대부분은 pip install quandl (파이썬 버전에 따라 pip3 install quandl) 코드를 통해 설치하면 아마 해결 될 거에요.



api_key = open('quandlapikey.txt', 'r').read()

api key는 https://www.quandl.com/ 홈페이지에서 로그인 한 후 받을 수 있습니다.


quandl.get("FRED/GDP", trim_start='2000-01-01', authtoken=api_key)

TICKER 값으로 gdp를 넣었습니다. 원하시는 데이터의 티커값을 넣으시면 됩니다.

trim_start는 불러올 데이터의 시작하는 날짜를 입력하면 됩니다.

authtoken의 경우 앞서 받은 api_key를 입력해주시면 돼요.


데이터 열의 이름을 보기 좋게 GDP로 바꾼 후 출력해봤습니다.






수고하셨습니다~







안녕하세요. 우주신 입니다.


이번에는 pandas의 merge()를 이용해 데이터프레임끼리 병합하는 방법에 대해 알아보겠습니다.


우선, import pandas as pd를 통해 pandas를 가져왔습니다.

지난 포스팅의 데이터프레임 결합에서 이용했던 데이터프레임을 그대로 쓰겠습니다.


df1과 df2는 인덱스만 다를 뿐 값이 다 같고, 

df3는 df1과 달리 3번째 열이 'Color_Num'입니다.




1. pd.merge(데이터프레임, 데이터프레임)


인덱스만 다르고 값이 같은 df1과 df2를 병합 시켜보겠습니다. 


위의 출력 결과를 보면, 인덱스와 상관 없이 병합이 되고, 같은 값들은 중복 표기가 되지 않습니다. 



2. pd.merge(데이터프레임, 데이터프레임, on = ' ')


이번에는 특정 열을 지정하여 그 열을 기준으로 병합 했습니다.

pd.merge()의 on = '열 이름' 을 입력하면 됩니다.


'Year'를 기준으로 병합한 결과, Year 열 외에는 데이터가 다 중복으로 표기되었습니다.


'Year'와 'Beer_Code'를 기준으로 병합하면,


기준 열 외에 'Price' 열의 데이터들이 중복으로 표기된 것을 확인할 수 있습니다.


좀 더 깔끔하게 'Year'를 인덱스로 설정하여 데이터프레임을 정리해보겠습니다.

inplace = True 를 입력해야 데이터프레임이 실제로 바뀝니다.



이번에는 하나의 열이 다르고 데이터가 서로 다른 df1과 df3를 병합 해보겠습니다.


그 결과, 서로 같이 공유하는 열 'Beer_Code', 'Year'의 데이터가 같은 행만 병합된 것을 확인할 수 있습니다.


'Year'를 기준으로 병합을 하면,


'Year'의 데이터가 같은 행들을 기준으로 병합이 됩니다.

'Price'와 'Color_Num'의 경우 서로 열을 공유하고 있지 않지만 'Beer_Code'는 공유하고 있기에 데이터가 중복 표기 되었습니다.



3. pd.merge(데이터프레임, 데이터프레임, on = ' ', how = ' ')


how = 'outer' / how = 'inner' 기능을 이용해보겠습니다.


how = 'outer'는 기준 열 'Year'의 데이터의 중복 여부와 상관 없이 모두 출력합니다.

how = 'inner'를 입력하면 중복된 데이터의 행만 출력되는 것을 확인할 수 있습니다.


how = 'left' / how = 'right' 기능을 이용해보겠습니다.


말 그대로 left는 df1의 'Year'를 기준으로, right는 df3의 'Year'를 기준으로 병합하라는 뜻입니다.

위의 결과를 보면 df1의 'Year'를 기준으로 병합된 것을 확인할 수 있습니다.




+ Recent posts