Pandas DataFrame 객체 내 연산 배우기

상후·2025년 4월 8일
post-thumbnail

시작하기 전에 import 하기

import numpy as np
import pandas as pd
import numba

반올림(round)

round 함수는 DataFrame 객체 내의 요소를 반올림하는 메서드입니다.

사용법

df.round(decimals=0, args, kwargs) decimals : 소수 n번째 자리 '까지' 반올림을 합니다. 만약 음수면 10의 n승 자리 까지 반올림 합니다.

예시

먼저, numpy의 random 메서드를 이용하여 3x3 난수 객체를 하나 생성하겠습니다.

col = ['col1','col2','col3']
row = ['row1','row2','row3']
data = np.random.rand(3,3)*100
df = pd.DataFrame(data=data, index=row, columns=col)
print(df)

decimals = 0인 경우
0은 기본값으로 일의자리 까지 반올림을 하게 됩니다.

print(df.round(0))

decimals > 0인 경우
양수인 경우 소수 n번째 자리 까지 반올림을 합니다.
(실행 예시 1)

print(df.round(1))


(실행 예시 2)

print(df.round(2))

decimals < 0인 경우
양수인 경우 10의 n승 자리 까지 반올림을 합니다.

print(df.round(-1))


합계(sum)

sum 메서드는 객체의 행이나 열의 총 합계를 구하는 메서드 입니다..

사용법

기본 사용법
df.sum(axis=None, skipna=None, level=None, numeric_only=None, min_count=0, kwargs)
axis : { 0 : 행 / 1 : 열} 더할 레이블을 선택합니다.
skipna : {True or False} Na가 존재할 경우 무시할지의 여부입니다. 기본값은 True입니다.
level : Multi Index일 경우 레벨을 설정합니다.
numeric_only : 숫자 데이터만 사용할지의 여부 입니다.
min_count : 계산에 필요한 숫자의 최소 갯수입니다.

예시

먼저, numpy의 random 메서드를 이용하여 3x3 난수 객체를 하나 생성하겠습니다.

col = ['col1','col2','col3']
row = ['row1','row2','row3']
data = [[1,2,3],[4,5,6],[7,np.nan,9]]
df = pd.DataFrame(data=data,index=row,columns=col)
print(df)

axis를 설정하여 더하기 수행
0은 열의 요소들의 합, 1은 행의 요소들의 합 입니다.
(실행 예시 1)

print(df.sum(axis=0))


(실행 예시 2)

print(df.sum(axis=1))

skipna를 변경하여 계산하기
위 계산에서는 NaN을 무시하고 계산한 것을 알 수 있습니다.
skipna=False일 경우 NaN이 포함되는경우에는 NaN을 반환합니다.

print(df.sum(axis=0,skipna=False))

min_count를 변경하여 계산하기
min_count는 계산에 필요한 숫자의 최소 갯수를 의미합니다.
즉, min_count=3이라면 NaN을 포함하는 행의 경우 숫자가 2개이기 때문에
skipna=True임에도 NaN을 출력하게 됩니다.

print(df.sum(axis=1,min_count=3))


곱 (prod, product)

prod 메서드는 객체의 행이나 열의 곱을 구하는 메서드 입니다.
product메서드와 동일합니다.

사용법

df.prod(axis=None, skipna=None, level=None, numeric_only=None, min_count=0, kwargs)
axis : { 0 : 행 / 1 : 열} 곱할 레이블을 선택합니다.
skipna : {True or False} Na가 존재할 경우 무시할지의 여부입니다. 기본값은 True입니다.
level : Multi Index일 경우 레벨을 설정합니다.
numeric_only : 숫자 데이터만 사용할지의 여부 입니다.
min_count : 계산에 필요한 숫자의 최소 갯수입니다.

예시

먼저, NaN이 포함된 3x3 객체를 하나 생성하겠습니다.

col = ['col1','col2','col3']
row = ['row1','row2','row3']
data = [[1,2,3],[4,5,6],[7,np.NaN,9]]
df = pd.DataFrame(data=data,index=row,columns=col)
print(df)

axis를 설정하여 곱하기 수행
0은 열의 요소들의 곱, 1은 행의 요소들의 곱 입니다.
(실행 예시 1)

print(df.prod(axis=0))


(실행 예시 2)

print(df.prod(axis=1))

skipna를 변경하여 계산하기
위 계산에서는 NaN을 무시하고 계산한 것을 알 수 있습니다.
skipna=False일 경우 NaN이 포함되는경우에는 NaN을 반환합니다.

print(df.prod(axis=0, skipna=False))

min_count를 변경하여 계산하기
min_count는 계산에 필요한 숫자의 최소 갯수를 의미합니다.
즉, min_count=3이라면 NaN을 포함하는 행의 경우 숫자가 2개이기 때문에
skipna=True임에도 NaN을 출력하게 됩니다.

print(df.prod(axis=1, min_count=3))


절대값 (abs)

abs메서드는 각 요소의 절댓값을 반환하는 메서드입니다.

사용법

df.abs( )
숫자의 경우 절댓값을 반환하며, 복소수의 경우 복소수의 크기가 반환됩니다.
복소수가 a+bj인 경우 복소수의크기
NaN의 경우는 NaN을 그대로 출력합니다.

예시

col = ['col1','col2','col3']
row = ['row1','row2','row3']
data = [[-1,2,-3.5],[4,-5.5, 3+4j],[7,np.nan,0]]
df = pd.DataFrame(data=data,index=row,columns=col)
print(df)

abs 메서드 실행
일반적인 수의 경우 절댓값을 취하며, 복소수의 경우 크기가 출력되는것을 확인 할 수 있습니다.

print(df.abs( ))


전치 (transpose, T)

transpose 메서드는 Dataframe객체를 전치 하는 메서드입니다.
만약 (n,m)짜리 DataFrame이라면 (0,0) 부터 (n,m)을 연결하는 대각선을 중심으로 뒤집는것과 같습니다.
T 메서드는 transpose 메서드와 동일합니다.

사용법

기본 사용법
df.transpose(args, copy=False)
copy : 사본을 반환할지 여부입니다. 여러 dtype으로 이루어진 경우 자동으로 True가 됩니다.

예시

먼저, 간단한 4x3 객체를 하나 생성하겠습니다.

col = ['col1','col2','col3']
row = ['row1','row2','row3','row4']
data = [['A',1,2],['B',3,4],['C',5,6],['D',7,8]]
df = pd.DataFrame(data=data,index=row,columns=col)
print(df)

transpose 메서드 실행
행과 열이 뒤바뀌며 전치가 실행된 것을 확인 할 수 있습니다.

print(df.transpose())


순위 (rank)

rank 메서드는 축에 대해서 순위를 매기는 메서드 입니다. 동일 순위일 경우 평균을 반환합니다.

사용법

기본 사용법
df.rank(axis=0, method='average', numeric_only=None, na_option='keep', ascending=True, pct=False)
axis : {0 : index / 1 : columns} 순위를 매길 레이블입니다.
method : {'average' / 'min' / 'max' / 'first' / 'dense'} 동순위 일때 처리 방법입니다.
average는 평균, min은 낮은순위, max는 높은순위, first는 나타나는순서대로
dense의 경우는 min과 같지만 그룹간 순위는 항상 1씩 증가합니다.
numeric_only : {True / False} 숫자만 순위를 매길지 여부 입니다.
na_option : {'keep' / 'top' / 'bottom'} NaN값의 처리 방법입니다.
keep의 경우 NaN순위 할당, top의 경우 낮은순위 할당, bottom의 경우 높은 순위를 할당합니다.
ascending : {True / False} 오름차순으로 할지의 여부 입니다.
pct : {True / False} 순위를 백분위수형식으로 할지 여부입니다.

예시

먼저, pd.NA가 포함된 간단한 9x1 객체를 하나 생성하겠습니다.
같은 수의 경우 보기 쉽도록 인덱스에 기호를 붙여두었습니다.

data = [[5],[5],[pd.NA],[3],[-3.1],[5],[0.4],[6.7],[3]]
row = ['A★','B★','C','D☆','E','F★','G','H','I☆']
df = pd.DataFrame(data=data, index=row, columns=['Value'])
print(df)

method에 따른 차이
method에따라 동점의 경우 순위가 어떻게 매겨지는지 확인 할 수 있습니다.

average : D와 I의 경우 각각 3등 4등이기때문에 3.5 출력
min : A, B, F의 경우 각각 5등 6등 7등으로 가장 낮은등수인 5 출력
max : A, B, F의 경우 각각 5등 6등 7등으로 가장 높등수인 7 출력
first : 동점일경우 위에서부터 매김 D와 I 각각 3등 4등
dense : min처럼 동작하지만 등수가 순차적으로 증가

df['average']=df['Value'].rank(method='average')
df['min']=df['Value'].rank(method='min')
df['max']=df['Value'].rank(method='max')
df['first']=df['Value'].rank(method='first')
df['dense']=df['Value'].rank(method='dense')
print(df)

na_option에 따른 차이
na_option에 따라 Na가 포함된경우 순위가 어떻게 매겨지는지 확인할 수 있습니다.
추가로 pct 의 경우도 추가하였습니다.

keep : Na요소에 NaN을 부여하여 그대로 둡니다.
top : Na에게 가장 높은 순위를 부여합니다. 1등이 된것을 볼 수 있습니다.
bottom : Na에게 가장 높은 순위를 부여합니다. 9등이 된것을 볼 수 있습니다.
pct : True일 경우 백분위수로 표시합니다.

df['keep']=df['Value'].rank(na_option='keep')
df['top']=df['Value'].rank(na_option='top')
df['bottom']=df['Value'].rank(na_option='bottom')
df['pct']=df['Value'].rank(pct=True)
print(df)


차이(이산) (diff)

diff는 한 객체 내에서 열과 열 / 행과 행의 차이를 출력하는 메서드 입니다.

사용법

기본 사용법
자세한 내용을 아래 예시를 참고 바랍니다.
df.diff(periods=1, axis=0)
axis : 비교할 축을 지정합니다. axis=0 인 경우 행끼리 비교하고 axis=1인 경우 열 끼리 비교합니다.
periods : 비교할 간격을 지정합니다. 기본은 +1로 바로 이전 값과 비교합니다.

예시

먼저 기본적인 사용법 예시를 위해 8x3짜리 객체를 생성하겠습니다.

a = [1,2,3,4,5,6,7,8]
b = [1,2,4,8,16,32,64,128]
c = [8,7,6,5,4,3,2,1]
data = {"col1":a,"col2":b,"col3":c}
df = pd.DataFrame(data)
print(df)

기본적인 사용법

axis에 따라서 행끼리 비교할지, 열 끼리 비교할지 정할 수 있습니다.
axis=0인 경우 행 - 바로전 행 의 값을 출력합니다. 비교할 값이 없다면 NaN을 출력합니다.
(실행 예시1)

print(df.diff(axis=0))

(실행 예시2)

print(df.diff(axis=1))

periods의 사용
periods의 경우 기본값은 +1로 +1인 경우 바로 이전 값과의 차를 출력합니다.
+3인 경우 3칸 이전 값과 비교하고 -2인 경우 2칸 후의 값과 비교하게 됩니다.
(실행 예시1)

print(df.diff(periods=3))


(실행 예시 2)

print(df.diff(periods=-2))


차이 백분률(pct_change)

pct_change는 한 객체 내에서 행과 행의 차이를 현재값과의 백분율로 출력하는 메서드 입니다.
즉, (다음행 - 현재행)÷현재행 을 의미합니다.

사용법

df.pct_change(periods=1, fill_method='pad', limit=None, freq=None, kwargs)
periods : 비교할 간격을 지정합니다. 기본은 +1로 바로 이전 값과 비교합니다.
fill_method : {ffill : 앞의 값으로 채움 / bfill : 뒤의 값으로 채움} 결측치를 대체할 값입니다.
limit : 결측값을 몇개나 대체할지 정할 수 있습니다.
freq : 시계열 API에서 사용할 증분을 지정합니다. (예: 'M' 또는 BDay( ))

예시

먼저 기본적인 사용법 예시를 위해 6x3짜리 객체를 생성하겠습니다.

a = [1,1,4,4,1,1]
b = [1,2,4,8,16,32]
c = [1,np.nan,np.nan,np.nan,16,64]
data = {"col1":a,"col2":b,"col3":c}
df = pd.DataFrame(data)
print(df)

기본적인 사용법
기본적으로 (다음행 - 현재행)÷현재행을 의미합니다.

print(df.pct_change())

periods 인수 사용
periods인수는 계산할 간격을 나타냅니다. 기본은 1로 +1을 의미하며 마이너스일 경우 반대방향으로 계산합니다.
periods=2 인 경우

print(df.pct_change(periods=2))

periods=-1 인 경우 (현재행 - 다음행)÷다음행 입니다.

print(df.pct_change(periods=-1))

fill_method / limit인수의 사용
fill_method인수는 결측치를 대체할 값을 지정할 수 있습니다.
fill_method='ffill'인 경우는 기본값으로 바로 윗값으로 결측치를 대체합니다.
fill_method='bfill'인 경우는 바로 아랫값으로 결측치를 대체합니다.

print(df.pct_change(fill_method='bfill'))

limit인수는 결측치를 몇개까지 대체할지 지정합니다.

print(df.pct_change(limit=2))


누적 계산 (expending)

expanding 메서드는 행이나 열의 값에 대해 누적으로 연산을 수행하는 메서드입니다.
df.expanding( ).sum( ) 처럼 추가 메서드를 이용하여 연산을 수행합니다.

사용법

df.expanding(min_periods=1, center=None, axis=0, method='single').추가메서드()
min_periods : 연산을 수행할 요소의 최소 갯수입니다. 이보다 작으면 NaN을 출력합니다.
center : 미사용
axis : 누적 연산을 수행할 축을 지정합니다.
method : {single / table} 연산을 한 줄씩 수행할지 아니면 전체 테이블에 대해서 롤링을 수행할지 여부입니다.
기본값은 'singl'로 한 줄씩 연산을 수행합니다. 'table'을 사용하기 위해서는 numba 라이브러리가 설치되어있어야 하며,
추가 연산 메서드에서 engine=numba로 설정해주어야 합니다.

예시

먼저 기본적인 사용법 예시를위하여 4x2 짜리 데이터를 만들어 보겠습니다.
method='table'의 사용을 위해 numba 라이브러리를 추가로 import하였습니다.

data = {'col1':[1,2,3,4],'col2':[3,7,5,6]}
idx = ['row1','row2','row3','row4']
df = pd.DataFrame(data = data, index = idx)
print(df)

기본적인 사용법
기본적으로 df.expanding( ).추가연산메서드 형태로 지정하면, 해당 연산을 누적으로 진행하게 됩니다.

print(df.expanding().sum())

min_period를 지정하게되면, 입력값 만큼의 갯수가 충족되지 않으면 연산을 하지 않고 NaN을 반환합니다.

print(df.expanding(min_periods=4).sum())

axis=1로 지정하면 열 기준으로 누적값의 계산이 수행됩니다.

print(df.expanding(axis=1).sum())

method='table'로 입력할 경우 numba 라이브러리를 이용해 연산을 테이블단위로 롤링할 수 있습니다.
추가 연산 메서드에 인수로 engine='numba'를 지정해주어야 합니다.

파이썬은 인터프리티 언어라서 C/C++등과 같은 언어에 비해 느립니다.
Numba는 파이썬 코드를 LLVM컴파일러를 이용해 머신코드로 바꾸어 수치연산을 가속해주는 라이브러리입니다.

print(df.expanding(method='table').sum(engine='numba'))


기간이동 계산 (rolling)

rolling 메서드는 현재 열에 대하여 일정 크기의 창(window)를 이용하여 그 window안의 값을 추가 메서드를 통해 계산하는 메서드 입니다.

사용법

df.rolling(window, min_periods=None, center=False, win_type=None, on=None, axis=0, closed=None, method='single')
window : 계산할 창(window)의 크기 입니다. 열 기준으로 계산할 경우 행의 수입니다.
min_periods : 계산할 최소 크기(기간) 입니다. window 안의 값의 수가 min_periods의 값보다 작을경우 NaN을 출력합니다.
기본적으로 window 크기와 동일합니다.
center : {True / False} 레이블을 window의 중간에 둘지 여부입니다. 기본값은 False로 레이블이 창 우측에 위치합니다.
win_type : {'triang' / 'gaussian' / ...} 가중치를 넣어 계산할 경우 계산 방식 입니다. 때에따라 연산 메서드에 추가 인수를 지정해야할수도 있습니다.
on : 시계열 인덱스나, 시계열과 유사한 열이 있을 경우 이 열을 기준으로 rolling을 수행할 수 있습니다.
axis : 계산의 기준이 될 축입니다.
closed : {'left' / 'right' / 'both' / 'neither'} window가 닫히는 방향입니다. 자세한건 아래 예시 참고바랍니다
method :{'single' / 'table'} numba 를 이용하여 테이블 계산을 진행하여 속도를 높힐지 여부입니다. 현재 'single'만 사용가능합니다.
method 인수의 numba 사용은 02-09 누적계산(expending)에서 자세히 다루고 있습니다.

예시

먼저 기본적인 사용법 예시를위하여 6x2 짜리 데이터를 만들어 보겠습니다.
col2는 on 인수의 사용을 위해 시계열 값으로 작성하였으나, 일반 계산에서는 진행되지 않습니다.

period = pd.period_range(start='2022-01-13 00:00:00',end='2022-01-13 02:30:00',freq='30T')
data = {'col1':[1,2,3,4,5,6],'col2':period}
idx = ['row1','row2','row3','row4','row5','row6']
df = pd.DataFrame(data= data, index = idx)
print(df)

기본적인 사용법
window 크기를 지정해주면, 현재 행 이전으로 window 크기 만큼의 계산을 수행합니다.

period = pd.period_range(start='2022-01-13 00:00:00',end='2022-01-13 02:30:00',freq='30T')
data = {'col1':[1,2,3,4,5,6],'col2':period}
idx = ['row1','row2','row3','row4','row5','row6']
df = pd.DataFrame(data= data, index = idx)
print(df['col1'].rolling(window=3).sum())

closed인수의 사용
closed는 계산의 닫는 위치를 지정합니다. 만약 6행을 기준으로 window=3을 계산한다고 하면 아래와 같은 범위로 window경계가 지정됩니다.

left : 3 ≤ x < 6
right : 3 < x ≤ 6
both : 3 ≤ x ≤ 6
neither : 3 < x < 6
closed='left'인 경우

center인수의 사용
center을 이용하여 레이블이 window의 중앙에 올지를 정할 수 있습니다.
자세한건 아래 이미지를 참고하면 이해하기 쉽습니다.

center=True인 경우 레이블이 window의 중앙에 위치한 것을 알 수 있습니다.

print(df[['col1']].rolling(window=3, center=True).sum())

on 인수의 사용
on='col2'를 이용하여 col2열의 시계열 인덱스를 기준으로 rolling의 수행이 가능합니다.

print(df.rolling(window='60T',on='col2').sum())


그룹화 계산 (groupby)

groupby 메서드는 데이터를 그룹화하여 연산을 수행하는 메서드 입니다.

사용법

df.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=NoDefault.no_default, observed=False, dropna=True)
by : 그룹화할 내용입니다. 함수, 축, 리스트 등등이 올 수 있습니다.
axis : 그룹화를 적용할 축입니다.
level : 멀티 인덱스의 경우 레벨을 지정할 수 있습니다.
as_index : 그룹화할 내용을 인덱스로 할지 여부입니다. False이면 기존 인덱스가 유지됩니다.
sort : 그룹키를 정렬할지 여부입니다.
group_keys : apply메서드 사용시 결과에따라 그룹화 대상인 열이 인덱스와 중복(group key)이 될 수 있습니다. 이 때, group_keys=False로 인덱스를 기본값으로 지정할 수 있습니다.
squeeze : 결과가 1행 or 1열짜리 데이터일 경우 Series로, 1행&1열 짜리 데이터일 경우 스칼라로 출력합니다.
observed : Categorical로 그룹화 할 경우 Categorical 그룹퍼에 의해 관찰된 값만 표시할 지 여부입니다.
dropna : 결측값을 계산에서 제외할지 여부입니다.

예시

먼저 기본적인 사용법 예시를위하여 데이터를 만들어 보겠습니다.

idx=['A','A','B','B','B','C','C','C','D','D','D','D','E','E','E']
col=['col1','col2','col3']
data = np.random.randint(0,9,(15,3))
df = pd.DataFrame(data=data, index=idx, columns=col).reset_index()
print(df)

여기에 추가 연산 메서드를 입력하면, 해당 열의 그룹화된 데이터에 대해서 연산이 수행됩니다.

print(df.groupby('index').mean())

추가 메서드의 적용
추가 메서드로는 단순 연산 메서드가 아닌 agg나 apply 메서드 등 여러 메서드의 적용이 가능합니다.

print(df.groupby('index').count())

agg메서드를 이용해 여러 연산을 수행할 경우 MultiColumns 형태로 출력됩니다.

print(df.groupby('index').agg(['sum','mean']))

group_keys 인수의 사용
apply 메서드를 이용해 groupby연산을 수행할 경우, groupkey가 설정되기 때문에 때에따라 컬럼과 인덱스가 중복될 수 있습니다. 이 때 group_keys=False를 통해 기본 인덱스로 출력이 가능합니다.
(실행 예시1)

def top (df,n=2,col='col1'):
  return df.sort_values(by=col)[-n:]
print(df.groupby('index').apply(top))


(실행 예시2)

print(df.groupby('index',group_keys=False).apply(top))

observed 인수의 사용
Categorical 객체를 생성할 때, 그룹화(groupby)할 열에 있는 값이 아닌 값을 포함하게되면, 그룹화 할 때 해당 값을 표시할지 여부를 선택할 수 있습니다.

idx=['A','A','B','B','B','C','C','C','D','D','D','D','E','E','E']
col=['col1','col2','col3']
data = np.random.randint(0,9,(15,3))
df = pd.DataFrame(data=data, index=idx, columns=col).reset_index()
df_cat = pd.Categorical(df['index'], categories=['A','B','C','D','E','F'])
print(df_cat)

위 catrory 객체에 대해서 col1열을 groupby 하면 아래와 같이 카테고리에만 존재하는 F에대한 groupby 값이 출력됩니다.

print(df['col1'].groupby(df_cat).count())

observed=True로 할경우 관찰되지 않는값 (카테고리에만 존재하는값)은 표시되지 않습니다.

print(df['col1'].groupby(df_cat,observed=True).count())

as_index인수의 사용
특정 열을 지정하여 groupby할 경우 해당 열이 인덱스가 되는데, as_index=False로 하여 기존 인덱스의 유지가 가능합니다.

print(df.groupby(['index'],as_index=False).sum())

dropna인수의 사용
dropna인수를 통해 결측값(NaN)이 포함된 경우 그룹화에서 제외할지 여부를 정할 수 있습니다.
먼저 index열의 6번행을 결측값(NaN)으로 변경해보겠습니다.

df.loc[6,'index'] = np.NaN
print(df)

일반적인 사용시 NaN은 계산에서 제외되어 인덱스에 표시되지 않은것을 확인할 수 있습니다.

print(df.groupby('index').sum())

dropna=False인 경우 인덱스에 NaN이 포함되어 계산된 것을 알 수 있습니다.

print(df.groupby('index',dropna=False).sum())

level인수의 사용 (Multi Index)
Multi Index의 경우 level을 숫자나 str 형태로 지정해주어 groupby를 실행할 수 있습니다.
먼저 Multi Index 객체를 생성해보겠습니다.
(실행 예시1)

idx = [['idx1','idx1','idx2','idx2','idx2'],['row1','row2','row1','row2','row3']]
col = ['col1','col2','col2']
data = np.random.randint(0,9,(5,3))
df = pd.DataFrame(data=data, index = idx, columns = col).rename_axis(index=['lv0','lv1'])
print(df)

(실행 예시2)

print(df.groupby(level=1).sum())

(실행 예시3)

print(df.groupby(['lv1','lv0']).sum())


지수가중함수 (ewm)

ewm 은 지수가중함수 입니다. 지수가중함수는 오래된 데이터에 지수감쇠를 적용하여 최근 데이터가 더 큰 영향을 끼지도록 가중치를 주는 함수입니다.
보통 추가 메서드로 mean() 을 사용해서 지수가중평균으로 사용합니다.

사용법

df.ewm(com=None, span=None, halflife=None, alpha=None, min_periods=0, adjust=True, ignore_na=False, axis=0, times=None, method='single')
기본적으로 가중치를 결정하는 요소는 alpha 로 표기되는 평활계수(감쇠계수) 입니다. com / span / halflife를 통해 자동 계산하도록 하거나, alpha를 통해 직접 설정할 수 있습니다.
com : 질량중심 값으로 평활계수를 계산합니다. [ a = 1(1+com) ]
span : 계산 기간으로 평활계수를 계산합니다. [ a = 2/(span+1) ]
halflife : 반감기를 이용하여 평활계수를 계산합니다. [ a= e^(-ln(2) / halflife) ]
alpha : 평활계수를 직접 입력합니다. [ 0 < a ≤ 1 ]
min_periods : 계산을위한 최소 기간입니다.
adjust : 상대적 가중치의 불균형을 해소하기위해 조정계수로 나눌지의 여부입니다. 대체로 값이 많을수록 adjust를 하는것이 유리합니다.
ignore_na : 가중치를 계산할때 누락값을 무시할지 여부 입니다.
[x0, None, x1] 일때, 인 경우 ignore_na = False 이면 절대위치를 기반으로 하며,
x0와 x2의 가중치는 adjust = [ True인경우 (1-a)^2와 1 / False인 경우 (1-a)^2와 a ] 입니다.
[x0, None, x1] 일때, 인 경우 ignore_na = False 이면 절대위치를 기반으로 하며,
x0와 x2의 가중치는 adjust = [ True인경우 (1-a)와 1 / False인 경우 (1-a)와 a ] 입니다.
axis : 계산을 수행할 축 입니다.
times : 관찰에 해당하는 시간입니다. 단조증가 형태의 datetime64[ns] 형태여야합니다.
method : {single / table} 한 줄씩 계산할지(기본값) 아니면 numba engine을 사용해서 table단위로 계산할지 정할 수 있습니다.
numba 라이브러리를 import 해야하며 사용시 ewm(method='table').mean(engine='numba') 처럼 추가 메서드에 engine 설정을 해줘야합니다.

예시

먼저 기본적인 사용법 예시를위하여 데이터를 만들어 보겠습니다.

data = {'val':[1,4,2,3,2,5,13,10,12,14,np.nan,16,12,20,22]}
df = pd.DataFrame(data).reset_index()
print(df)


기본적인 사용법
기본적으로는 com / span / halflife를 통한 평활계수의 계산, 또는 alpha를 통해 평활계수를 직접 입력하여 지수가중평균을 표현합니다.

df2 = df.assign(ewm=df['val'].ewm(alpha=0.3).mean()) # val열에 ewm 메서드적용 후 df에 추가
ax = df.plot(kind='bar',x='index',y='val') # ax에 df의 bar chart 생성
ax2= df2.plot(kind='line',x='index', y='ewm', color='red', ax=ax) # ax2에 df2의 line chart 생성후 ax에 추가
plt.show() # 그래프 출력


파란색 막대가 기존 그래프, 붉은 선이 지수가중평균 입니다.

alpha에 따른 차이
alpha는 평활계수로써, 자동 계산이 가능하지만, alpha 인수를 직접 입력하여 설정이 가능합니다.
alpha가 클수록 더 큰 변화에 민감하며, alpha가 작을수록 평활한 그래프가 생성됩니다.

df2 = df.assign(ewm_a_low=df['val'].ewm(alpha=0.1).mean()) #alpha=0.1로 df2 생성
df3 = df.assign(ewm_a_high=df['val'].ewm(alpha=0.7).mean()) #alpha=0.7로 df3 생성
ax = df.plot(kind='bar',x='index',y='val') 
ax2= df2.plot(kind='line',x='index', y='ewm_a_low', color='red', ax=ax) # alpha=0.1 은 적색
ax3= df3.plot(kind='line',x='index', y='ewm_a_high', color='green', ax=ax) # alpha=0.7 은 녹색
plt.show()


alpha가 0.1인 적색선보다. alpha가 0.7인 녹색선이 급격한 변화에 더 민감한 것을 볼 수 있습니다.

span 인수의 사용
span은 기간을 지정하여 평활계수를 계산하는 인수입니다. 계산식은 a = 2/(span+1)으로 계산 기간이 길어질수록 a가 작아집니다.

df2 = df.assign(span_4=df['val'].ewm(span=4).mean())
df3 = df.assign(span_8=df['val'].ewm(span=8).mean())
ax = df.plot(kind='bar',x='index',y='val')
ax2= df2.plot(kind='line',x='index', y='span_4', color='red', ax=ax)
ax3= df3.plot(kind='line',x='index', y='span_8', color='green', ax=ax)
plt.show()


span이 긴 녹색이 span이 짧은 적색선보다 덜 민감하게 반응하는 것을 확인 할 수 있습니다.
span이 길면 그만큼 과거의 데이터의 영향이 커지기 때문입니다.

com 인수의 사용
com 은 질량중심 감쇠법으로 평활계수를 계산하는 인수입니다. 계산식은 a=1/(1+com)으로 com이 커질수록 a가 작아집니다.

df2 = df.assign(com_2=df['val'].ewm(com=2).mean())
df3 = df.assign(com_10=df['val'].ewm(com=10).mean())
ax = df.plot(kind='bar',x='index',y='val')
ax2= df2.plot(kind='line',x='index', y='com_2', color='red', ax=ax)
ax3= df3.plot(kind='line',x='index', y='com_10', color='green', ax=ax)
plt.show()


com이 큰 녹색이 com이 작은 적색보다 덜 민감하게 반응하는 것을 확인할 수 있습니다.
com이 클 수록 과거의 데이터의 가중치가 커지기 때문입니다.

halflife 인수의 사용
halflife인수는 반감기를 이용하여 평활계수를 계산하는 인수입니다. 계산식은 a=1-e^(-ln(2)/halflife) 으로 halflife가 길어질수록 a가 작아집니다.

df2 = df.assign(harf_2=df['val'].ewm(halflife=2).mean())
df3 = df.assign(harf_5=df['val'].ewm(halflife=5).mean())
ax = df.plot(kind='bar',x='index',y='val')
ax2= df2.plot(kind='line',x='index', y='harf_2', color='red', ax=ax)
ax3= df3.plot(kind='line',x='index', y='harf_5', color='green', ax=ax)
plt.show()


halflife 반감기가 길수록(녹색) 더욱 둔감한 그래프가 그려지는것을 확인할 수 있습니다.

adjust인수의 사용
상대적 가중치의 불균형을 해소하기위해 조정계수로 나눌지의 여부입니다. 대체로 값이 많을수록 adjust를 하는것이 유리합니다.

df2 = df.assign(adj_True=df['val'].ewm(alpha=0.2,adjust=True).mean())
df3 = df.assign(adj_False=df['val'].ewm(alpha=0.2,adjust=False).mean())
ax = df.plot(kind='bar',x='index',y='val')
ax2= df2.plot(kind='line',x='index', y='adj_True', color='red', ax=ax)
ax3= df3.plot(kind='line',x='index', y='adj_False', color='green', ax=ax)
plt.show()

ignore_na인수의 사용
ignore_na는 결측치가 존재할 경우 가중치를 어떻게 설정할지 정하는 인수 입니다.
[x0, None, x1] 일때, 인 경우 ignore_na = False 이면 절대위치를 기반으로 하며,
x0와 x2의 가중치는 adjust = [ True인경우 (1-a)^2와 1 / False인 경우 (1-a)^2와 a ] 입니다.
[x0, None, x1] 일때, 인 경우 ignore_na = False 이면 절대위치를 기반으로 하며,
x0와 x2의 가중치는 adjust = [ True인경우 (1-a)와 1 / False인 경우 (1-a)와 a ] 입니다.

df2 = df.assign(ignore_na_True=df['val'].ewm(alpha=0.2,ignore_na=True).mean())
df3 = df.assign(ignore_na_False=df['val'].ewm(alpha=0.2,ignore_na=False).mean())
ax = df.plot(kind='bar',x='index',y='val')
ax2= df2.plot(kind='line',x='index', y='ignore_na_True', color='red', ax=ax)
ax3= df3.plot(kind='line',x='index', y='ignore_na_False', color='green', ax=ax)
plt.show()


결측치가 있는 10번 data부터 ignore_na의 여부에 따라 그래프가 달라지는것을 볼 수 있습니다.

method 인수의 사용
method인수는 single인 경우 한줄씩, table인 경우 전체 테이블을 한번에 계산합니다. 데이터가 많을수록 method='table'이 속도에서 유리합니다.
사용시 추가 메서드에서 engine='numba' 형태로 설정을 해주어야 합니다.

print(df['val'].ewm(alpha=0.2, method='table').mean(engine='numba'))

profile
개발자를 꿈꾸는 학생

0개의 댓글