Python 데이터분석 라이브러리(6) - Pandas(DataFrame functions)
Data-Science 강의는 여러 절로 구성되어 있습니다.
- Python 데이터분석 라이브러리(1) - NumPy
- Python 데이터분석 라이브러리(2) - NumPy(Exercise)
- Python 데이터분석 라이브러리(3) - Pandas(Series)
- Python 데이터분석 라이브러리(4) - Pandas(DataFrame 생성)
- Python 데이터분석 라이브러리(5) - Pandas(DataFrame indexing)
- Python 데이터분석 라이브러리(6) - Pandas(DataFrame functions)
- Python 데이터분석 라이브러리(7) - Pandas(DataFrame merge)
- Python 데이터분석 라이브러리(8) - Pandas(DataFrame 제어)
- Python 데이터분석 라이브러리(9) - Pandas(DataFrame Grouping)
- Python 데이터분석 라이브러리(10) - Pandas(Exercise)
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 분석용 함수 - 공분산(예제)
# 공분산이 양수인 경우 ( 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 강좌는 아래의 책과 사이트를 참조했습니다. 조금 더 자세한 사항을 알고 싶으시면 해당 사이트를 방문하세요!!