/ DATA-SCIENCE

Python 데이터분석 라이브러리(6) - Pandas(DataFrame functions)

Data-Science 강의는 여러 절로 구성되어 있습니다.


DataFrame 분석용 함수

## 기댓값(expected value) : 어떤 확률을 가진 사건을 무한히 반복했을 경우 
##                         얻을 수 있는 값의 평균으로서 기대할 수 있는 값

# 주사위 1개를 던지는 사건을 무한히 반복했을 경우 기댓값은?
# import numpy as np

# result = np.random.randint(1,7,(100000,))
# print(result.mean())

## 편차( deviation ) : 확률변수 X와 평균값(기댓값)의 차이. 
## 국민개개인의 소득을 이용하여 국민평균 소득을 산출한 후 
## 편차의 관점에서 데이터를 바라보면 얼마나 양극화가 진행됬는지
## 대략 가늠할 수 있다.
## 데이터의 흩어진 정도를 알기 위해 편차의 평균을 이용하면 될 듯 하다. 
## 하지만 편차의 합계는 0이기 때문에 평균을 구할 수 없고
## 결국 데이터의 흩어진 정도를 수치화 하기 힘들다.

## 분산 ( variance ) : 데이터의 흩어진 정도를 알기 위해 사용하는 편차의 제곱의 평균.
## 하지만 제곱한 값이기 때문에 사용하기 애매하다.

## 표준편차 ( standard deviation ) : 분산의 제곱근
## 데이터가 얼마나 흩어져 있는지, 얼마나 차이가 심한지를 알 수 있음.

# 평균, 편차, 분산, 표준편차

import numpy as np

arr = np.array([4,6,1,3,8,8], dtype=np.int32)

print(arr)
print("합계 : {}".format(arr.sum()))
print("평균 : {}".format(arr.mean()))
print("분산 : {}".format(arr.var()))
print("표준편차 : {}".format(arr.std()))


DataFrame 분석용 함수 - 공분산

공분산


## 공분산 ( covariance ) : 두 개의 확률변수의 관계를 보여주는 값
## 확률변수 X(독립변수)와 Y(종속변수)에 대해 X가 변할 때 Y가 변하는 정도를 나타내는 값

## 공분산은 두 확률변수 편차의 곱에 대한 평균으로 이 역시
## 데이터가 평균으로 부터 얼마나 떨어져 있는가를 나타낸 값.

## 그래프를 이용하여 공분산의 의미를 이해해보자.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 독립변수 X에 대해 종속변수 Y의 값을 랜덤하게 구해보자
np.random.seed(2)

x = np.random.randint(-20,20,(10,))
y = np.random.randint(-10,10,(10,))

x_mean = x.mean()
y_mean = y.mean()

# 이렇게 구한 값을 산점도로 표현해보자
plt.scatter(x,y,color="red")
plt.scatter(x_mean,y_mean,color="blue")
plt.show()

# x가 변할 때 y가 어떻게 변하는지를 확인할 수 있다.
# 평균을 기준으로 1,3 사분면에 있는 점들은 x가 증가할 때 y가 증가하거나
#                                          x가 감소할 때 y가 감소
# 평균을 기준으로 2,4 사분면에 있는 점들은 x가 증가할 때 y가 감소하거나
#                                          x가 감소할 때 y가 증가

# 공분산은 이런 데이터의 변화량에 대한 총합
# 따라서 공분산이 양수인지 음수인지에 따라 데이터의 방향성을 알 수 있다.
# 다만, 단위의 문제 때문에 실제 어느정도의 연관성을 가지는지에 대한 내용은
# 알 수 없다.

## 모공분산은 두 확률변수 각각의 편차의 곱에 대한 평균으로 표현되고
## 표준공분산은 두 확률변수 각각의 편차의 곱에 대한 합을 n-1로 나눠 계산한다.
## 표준공분산이 n-1로 나누는 이유는 이렇게 해야 더 좋은 추정량이 되기 때문이다. 
   
## 만약 확률변수 X와 Y가 서로 아무 관련이 없는 독립이면 공분산은 0으로 수렴된다.
## 방향성이 없이 랜덤하게 무수하게 많은 샘플에 대해 값을 계산하게 되면 결국 양수,음수가
## 번갈아 나오게 되서 최종적으로 0과 가까워진다.

## 일반적으로 역은 성립하지 않는다. 즉, X와 Y가 독립이 아니더라도
## 공분산은 0이 될 수 있다.
      
## 표준공분산의 공식을 이용하여 프로그램으로 두 확률변수간의 공분산을 계산해보자

import numpy as np
import pandas as pd

np.random.seed(2)
sampleNum = 100

x = np.random.randint(0,10,(sampleNum,))
y = np.random.randint(-10,20,(sampleNum,))

x_mean = x.mean()   # x의 평균
y_mean = y.mean()   # y의 평균

x_deviation = x-x_mean; 
y_deviation = y-y_mean; 

result = 0;
for i in range(sampleNum):
    result += (x_deviation[i] * y_deviation[i])
    
result_covariance = result / (sampleNum-1);  # 표준공분산(n-1)
print(result_covariance)

print(np.cov(x,y))   # numpy의 함수를 이용하여 계산   
   
## 2개의 확률 변수 중 하나의 값이 상승하는 경향을 보일 때, 
## 다른 값도 상승하는 경향의 관계에 있다면, 공분산의 값은 양수. 
## ( 그렇지 않은 경우 음수 )
   
## 하지만 가장 큰 단점은 측정단위에 따라서 값이 달라진다는 것. 
## 즉, 두 변수가 얼마나 연관되었는지 그 강도(strength)를 잘 보여주지 못하는 경향이 있다.    
## 측정 단위에 상관없이 두 변수 사이의 관계를 보여주는 값으로는 상관계수를 사용


DataFrame 분석용 함수 - 공분산(예제)

2018년 주식데이터 JSON


# 공분산이 양수인 경우 ( KOSPI 지수와 삼성전자 주가 )
# 2020년 2월 기준 코스피200 지수 내 삼성전자의 비중은 33.24%

import numpy as np
import pandas as pd
import pandas_datareader.data as pdr # 설치필요
from  datetime import datetime

start = datetime(2018,1,1) # 특정날짜 객체 생성
end = datetime(2018,12,31)

# YAHOO에서 제공하는 KOSPI 지수
df_KOSPI = pdr.DataReader("^KS11", "yahoo", start, end)
df_KOSPI.to_json("./data/KOSPI.json")

# json 파일의 날짜값은 timestamp를 이용한다.
from datetime import datetime
timestamp = 1514937600000
datetime_obj = datetime.fromtimestamp(timestamp/1000)
print(datetime_obj) # 2018-01-03 09:00:00

# YAHOO에서 제공하는 삼성전자 주가
df_SE = pdr.DataReader("005930.KS", "yahoo", start, end)
df_SE.to_json("./data/SE.json")

# YAHOO에서 제공하는 부산산업 지수
df_BUSAN = pdr.DataReader("011390.KS", "yahoo", start, end)
df_BUSAN.to_json("./data/부산산업.json")

# YAHOO에서 제공하는 LIG넥스원 주가
df_LIG = pdr.DataReader("079550.KS", "yahoo", start, end)
df_LIG.to_json("./data/LIG넥스원.json")

df_close_KOSPI = df_KOSPI["Close"] # 종가데이터
df_close_SE = df_SE["Close"]
print(np.cov(df_close_KOSPI.values,df_close_SE.values))  # 공분산
# 0행 0열 : KOSPI의 공분산
# 0행 1열 : KOSPI와 SE의 공분산
# 1행 0열 : SE와 KOSPI의 공분산
# 1행 1열 : SE의 공분산

df_close_BUSAN = df_BUSAN["Close"] # 종가데이터
df_close_LIG = df_LIG["Close"]
print(np.cov(df_close_BUSAN,df_close_LIG))  # 공분산


DataFrame 분석용 함수 - 상관계수


## 상관관계 (Correlation) : 두 대상이 서로 연관성이 있다고 추측되는 관계
## 성적과 자존감
## 온라인 게임과 폭력성

## 상관계수 (Correlation Coefficient) : -1과 1사이의 실수.

## 일반적으로 피어슨 상관계수를 의미하며 다른 상관계수도 존재한다.
## 공분산을 각 변수의 표준편차의 곱으로 나눈값 
## 하나의 변수가 변화할 때 다른 변수가 변화하는 정도를 의미
## 양수일 경우 정적 상관관계, 음수일 경우 부적상관관계

## 0에 가까울수록 관련성이 없음. 절대값이 1에 가까울수록 관련성이 높음.
## 성적과 자존감의 상관계수가 0.8이면 성적이 높을수록 자존감이 높다고 추측
   
## 단, 상관관계로 인과관계를 설명할 수 없음 (오류의 여지가 많음 )
## 성적이 높기때문에 자존감이 높다 ??
## 온라인게임을 많이하면 폭력적이된다 ??

## 인과관계와 같이 한 변수가 다른 변수에 주는 영향력을 알아보기 위해서는
## 회귀 분석(regression analysis)를 사용한다.

## Network연결이 가능한 환경이라면 아래의 참고 코드를 이용하여 
## 특정 종목의 종목코드를 알아와서 pandas_datareader를 이용하여
## 특정기간의 주가를 알아와서 상관계수를 구할 수 있다.

## 만약 Network연결이 안되는 환경이라면 제공된 JSON파일을
## 읽어들여서 DataFrame을 생성한 후 상관계수를 구해보자.

import numpy as np
import pandas as pd
import json

file_KOSPI = open("C:/notebook_dir/data/KOSPI.json","r")
series_KOSPI = pd.DataFrame(json.load(file_KOSPI))["Close"]  # Series

file_SE = open("C:/notebook_dir/data/SE.json","r")
series_SE = pd.DataFrame(json.load(file_SE))["Close"] # Series

file_LIG = open("C:/notebook_dir/data/LIG넥스원.json","r")
series_LIG = pd.DataFrame(json.load(file_LIG))["Close"] # Series

file_PUSAN = open("C:/notebook_dir/data/부산산업.json","r")
series_PUSAN = pd.DataFrame(json.load(file_PUSAN))["Close"] # Series

# NumPy 함수로 상관계수를 구해보자.
np.corrcoef(series_KOSPI,series_SE)

# 위에서 구한 Series를 이용해 DataFrame을 생성
myDict = { "KOSPI" : series_KOSPI,
           "SE" : series_SE,
           "LIG넥스원" : series_LIG,
           "부산산업" : series_PUSAN}

df = pd.DataFrame(myDict)

display(df.corr())   # DataFrame을 이용한 상관계수 계산

#####################################

# 참고코드
# 외부 API를 이용해 KOSPI 전체 종목코드를 읽어온 후
# 종목명으로 종목코드를 검색하는 코드.

import numpy as np
import pandas as pd

# 전체 종목코드를 읽어온다.(네트워크 연결가능할 경우)
df = pd.read_html("http://kind.krx.co.kr/corpgeneral/corpList.do" + \
                  "?method=download&searchType=13", 
                  header=0)[0]

# JSON 파일로 저장
with open('./data/전체종목코드.json', 'w', encoding='utf-8') as file:
    df.to_json(file, force_ascii=False, orient="columns") 

# 종목명으로 종목코드 검색
title = "LG화학"  # 종목명
code = "종목코드"   # 종목코드

df = df.loc[:,["회사명","종목코드"]] # 회사명과 종목코드만 추출

# map() : Series에서만 사용, 사용자 정의함수 호출
df["종목코드"] = df["종목코드"].map('{:06d}'.format) # 종목코드 6자리로 변환

code = df.loc[df["회사명"] == title,"종목코드"].values[0]

print("종목명 : {}, 종목코드 : {}".format(title,code))


DataFrame 분석용 함수 - 상관계수 실습


# 주식데이터 생성

# 공분산과 상관계수(피어슨 상관계수 공식이용)
import numpy as np
import pandas as pd
import pandas_datareader.data as pdr # 설치필요
import datetime

start = datetime.datetime(2018,1,1) # 특정날짜 객체 생성
end = datetime.datetime(2018,12,31)

# YAHOO에서 제공하는 LG전자 주가 데이터 중 종가
LG = pdr.DataReader("066570.KS", "yahoo", start, end)["Close"]
# YAHOO에서 제공하는 롯데쇼핑 주가 데이터 중 종가
LOTTE = pdr.DataReader("023530.KS", "yahoo", start, end)["Close"]
# YAHOO에서 제공하는 삼성전자 주가 데이터 중 종가
SE = pdr.DataReader("005930.KS", "yahoo", start, end)["Close"]

df = pd.DataFrame({ "LG" : LG , "LOTTE" : LOTTE, "SE" : SE })
print("LG전자와 삼성전자의 공분산 : {}".format(df["LG"].cov(df["SE"])))
print("LG전자와 삼성전자의 상관계수 : {}".format(df["LG"].corr(df["SE"])))
print("LG전자와 롯데쇼핑의 상관계수 : {}".format(df["LG"].corr(df["LOTTE"])))

display(df.cov())    # DataFrame안의 모든 컬럼에 대한 공분산

display(df.corr())   # DataFrame안의 모든 컬럼에 대한 상관계수


DataFrame 분석용 함수 - sum, mean


# DataFrame 분석용 함수 (Sample DataFrame 생성)

import numpy as np
import pandas as pd

data = [[2, np.nan],
        [7, -3],
        [np.nan, np.nan],
        [1, -2]
       ]

df = pd.DataFrame(data, 
                  columns=["one","two"],
                  index=["a","b","c","d"])

display(df)
print(df.sum())   # df.sum(axis=0)
                  # skipna=True (default) => NaN은 제외
                  # Series return
                  
print(df.sum(axis=1))

print(df["two"].sum())    # 특정 열에 대한 합
print(df.loc["b"].sum())  # 특정 행에 대한 합

 skipna=False, NaN 연산에 포함(실수처리)
print(df.mean(axis=0, skipna=False))
             
#  skipna=True, NaN을 연산에서 배제    
print(df.mean(axis=1, skipna=True))
                                                    
# "one" column의 결측값은 "one" column의 평균으로
# "two" column의 결측값은 "two" column의 최소값으로 대체
one_avg = df["one"].mean() # df.mean(axis=0)["one"]
two_min = df["two"].min()  # df.min(axis=0)["two"]

df["one"] = df["one"].fillna(value=one_avg)
df["two"] = df["two"].fillna(value=two_min)

display(df)       


DataFrame 분석용 함수 - sort


# DataFrame index와 column 재 설정

import numpy as np
import pandas as pd

np.random.seed(1)
df = pd.DataFrame(np.random.randint(0,10,(6,4)))
display(df)   # 숫자 index사용, column명도 숫자 index처리

df.columns = ["A", "B", "C", "D"]
df.index = pd.date_range("20200101", periods=6)
display(df)

# 순열 랜덤 치환
random_date = np.random.permutation(df.index)  
print(random_date)
# np.random.shuffle(df.index)
# shuffle()을 못쓰는 이유는 Index는 mutable opertion을 지원하지 않기때문.

# index와 column이 재 설정된 DataFrame 생성
df2 = df.reindex(index=random_date, columns=["B","A","D","C"])
display(df2)

## axis 기준으로 정렬
display(df2.sort_index(axis=1, ascending=True))
# axis=0 : 행(row) 기준 정렬
# axis=1 : 열(column) 기준 정렬
# ascending=Flase : 내림차순 정렬

## 특정 column의 값으로 행 정렬
display(df2.sort_values(by="B"))

# "B"값이 같을 때 "A"로 정렬(2차정렬)
display(df2.sort_values(by=["B","A"]))   


DataFrame 분석용 함수 - unique, value_counts, isin


# DataFrame 유용한 함수들

# unique(), value_counts(), isin()
import numpy as np
import pandas as pd

np.random.seed(1)
df = pd.DataFrame(np.random.randint(0,10,(6,4)))

df.columns = ["A", "B", "C", "D"]
df.index = pd.date_range("20200101", periods=6)

df["E"] = ["AA","BB","CC","CC","AA","CC"]
display(df)

print(df["E"].unique())          # 중복제거(ndarray)

print(df["E"].value_counts())    # 각 값들의 개수 return(Series)

print(df["E"].isin(["AA","BB"])) # boolean indexing(Series) 


DataFrame 분석용 함수 (lambda 함수)


# DataFrame 유용한 함수들

# python에서 배운 lambda 함수를 DataFrame의 행, 열에 apply()를 통해 적용
# 각 행의 column에 대해 최대값 - 최소값을 구해 새로운 column을 추가
# 각 column안에서 최대값 - 최소값을 구해 출력

import numpy as np
import pandas as pd

np.random.seed(1)
df = pd.DataFrame(np.random.randint(0,10,(6,4)))

df.columns = ["A", "B", "C", "D"]
df.index = pd.date_range("20200101", periods=6)
display(df)

func = lambda x: x.max() - x.min()

df["최대-최소"] = df.apply(func, axis=1)
display(df)

display(df.apply(func, axis=0))  # Series return

End.


Data-Science 강좌는 아래의 책과 사이트를 참조했습니다. 조금 더 자세한 사항을 알고 싶으시면 해당 사이트를 방문하세요!!