Python 공부 기록-12

김시헌·2025년 4월 8일

반올림 (round)

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

사용법

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

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

코드

import numpy as np
import pandas as pd

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)

실행 결과
col1 col2 col3
row1 60.081379 47.726367 86.684306
row2 50.503265 24.890108 80.668587
row3 88.580469 56.231781 9.048607

decimals = 0인 경우

0은 기본값으로 일의자리 까지 반올림을 하게 됩니다.
코드

print(df.round(0))

실행 결과
col1 col2 col3
row1 67.0 19.0 77.0
row2 7.0 98.0 72.0
row3 25.0 80.0 9.0

decimals > 0인 경우

양수인 경우 소수 n번째 자리 까지 반올림을 합니다.
코드

print(df.round(1))

실행 결과
col1 col2 col3
row1 66.6 18.6 77.2
row2 6.9 98.1 71.8
row3 25.0 79.8 9.4

코드

print(df.round(2))

실행 결과
col1 col2 col3
row1 66.58 18.55 77.20
row2 6.90 98.05 71.79
row3 24.96 79.81 9.45

decimals < 0인 경우

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

print(df.round(-1))

실행 결과
col1 col2 col3
row1 70.0 20.0 80.0
row2 10.0 100.0 70.0
row3 20.0 80.0 10.0

합계 (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 : 계산에 필요한 숫자의 최소 갯수입니다.

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)

실행 결과
col1 col2 col3
row1 1 2.0 3
row2 4 5.0 6
row3 7 NaN 9

axis를 설정하여 더하기 수행

0은 열의 요소들의 합, 1은 행의 요소들의 합 입니다
코드

print(df.sum(axis=0))

실행 결과
col1 12.0
col2 7.0
col3 18.0
dtype: float64

코드

print(df.sum(axis=1))

실행 결과
row1 6.0
row2 15.0
row3 16.0
dtype: float64

skipna를 변경하여 계산하기

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

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

실행 결과
col1 12.0
col2 NaN
col3 18.0
dtype: float64

min_count를 변경하여 계산하기

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

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

실행 결과
row1 6.0
row2 15.0
row3 NaN
dtype: float64

곱 (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)

실행 결과
col1 col2 col3
row1 1 2.0 3
row2 4 5.0 6
row3 7 NaN 9

axis를 설정하여 곱하기 수행

0은 열의 요소들의 곱, 1은 행의 요소들의 곱 입니다.

코드

print(df.prod(axis=0))

실행 결과
col1 28.0
col2 10.0
col3 162.0
dtype: float64

코드

print(df.prod(axis=1))

실행 결과
row1 6.0
row2 120.0
row3 63.0
dtype: float64

skipna를 변경하여 계산하기

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

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

실행 결과
col1 28.0
col2 NaN
col3 162.0
dtype: float64

min_count를 변경하여 계산하기

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

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

실행 결과
row1 6.0
row2 120.0
row3 NaN
dtype: float64

절대값 (abs)

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

사용법

df.abs( )
숫자의 경우 절댓값을 반환하며, 복소수의 경우 복소수의 크기가 반환됩니다.
※ 복소수가 a+bj인 경우 복소수의크기

NaN의 경우는 NaN을 그대로 출력합니다.

NaN과 복소수가 포함된 3x3 객체를 하나 생성하겠습니다.

코드

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)

실행 결과
col1 col2 col3
row1 -1 2.0 -3.5+0.0j
row2 4 -5.5 3.0+4.0j
row3 7 NaN 0.0+0.0j

abs 메서드 실행

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

print(df.abs( ))

실행 결과
col1 col2 col3
row1 1 2.0 3.5
row2 4 5.5 5.0
row3 7 NaN 0.0

전치 (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)

실행 결과
col1 col2 col3
row1 A 1 2
row2 B 3 4
row3 C 5 6
row4 D 7 8

transpose 메서드 실행

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

print(df.transpose())

실행 결과
row1 row2 row3 row4
col1 A B C D
col2 1 3 5 7
col3 2 4 6 8

순위 (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)
df

실행 결과

기본적인 사용법

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

print(df.diff(axis=0))

실행 결과

axis=1인 경우 열 - 바로전 열의 값을 출력합니다. 비교할 값이 없다면 NaN을 출력합니다.

코드

print(df.diff(axis=1))

실행 결과

col1은 뺄 이전 열이 없으므로 NaN출력
col2 의 값은 기존 data의 col2 - col1
col3 의 값은 기존 data의 col3 - col2

periods의 사용

periods의 경우 기본값은 +1로 +1인 경우 바로 이전 값과의 차를 출력합니다.
+3인 경우 3칸 이전 값과 비교하고 -2인 경우 2칸 후의 값과 비교하게 됩니다.
코드

print(df.diff(periods=3))

실행 결과

코드

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하였습니다.
코드

import numba
...
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 크기 만큼의 계산을 수행합니다.
코드

print(df.col1.rolling(window=3).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메서드를 이용해 여러 연산을 수행할 경우 MultiColumns 형태로 출력됩니다.

코드

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

실행 결과

group_keys 인수의 사용

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

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

출력 코드

print(df.groupby('index').apply(top))

실행 결과

observed 인수의 사용

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

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 객체를 생성해보겠습니다.
코드

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)

실행 결과

level을 int로 지정해주는 경우

코드

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

실행 결과

level을 str로 지정해주는경우 + (여러개 지정시 순차적으로 groupby 됩니다.)

코드

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)

실행 결과

그래프


막대그래프로 표현하면 위와 같습니다. 이해를 보다 쉽게 하기 위해 그래프로 표현하겠습니다.
그래프 출력에 대한 자세한 내용은 plot항목을 참고 바랍니다.

기본적인 사용법

기본적으로는 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의 여부에 따라 그래프가 달라지는것을 볼 수 있습니다.

0개의 댓글