< DataFrame 행과 열 >
1. loc[ ]를 이용한 추출
import numpy as np
import pandas as pd
data = {'이름':['이순신', '홍길동', '강감찬', '김유신', '장보고'],
'학과':['컴퓨터', '기계', '철학', '컴퓨터', '국어국문'],
'학년':[1,2,2,4,3],
'학점':[1.5, 2.0, 3.1, 1.1, 2.7]}
df = pd.DataFrame(data,
columns=['학과','이름','학점','학년','등급'],
index=['one','two','three','four','five'])
# 행 추출
display(df.loc['one':'three'])
# 행과 열을 동시에 추출할 수도 있다.
# display(df.loc['one':'three','이름':'학년']) # return : Series
# Fancy indexing
display(df.loc['one':'three',['이름','학년']])
# 간단한 연습문제
# 1. 학점이 1.5점을 초과하는 학생의 이름과 학점을 DataFrame으로 출력
display(df.loc[df['학점'] > 1.5, ['이름','학점']])
# 2. 이름이 '홍길동'인 사람을 찾아서 이름과 학점을 DataFrame(DF)로 출력
display(df.loc[df['이름'] == '홍길동',['이름','학점']])
# 3. 학점이 1.5 초과이고 2.5 미만인 모든 사람을 찾아서
# 학과, 이름, 학점을 DF로 출력
# display(df.loc[(df['학점'] > 1.5) and (df['학점'] < 2.5), '학과:'학점']) # error
# vector 간의 연산이기 때문에 and 연산을 사용하면 error!
# & 연산을 수행해야 한다.
display(df.loc[(df['학점'] > 1.5) & (df['학점'] < 2.5),'학과':'학점'])
# 4. 학점이 3.0을 초과하는 사람을 찾아서 등급을 'A'로 설정 후 출력
df.loc[df['학점'] > 3.0,'등급'] = 'A'
display(df)
2. iloc[ ]를 이용한 추출
import numpy as np
import pandas as pd
data = {'이름':['이순신', '홍길동', '강감찬', '김유신', '장보고'],
'학과':['컴퓨터', '기계', '철학', '컴퓨터', '국어국문'],
'학년':[1,2,2,4,3],
'학점':[1.5, 2.0, 3.1, 1.1, 2.7]}
df = pd.DataFrame(data,
columns=['학과','이름','학점','학년','등급'],
index=['one','two','three','four','five'])
# iloc[]를 이용한 행과 열의 indexing
# 숫자 index를 이용해서 처리할 때 사용
print(df.iloc[0,0]) # 컴퓨터
print(df.iloc[1]) # Series
# 학과 기계
# 이름 홍길동
# 학점 2
# 학년 2
# 등급 NaN
# Name: two, dtype: object
display(df.iloc[1:4]) # DataFrame
# Fancy indexing
# numpy 에서는 행과 열에 동시에 fancy indexing 사용이 불가능했다.
# 그래서 np.ix_() 함수를 이용해서 동시 사용하였다.
# 하지만, pandas 에서는 함수없이 동시에 fancy indexing 가능
3. 행과 열의 추가와 삭제
import numpy as np
import pandas as pd
data = {'이름':['이순신', '홍길동', '강감찬', '김유신', '장보고'],
'학과':['컴퓨터', '기계', '철학', '컴퓨터', '국어국문'],
'학년':[1,2,2,4,3],
'학점':[1.5, 2.0, 3.1, 1.1, 2.7]}
df = pd.DataFrame(data,
columns=['학과','이름','학점','학년','등급'],
index=['one','two','three','four','five'])
# DF 에서 새로운 행을 추가하려면?
# 기존에 없는 index를 그대로 적어서 새로운 행 추가 가능
df.loc['six',:] = ['영어영문','대조영',4.0,3,'A']
# 새로운 행의 일부 열에 대해서만 데이터를 추가하는 것도 가능
# 이 때, 설정해주지 않은 값들은 NaN으로 설정
df.loc['six',['학과','이름']] = ['영어영문','대조영']
# DF 에서 특정 행을 삭제하려면?
# 삭제는 행과열 모두 drop() 함수 사용
# 지우려는 것이 행인지 열인지 알려주는 axis를 인자로 전달
# inplace는 True면 원본을 변경, False면 복사본을 return
# 1. 열 삭제
display(df.drop('학점', axis=1, inplace=False))
# 2. 행 삭제
display(df.drop('three', axis=0, inplace=False))
# Fancy indexing으로 여러행 삭제 가능
display(df.drop(['two','five'], axis=0, inplace=False))
< DataFrame 제공 함수 - 통계기반 >
# DataFrame이 제공하는 함수들 (집계함수, 통계기반 함수 등)
# 기댓값(expected value)
# 어떤 확률을 가진 사건을 무한히 반복했을 때
# 얻을 수 있는 값의 평균으로 기대할 수 있는 값
# 주사위 1개를 던지는 사건을 무한히 반복했을 때, 기댓값은 얼마일까?
import numpy as np
# 1000000 번 주사위를 던짐
result = np.random.randint(1,7,(1000000,))
print(result.mean()) # 3.503021 (거의 3.5)
arr = np.array([4,6,1,3,8,8], dtype=np.int32)
# 합계
print(arr.sum(axis=0)) # 30
# 평균
print(arr.mean()) # 5.0
# 편차(deviation) : 확률변수 x와 평균(기댓값)의 차이
# 편차의 단점 : 데이터의 흩어진 정도를 편차로만 표현하기 힘듬
# 편차의 합은 항상 0이므로 편차 하나만으로 표현이 힘들다.
# 분산(variance) : 데이터의 흩어진 정도를 알기위해서 사용
# 편차 제곱의 합의 평균
# 제곱을 사용했기 때문에 사용하기가 애매한 부분이 있다.
# var() 함수를 이용
print(arr.var()) # 6.6667
# 표준편차(standard deviation = std)
# 분산의 제곱근
# std() 함수를 이용
print(arr.st()) # 2.5819
< 공분산 (covariance) >
# 공분산(covariance)
# 두 개의 확률변수의 관계를 보여줄 때 사용하는 값
# 공분산은 두 확률변수의 편차의 곱에 대한 평균
# 확률변수 X(독립변수)와 Y(종속변수)에 대해 X가 변할 때 Y가 변하는 정도
# 그래프를 이용해서 공분산의 의미를 파악해보자
import numpy as np
import matplotlib.pyplot as plt
# 독립변수 X에 대해 종속변수 Y의 값을 랜덤으로 생성해서 알아보자
np.random.seed(1)
x = np.random.randint(-20, 20, (10,))
y = np.random.randint(-10, 10, (10,))
x_mean = x.mean() # X의 평균
y_mean = y.mean() # Y의 평균
# 이렇게 구한 값을 가지고 scatter(산점도)를 그려보자
plt.scatter(x,y,color='red')
plt.scatter(x_mean, y_mean, color='blue')
plt.show()

공분산은 데이터의 변화량에 대한 총합을 의미한다.
- 공분산이 양수면 값이 증가하면 같이 증가하는 관계
- 공분산이 음수면 값이 증가하면 감소하는 역의 관계
< 공분산의 단점 >
- 연관성은 파악할 수 있지만, 단위의 문제 때문에 그 강도는 알 수 없다.
< 특징 >
- 확률변수 X와 Y가 독립이면 공분산은 0에 수렴
- 역은 성립하지 않음 (공분산이 0이면 두 확률변수는 독립 => X)
< 공분산 계산 예제 >
import numpy as np
np.random.seed(2)
sampleNum = 100 # 데이터의 개수
x = np.random.randint(0, 10, (sampleNum,))
y = np.random.randint(-20, 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 tmp in range(sampleNum):
result += (x_deviation[tmp] * y_deviation[tmp])
result_covariance = result / (sampleNum-1) # 표준공분산
print(result_covariance) # -0.591515151515151
# 공분산을 구하는 함수 cov()를 이용하면 편리
print(np.cov(x,y))
# [[ 7.52767677 -0.59151515]
# [ -0.59151515 123.99636364]]
< 공분산 사용 예제 >
# 주가를 이용해서 공분산의 의미를 알아보자
# KOSPI 200 : 대형회사 200개의 주가로 만든 또 다른 지수
# KOSPI 200 안에서 삼성전자 비중이 34% 정도 된다.
# 삼성전자가 오르면 KOSPI가 오르고, 떨어지면 KOSPI가 떨어진다.
import numpy as np
import pandas as pd
# network에서 데이터를 가져와서 바로 DataFrame으로 만들어줌
import pandas_datareader.data as pdr # 주가 데이터를 받기 위해서 필요
from datetime import datetime # 날짜 객체를 만들기 위해서 필요
# pandas_datareader 모듈을 설치해야 사용 가능
# anaconda prompt 에서 pip install pandas_datareader 실행
# 특정 날짜 간격을 정하기 위해서 datetime을 이용
# 시작날짜와 끝날짜를 지정
start = datetime(2018,1,1) # 2018년 1월 1일
end = datetime(2018,12,31) # 2018년 12월 31일
# 주식 데이터는 yahoo에서 제공하는 것을 활용
# json으로 가져올 필요없이 dataframe으로 바로 생성이 가능하다.
# 각 항목의 code를 통해서 가져올 데이터 지정
df_KOSPI = pdr.DataReader('^KS11', 'yahoo', start, end)
df_SE = pdr.DataReader('005930.KS', 'yahoo', start, end)
# 구조를 보면 Close라는 column이 우리가 원하는 주가 데이터
closed_KOSPI = df_KOSPI['Close'] # Series
closed_SE = df_SE['Close'] # Series
# 가져온 데이터에 대해서 공분산을 구해보자
print(np.cov(closed_KOSPI.values, closed_SE.values))
#[[ 24045.56247333 489067.36939603]
# [ 489067.36939603 11918322.34148349]]
# 값이 양수이므로 하나가 증가하면 다른 하나가 증가하는 관계이다.
# 반대로 움직일만한 주식데이터를 가져와서 확인해보자
df_LIG = pdr.DataReader('079550.KS', 'yahoo', start, end) # LIG넥스원(방위산업체)
df_PUSAN = pdr.DataReader('011390.KS', 'yahoo', start, end) # 부산산업(남북경협주)
closed_LIG = df_LIG['Close'] # Series
closed_PUSAN = df_PUSAN['Close'] # Series
print(np.cov(closed_LIG.values, closed_PUSAN.values))
# [[ 6.24988174e+07 -3.81494283e+08]
# [-3.81494283e+08 4.64412566e+09]]
# 1, 3사분면에 해당하는 값이 음수 => 역의 관계
< 상관관계 : correlation coefficient >
공분산을 이용해서 도출한 값으로, 방향성과 관련성 및 강도도 알 수 있다.
- ex) 성적과 자존감 / 온라인게임과 폭력성 등
* 주의 : 하지만 인과관계를 설명할 수는 없다!
- ex) 온라인 게임을 많이해서 폭력성이 높다고는 할 수 없다.
- 인과관계는 regression을 이용해서 분석한다.
- 상관계수는 -1 ~ 1 사이의 실수값이다.
- 0 : 서로독립 / 1 에 가까워질수록 양의 상관관계 / -1 에 가까워질수록 음의 상관관계
# 아까했던 주식 데이터를 가지고 계산해보자
import numpy as np
import pandas as pd
import pandas_datareader.data as pdr
from datetime import datetime
start = datetime(2018,1,1) # 2019년 1월 1일
end = datetime(2018,12,31) # 2019년 12월 31일
df_KOSPI = pdr.DataReader('^KS11', 'yahoo', start, end)
df_SE = pdr.DataReader('005930.KS', 'yahoo', start, end) # 삼성전자의 코드 전달
closed_KOSPI = df_KOSPI['Close'] # Series
closed_SE = df_SE['Close'] # Series
# 상관관계 계산함수 : corrcoef (correlation coefficient의 약자)
print(np.corrcoef(closed_KOSPI, closed_SE))
# [[1. 0.91357384]
# [0.91357384 1. ]]
# 1이 최대인데 0.9면 연관강도가 매우 높음을 알 수 있다.
< 중첩리스트를 이용한 DataFrame 생성 >
import numpy as np
import pandas as pd
# python의 중첩리스트를 이용해서 DF를 만들어보자 => matrix
# np.nan = NaN을 나타내는 상수
data = [[2, np.nan], [7, -3], [np.nan, np.nan], [1, -2]] # 4 x 2 matrix
df = pd.DataFrame(data)
# column 명이 존재하지 않으므로 숫자 index로 생성된다.
display(df)
# column명과 index를 지정해보자
df = pd.DataFrame(data, columns=['one','two'], index=['a','b','c','d'])
display(df)
# sum() 함수
# numpy 에서는 sum()에 axis를 지정하지 않으면 None으로 설정
# => sum()의 대상이 ndarray 전체 요소
# DataFrame의 경우는 모든 요소를 대상으로 하지 않는다.
# axis=0 (default) # axis=0 이면 행방향이므로 행들의 값을 합산함
# series 형태로 return
print(df.sum())
# one 10.0
# two -5.0
# dtype: float64
print(df.sum(axis=1)) # axis=1 : 열방향이므로 열들의 값을 합산
# a 2.0
# b 4.0
# c 0.0
# d -1.0
# dtype: float64
< DataFrame의 정렬 >
# DataFrame의 정렬 - ndarray matrix의 sort와 다름
import numpy as np
import pandas as pd
np.random.seed(1)
# 2차원 ndarray를 정수형 난수로 생성하고 그것을 이용해서 DataFrame 생성
df = pd.DataFrame(np.random.randint(0,10,(6,4)))
df.columns = ['A','B','C','D']
# 숫자 index 대신 날짜 사용
# pandas의 date_range() 함수로 20200101 부터 6일간 1일씩 증가하면서 날짜 생성
df.index = pd.date_range('20200101', periods=6)
display(df)
# 정렬(sort)
# random.shuffle() 함수는 원본이 바뀐다.
# np.random.shuffle(df.index)
# error : index does not support mutable operations
# 이미 만들어져 있는 index를 다른 것으로 대체할 수는 있지만
# 수정하는 것은 지원하지 않기 때문
# 그래서 permutation() 함수 이용
# permutation() : shuffle()과 기능은 동일한데 index를 수정하지 않고
# 랜덤으로 섞은 또 다른 ndarray를 return
random_date = np.random.perutation(df.index)
# reindex() 함수로 index를 수정
# column의 순서도 변경이 가능한데 별 의미는 없다.
df2 = df.reindex(index=random_date, columns=['B','A','D','C'])
display(df2)
# sort_index() : index를 이용한 정렬, column의 정렬 둘 다 가능
# 정렬된 결과 DataFrame이 return
# 날짜 인덱스에 대해서 내림차순 정렬
display(df2.sort_index(axis=0, ascending=False)) # 행방향, 내림차순
# column들에 대해서 오름차순 정렬
display(df2.sort_index(axis=1, ascending=True)) # 열방향, 오름차순
# 값으로 정렬하는 방법도 있다.
display(df2.sort_values(by='B')) # B 라는 column에 대해서 값으로 오름차순
# 만약 B의 값이 동률이라면? => list 형태로 그 다음 정렬탐색 순서를 전달
display(df2.sort_values(by=['B','A'])) # B가 같으면 A를 기준으로 정렬
< 알아두면 좋은 DataFrame 함수들 >
import numpy as np
import pandas as pd
np.random.seed(1)
df = pd.DataFrame(np.random.randint(0, 10, (6,4)),
index=pd.date_range('20200101', periods=6),
columns=['A','B','C','D'])
df['E'] = ['AA','BB','CC','CC','AA','CC']
# 중복을 없애고 unique한 값만을 추출하고 싶음
# unique() 함수 이용
print(df['E'].unique()) # ['AA' 'BB' 'CC']
# 각각의 값들의 개수를 알고 싶음
# value_counts() 함수 이용
# Series 형태로 각 항목의 개수 return
print(df['E'].value_counts())
# CC 3
# AA 2
# BB 1
# Name: E, dtype: int64
# 값이 포함되어 있는지를 확인하는 함수
# isin() : 전달된 인자에 대해서 해당 값이 있는지 찾아서 boolean mask로 return
print(df['E'].isin(['AA','BB']))
# 2020-01-01 True
# 2020-01-02 True
# 2020-01-03 False
# 2020-01-04 False
# 2020-01-05 True
# 2020-01-06 False
# Freq: D, Name: E, dtype: bool
< lambda expression을 이용한 DF 처리 >
# apply와 lambda를 이용한 처리
import numpy as np
import pandas as pd
np.random.seed(1)
df = pd.DataFrame(np.random.randint(0, 10, (6,4)),
index=pd.date_range('20200101', periods=6),
columns=['A','B','C','D'])
# x가 인자이며 어떤식으로 수행할지 콜론뒤에 서술
my_func = lambda x : x.max() - x.min()
# my_func를 적용해서 열방향으로 붙이겠다는 의미
df['최대-최소'] = df.apply(my_func, axis=1)
# 결과로 새로운 column인 '최대-최소'가 들어간다.
print(df.apply(my_func, axis=0))
# my_func를 적용해서 행방향으로 만들겠다는 의미
# A 6
# B 9
# C 9
# D 7
# 최대-최소 4
# dtype: int64
'Python > Data Analysis' 카테고리의 다른 글
Data Analysis / ML / Basic Concept(1) (0) | 2020.09.22 |
---|---|
Data Analysis / pandas / DataFrame(4) (0) | 2020.09.15 |
Data Analysis / pandas / DataFrame(2) (0) | 2020.09.11 |
Data Analysis / Pandas / DataFrame(1) (0) | 2020.09.09 |
Data Analysis / Pandas / Series (0) | 2020.09.09 |