파이썬판다스 따라하기/3판다스연산

#판다스연산4편 - 판다스 diff pct_change expending rolling groupby ewm 함수

모두의 실험실 2023. 6. 1. 05:43
728x90

판다스에서 사용하는 함수들은

사용자가 일반 파이썬 연산으로

구현도 가능함

 

하지만 오류검증등 코드를 완성도 있게

구현하는데 시간이 소요되기 때문에

구현 보다는 활용이 더 현명함

 

하지만 앞서 말한것과 같이 

다른사람이 만든 코드를 사용하는것이

항상 옳은 방향은 아님

 

예를 들어 대량의 데이터를 반복하여

수행하며 직접 코드를 만들어서

사용하는 것이 속도가 더빠르고

이 작업의 핵심이 시간이라면

직접만들어서 사용할 수 밖에 없음

 

기능과 리소스등을 고려해서 오픈소스를

사용하는 것이 현명함

 

DataFrame.diff(periods=1, axis=0)

diff는 diffence(차이)의 줄임말임

 axis가 0이면 행을 의미하며 axix가 1이면 열이며

설정된 axis값을 참조하여 행열을 비교함

axis의 기본값은 0임

periods는 숫자이전 행또는 열과의 차를 출력함

import pandas as pd
data = [[1,2,3],[4,5,6],[7,8,9]]
df = pd.DataFrame(columns = ['col1','col2','col3'],index = ['index1','index2','index3'],data = data)
print(df)
print('\n------------------\n')
print(df.diff()) #periods = 1 , axis = 0 행과비교
print('\n------------------\n')
print(df.diff(axis = 1)) #periods = 1 , axis = 1 열과비교
print('\n------------------\n')
print(df.diff(periods = 2)) #periods = 2 , axis = 0 행과비교
print('\n------------------\n')
print(df.diff(periods = -2)) #periods = -2 , axis = 0 행과비교

-결과 (이미지)

 

periods와 axis에 의해 결과 값이 출력됨

NaN이 나오는 이유는 Index1과 Col1의

이전 행열 값이 없기 때문임

periods =2 또는 -2의 경우도 마찬가지임

-2의 경우는 Index3 이 맨마지막이기 때문에

빼야될 행이 없음 그래서 NaN이 출력됨

 

DataFrame.pct_change(periods=1, fill_method='pad', limit=None, freq=None, kwargs)

diff는 행열을 선택하여 값을 구할 수 있지만

pct_change는 열의 연산만 가능함

periods가 1의경우

결과 값은 (n행 - n-1행)/n-1행을 의미함

periods가 2의경우

결과 값은 (n행 - n-2행)/n-2행을 의미함

NaN이  포함된  연산은 0으로 반환

periods는 diff와 동일

fill_method는 결측치 NaN을 대체할 값을 정하는 요소이며

fill_method = 'ffill'의 경우는 기본값 바로 윗행의 값으로 결측치를 대체하며

fill_method = 'bfill'의 경우는 기본값 바로 아랫행의 값으로 결측치를 대체함

기본적인값은 'ffill'임

limit = 2이면 결측치를 2개 까지 교체함

import pandas as pd
import numpy as np
data = [[1,2,3],[4,np.NaN,6],[np.NaN,8,np.NaN],[np.NaN,11,12]]
df = pd.DataFrame(columns = ['col1','col2','col3'],index = ['index1','index2','index3','index4'],data = data)
print(df)
print('\n------------------\n')
print(df.pct_change()) #periods = 1 
print('\n------------------\n')
print(df.pct_change(periods = 2))
print('\n------------------\n')
print(df.pct_change(periods = 2,fill_method = 'bfill'))
print('\n------------------\n')
print(df.pct_change(periods = -1))
print('\n------------------\n')
print(df.pct_change(limit=1)) #열기준으로 위에서부터 1개만 결측값대체

-결과 (이미지)

 

limit는 열기준으로 NaN값을 측정함

col1의 NaN이 2개 이므로 limit = 1이면

index3,col1의 값만 4로 연산이 대체되여

연산됨 

 

DataFrame.expanding(min_periods=1, center=None, axis=0, method='single')

expanding은  확장이라는 의미를 가지고 있음

결과값은 행열의 누적연산임

주로 expanding.sum() 등과 같이 

메서드와 함께 사용되며 expanding() 단독으로는 

출력결과가 없음

min_periods는 연산을 수행할 최소갯수임

min_periods = 4인데 3행이라면 NaN을 반환함

axis 0은 열의 연산 1은 행의 연산을 수행함 기본값은 0임

method는 'single'과 'table'이 될수 있으며

'table'경우는 'numba' 패키지가 설치 되어있어야 

사용가능하며 대량 연산에 빠른속도를 지원함

datetime.now()를 사용하여 코드 수행 처음과 끝에

입력하여 수행시간을 측정하여 더 빠른 것을 선택가능함

 

import pandas as pd
import numpy as np
data = [[1,2,3],[4,5,6],[7,8,9]]
df = pd.DataFrame(columns = ['col1','col2','col3'],index = ['index1','index2','index3'],data = data)
print(df)
print('\n------------------\n')
print(df.expanding())
print('\n------------------\n')
print(df.expanding().sum())
print('\n------------------\n')
print(df.expanding(axis = 1).sum())
print('\n------------------\n')
print(df.expanding(min_periods =3).sum())
print('\n------------------\n')
print(df.expanding(method = 'table').sum(engine='numba'))

-결과 (이미지)

 

DataFrame.rolling(window, min_periods=None, center=False, win_type=None, on=None, axis=0, closed=None, method='single')

rolling은 주가의 분봉 일봉등 평균이동선을 구할때 주로 사용

rolling의 사전적의미는 '구르기' '회전' '구르는'의 의미가 있음

판다스에서는 기간을 설정하여 연산함

window는 가장 중요한 요소이며 기간의 범위를 정함

closed 요소는 연산의 범위의 양쪽 엣지가 포함되는 여부를 결정

window 3설정후 4행 연산은 2~4행까지 연산을 해주는데

left는 1 ≤ 범위 < 4

right는 1 < 범위 4

both는 1 ≤ 범위4

neither는 1 < 범위 < 4

closed = '요소값' 의 형태이며 기본값은 right임

win_type는 2가지 요소값을 가지며 'triang'과 'gaussian'이 있음

'triang'은 삼각함수로 가중치를 부여하며

'gaussian'은 가우시안 분포로 가중치를 부여함

on은 해당 열의 값을 활용하여 window값을 설정가능함

import pandas as pd
import numpy as np
data = [[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15]]
df = pd.DataFrame(columns = ['col1','col2','col3'],index = ['index1','index2','index3','index4','index5'],data = data)
print(df)
print('\n------------------\n')
print(df.rolling(3))
print('\n------------------\n')
print(df.rolling(3).sum())
print('\n------------------\n')
print(df.rolling(3,closed = 'left').sum())
print('\n------------------\n')
print(df.rolling(3,closed = 'both').sum())
print('\n------------------\n')
print(df.rolling(3,win_type = 'triang').sum())
print('\n------------------\n')
print(df.rolling(3,win_type = 'gaussian').sum(std=2))

-결과 (이미지)

 

DataFrame.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=NoDefault.no_default, observed=False, dropna=True)

 

groupby는 데이터를 그룹화 하여

연산을할때 주로 사용함

쉽게 설명해 여러 그룹이 가능한 것들을 

최대한 묶어서 연산이 가능함

 

학급의 친구들이 여러번 시험을 쳤다고 가정함

import pandas as pd
import numpy as np
data = [['철수',93,84,98],['철수',94,85,99],['철수',92,83,96],['영희',100,72,84],['영희',100,71,80]
        ,['맹구',79,69,72],['맹구',76,65,77],['맹구',71,60,72],['영구',71,48,21],['영구',71,44,29]]
df = pd.DataFrame(columns = ['학생','코딩','영어','수학'],index = range(len(data)),data = data)
print(df)

-결과 (이미지)

 

철수는 시험을 3번 영희는 2번 맹구는 3번 영구는 2번의 시험을 침학생이 친 과목의 평균을 groupby와 mean()을 활용하여 구할 수 있음그리고 count()로 몇번의 해당과목의시험을 쳤는지도 알 수 있음

 

agg는 복수의 함수를 사용하여

결과를 복수의 column으로 출력할수 있음

 

print(df.groupby('학생').mean())
print('\n##########\n')
print(df.groupby('학생').count())
print('\n##########\n')
print(df.groupby('학생').agg(['sum','mean']))

-결과 (이미지)

 

apply를 사용하여 데이터 프레임에내장함수가 아닌 사용자 함수를사용할 수 있음

## 코딩 2위가 해당되는 시험을 출력해주는 함수
def ranking(df,n=2,col='코딩'):
    return df.sort_values(by=col)[n-1:n]

print(df.groupby('학생').apply(ranking)) 
print('\n##########\n')
print(df.groupby('학생',group_keys=False).apply(ranking))

-결과 (이미지)

 

각 학생들이 두번째로 잘쳤던  '코딩'시험이 있었던 전체 시험을 출력함group_key를 '학생'으로 했는데False를 하여  숨길 수 있음

 

함수가 철수 영희 맹구 영구만 시험을 쳤지만 '미진'은 시험을을 안 쳤는데 데이터프레임에 포함이 되어있다면 observed옵션으로 선택적 데이터를 보여 줄 수 있음 참고로 ovserve는 관찰하다는 의미임

df_cat = pd.Categorical(df['학생'], categories=['철수', '영희', '맹구', '영구','미진'])
print(df_cat)
print('\n##########\n')
print(df['수학'].groupby(df_cat,observed=False).count())
print('\n##########\n')
print(df['수학'].groupby(df_cat,observed=True).count())

-결과 (이미지)

 

dropna 옵션을 사용하여 선택적으로 보여줄 수 있음 '맹구'가 index 6의 시험지에 답안지를 늦게 제출한게 뒤늦게 알려져서 실격처리가 되었는데 실격된 데이터를 안보이게 하려면 dropna = True로 하면 됨

import numpy as np
print(df)
df.loc[6,'학생'] = np.NaN
print('\n##########\n')
print(df)
print('\n##########\n')
print(df.groupby('학생',dropna=True).mean())
print('\n##########\n')
print(df.groupby('학생',dropna=False).mean())

-결과 (이미지)

dropna = False로 하면 mean()에 적용되지 않고 분리되어 보여짐

 

DataFrame.ewm(com=None, span=None, halflife=None, alpha=None, min_periods=0, adjust=True, ignore_na=False, axis=0, times=None, method='single')

 

emw는  exponentially weighted moving약자인데 해석하면 '지수가중이동' 임

com,span,alpha,halflife 등 옵션의 수치를 입력하여 사용자가 원하는 값을 구할 수 있음주로 시계열 데이터 분석에 사용됨각각의 옵션에 따른 사용자 함수를 구현할 수 있으며 pandas는 내장으로 구현되어 있음

import pandas as pd
import numpy as np
df = pd.DataFrame(columns = ['값'], data = [0,1,2,3,4])

df['mean'] = df['값'].mean()

df['com2'] = df['값'].ewm(com=2).mean()
df['com10'] = df['값'].ewm(com=10).mean()
df['span4'] = df['값'].ewm(span=4).mean()
df['span8'] = df['값'].ewm(span=8).mean()
df['alpha03'] = df['값'].ewm(alpha=0.3).mean()
df['alpha05'] = df['값'].ewm(alpha=0.5).mean()
df['halflife2'] = df['값'].ewm(halflife=2).mean()
df['halflife5'] = df['값'].ewm(halflife=5).mean()
df

   -결과 (이미지)

 

com,span,alpha,halflife의 각옵션이 실제로 계산되는 수식은 다음과 같음

사용자가 원하는 옵션을 사용하여 데이터 구현 가능함

 

import math

def EWMA(data, factor , formula):
    ewma=[0]*len(data)
    molecule=0
    denominator=0
    for i in range(len(data)):
        molecule = (data[i] + (1.0-formula)*molecule)
        denominator+=(1-formula)**i
        ewma[i] = molecule/denominator  
    return ewma


data = [0,1,2,3,4]

com_factor = 2
com_formular = 1.0 / (1.0 + com_factor)

span_factor = 4
span_formular = 2.0 / (1.0 + span_factor)

alpha_factor = 0.3
alpha_formular = alpha_factor #alpha_factor

halflife_factor = 5
halflife_formular = 1- math.exp(-1*math.log(2)/halflife_factor)

print(EWMA(data, com_factor, com_formular))
print(EWMA(data, span_factor, span_formular))
print(EWMA(data, alpha_factor, alpha_formular))
print(EWMA(data, halflife_factor, halflife_formular))

-결과 (드래그로 확인가능)
[0.0, 0.6, 1.2631578947368423, 1.984615384615385, 2.7582938388625595]
[0.0, 0.625, 1.326530612244898, 2.0955882352941178, 2.921582234559334]
[0.0, 0.5882352941176471, 1.2328767123287672, 1.930517173312278, 2.6767877105044895]
[0.0, 0.5346019613807635, 1.0921248294619423, 1.6723501058423316, 2.2749760411274242]

 

pandas를 이용한것과 사용자함수 EWMA가 동일함을 확인완료함

 

 

태그

-------------------------------------------------------------

#python, #파이썬, #anaconda, #아나콘다, #기초, #클래스, #class, #import, #selenium, #셀레늄, #자동, #교육, #코딩교육, #coding, #chatgpt, #챗GPT, #로봇,

 

728x90
반응형