일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- PostgreSQL
- GIT
- google apps script
- c#
- Excel
- gas
- math
- string
- django
- PySpark
- array
- Kotlin
- Apache
- Google Spreadsheet
- list
- Python
- dataframe
- matplotlib
- Google Excel
- PANDAS
- SQL
- hive
- Github
- Java
- Redshift
- 파이썬
- numpy
- Mac
- Tkinter
- Today
- Total
달나라 노트
Python Pandas : rolling (DataFrame window function) 본문
Python Pandas : rolling (DataFrame window function)
CosmosProject 2021. 1. 22. 16:46
Pandas에서 사용할 수 있는 window function 기능을 알아봅시다.
import pandas as pd
dict_test = {
'col1': [1, 1, 2, 2, 3, 3, 3, 4],
'col2': [1000, 1100, 2100, 2050, 3000, 3100, 3200, 4200],
'col3': ['a', 'b', 'a', 'c', 'a', 'a', 'd', 'e']
}
df_test = pd.DataFrame(dict_test)
# print(df_test)
# print(type(df_test))
- Output
col1 col2 col3
0 1 1000 a
1 1 1100 b
2 2 2100 a
3 2 2050 c
4 3 3000 a
5 3 3100 a
6 3 3200 d
7 4 4200 e
<class 'pandas.core.frame.DataFrame'>
d먼저 위처럼 Test용 DataFrame을 만듭시다.
df_test = pd.DataFrame(dict_test)
df_test['rolling_col'] = df_test.loc[:, ['col2']].rolling(3).sum()
print(df_test)
- Output
col1 col2 col3 rolling_col
0 1 1000 a NaN
1 1 1100 b NaN
2 2 2100 a 4200.0
3 2 2050 c 5250.0
4 3 3000 a 7150.0
5 3 3100 a 8150.0
6 3 3200 d 9300.0
7 4 4200 e 10500.0
위 코드는 col2를 기준으로 rolling sum을 하고있습니다.
코드를 부분부분 나눠서 파악해봅시다.
df_test.loc[:, ['col2']] -> rolling sum을 적용시킬 컬럼을 loc를 이용하여 추출합니다.
rolling(3) -> rolling을 적용시킵니다. rolling은 sum, mean 등의 함수를 함께 적용하는데 이때 어떤 데이터를 참조할지를 알려줘야 합니다. 예를들어서 rolling(3)이면 현재 행과 이전 2개 행을 참조합니다. 즉 총 3개의 행을 참조하는것이죠. 이건 예시를 보면서 이해해봅시다.
sum() -> rolling의 결과로 sum을 적용합니다.(mean은 평균입니다.)
위 예시의 Output을 봅시다.
rolling sum이 적용되는 컬럼은 col2입니다. col2의 숫자들을 참조해서 sum을 적용한 후 결과값이 rolling_col에 추가되었습니다.
row_index = 0인 rolling_col 값을 봅시다.
NaN으로 나와있죠. 그 사유는 rolling의 인자를 3(rolling(3))으로 지정했기 때문입니다.
col2 | rolling_col | |
-2 | None | |
-1 | None | |
0 | 1000 | NaN |
1 | 1100 |
위 표를 봐봅시다.
rolling_col의 row_index = 0인 위치에 들어갈 값은 위 표에서 색칠된 3가지의 데이터를 참조하여 더합니다. 왜냐면 rolling(3).sum()으로 sum함수가 사용되었기 때문입니다.
즉, 현재 행(row_index = 0)과 그 이전 2개 행을 참조하여 총 3개의 행의 col2 컬럼 값을 참조해서 더하는거죠.
그러나 row_index = -1 또는 row_index = -2인 데이터는 없죠. 따라서 None + None + 1000 = NaN이라는 결과가 나오는겁니다.
row_index = 1인 rolling_col 값을 봅시다.
NaN으로 나와있죠. 그 사유는 마찬가지로 rolling의 인자를 3(rolling(3))으로 지정했기 때문입니다.
col2 | rolling_col | |
-1 | None | |
0 | 1000 | NaN |
1 | 1100 | NaN |
위 표를 봐봅시다.
rolling_col의 row_index = 1인 위치에 들어갈 값은 위 표에서 색칠된 3가지의 데이터를 참조합니다.
즉, 현재 행(row_index = 1)과 그 이전 2개 행을 참조하여 총 3개의 행을 참조하는거죠.
그러나 row_index = -1인 데이터는 없죠. 따라서 None + 1000 + 1100 = NaN이라는 결과가 나오는겁니다.
row_index = 2인 rolling_col 값을 봅시다.
col2 | rolling_col | |
0 | 1000 | NaN |
1 | 1100 | NaN |
2 | 2100 | 4200 |
rolling_col의 row_index = 2인 위치에 들어갈 값은 위 표에서 색칠된 3가지의 데이터를 참조합니다.
즉, 현재 행(row_index = 2)과 그 이전 2개 행을 참조하여 총 3개의 행을 참조하는거죠.
따라서 1000 + 1100 + 2100 = 4200이라는 결과가 나오는겁니다.
row_index = 3인 rolling_col 값을 봅시다.
col2 | rolling_col | |
0 | 1000 | NaN |
1 | 1100 | NaN |
2 | 2100 | 4200 |
3 | 2050 | 5250 |
rolling_col의 row_index = 3인 위치에 들어갈 값은 위 표에서 색칠된 3가지의 데이터를 참조합니다.
즉, 현재 행(row_index = 3)과 그 이전 2개 행을 참조하여 총 3개의 행을 참조하는거죠.
따라서 1100 + 2100 + 2050 = 5250이라는 결과가 나오는겁니다.
그 다음 행들도 다 이런 방식입니다.
이제 코드를 약간 바꿔봅시다.
df_test = pd.DataFrame(dict_test)
df_test['rolling_col'] = df_test.loc[:, ['col2']].rolling(3, min_periods=1).sum()
print(df_test)
- Output
col1 col2 col3 rolling_col
0 1 1000 a 1000.0
1 1 1100 b 2100.0
2 2 2100 a 4200.0
3 2 2050 c 5250.0
4 3 3000 a 7150.0
5 3 3100 a 8150.0
6 3 3200 d 9300.0
7 4 4200 e 10500.0
코드는 전체적으로 비슷한데 min_periods라는 인자가 rolling함수에 추가되었습니다.
그리고 Output을 보면 이전 예시에 있었던 NaN값이 모두 사라졌죠?
이것은 min_periods = 1이라는 인자를 넣었기 때문입니다.
row_index = 0인 rolling_col 값을 봅시다.
col2 | rolling_col | |
-2 | None | |
-1 | None | |
0 | 1000 | 1000 |
1 | 1100 |
rolling_col의 row_index = 0인 위치에 들어갈 값은 위 표에서 색칠된 3가지의 데이터를 참조하는건 위에서 봤던것과 동일합니다.
따라서 원래대로라면 None + None + 1000 = NaN이 되어야하지만, min_periods를 1로 지정했습니다.
즉, rolling(3)에 의해 rolling 시 참조할 행은 3개지만, 위처럼 존재하지 않는 행을 참조해야할 땐 최소 1개의 행만을 참조하여 결과를 반환합니다.
따라서 존재하지 않는 row_index = -1, -2인 행은 무시하고 row_index = 0인 데이터만 참조하게 되는것이죠.
df_test = pd.DataFrame(dict_test)
df_test['rolling_col'] = df_test.loc[:, ['col2']].rolling(3, min_periods=2).sum()
print(df_test)
- Output
col1 col2 col3 rolling_col
0 1 1000 a NaN
1 1 1100 b 2100.0
2 2 2100 a 4200.0
3 2 2050 c 5250.0
4 3 3000 a 7150.0
5 3 3100 a 8150.0
6 3 3200 d 9300.0
7 4 4200 e 10500.0
min_periods=2로 설정하였습니다.
row_index = 0인 rolling_col 값을 봅시다.
col2 | rolling_col | |
-2 | None | |
-1 | None | |
0 | 1000 | 1000 |
1 | 1100 |
row_index=0의 rolling은 위처럼 3개의 행을 참조해야합니다.
그러나 2개의 행이 존재하지 않는 행이죠.
따라서 min_periods=2로 설정되어있으니 3개를 모두 참조할 필요가 없고, 참조할 행이 없으면 2개까지만 참조해도 됩니다.
그러면 위 예시에서 row_index=0의 rolling은 row_index=0, -1 의 행을 참조할 것입니다.
그러면 None + 1000 = NaN이 되죠.
반면에 row_index = 1인 rolling_col 값을 봅시다.
col2 | rolling_col | |
-1 | None | |
0 | 1000 | NaN |
1 | 1100 | 2100 |
row_index=1의 rolling은 위처럼 3개의 행을 참조해야합니다.
그러나 참조해야 할 3개의 행 중 1개의 행(row_index = -1)이 존재하지 않는 행이죠.
min_periods=2로 설정되어있으니 3개를 모두 참조할 필요가 없고, 참조할 행이 없으면 2개까지만 참조해도 됩니다.
그러면 위 예시에서 row_index=1의 rolling은 row_index=1, 0 의 행을 참조할 것입니다.
그러면 1000 + 1100 = 2100이 되죠.
또 한 가지 옵션을 추가해봅시다.
df_test = pd.DataFrame(dict_test)
df_test['rolling_col'] = df_test.loc[:, ['col2']].rolling(3, min_periods=2).sum().shift(-2)
print(df_test)
- Output
col1 col2 col3 rolling_col
0 1 1000 a 4200.0
1 1 1100 b 5250.0
2 2 2100 a 7150.0
3 2 2050 c 8150.0
4 3 3000 a 9300.0
5 3 3100 a 10500.0
6 3 3200 d NaN
7 4 4200 e NaN
이전에 봤던 예시와 동일합니다.
그러나 맨 끝에 shift(-2)라는 옵션이 추가되었습니다.
이 말은 rolling sum의 결과를 위로 2개씩 당기라는 것입니다.
이전 예시와 비교해보면 rolling_col에 10500이라는 숫자는 분명히 row_index=7인 곳에 존재했었습니다.
그러나 위 예시에서는 shift(-2)에 의해 10500이라는 숫자가 row_index=5인 곳으로 이동되었습니다.
또한 기존에 row_index = 8, 9인 데이터가 없어 shift에 의해 row_index = 6, 7로 이동될 데이터가 없습니다.
따라서 row_index = 6, 7의 rolling_sum 데이터는 NaN으로 나타내어집니다.
shift에 양수를 넣을 수도 있습니다.
df_test = pd.DataFrame(dict_test)
df_test['rolling_col'] = df_test.loc[:, ['col2']].rolling(3, min_periods=2).sum().shift(2)
print(df_test)
- Output
col1 col2 col3 rolling_col
0 1 1000 a NaN
1 1 1100 b NaN
2 2 2100 a 1000.0
3 2 2050 c 2100.0
4 3 3000 a 4200.0
5 3 3100 a 5250.0
6 3 3200 d 7150.0
7 4 4200 e 8150.0
shift에 양수를 입력하면 기존의 데이터들을 기존의 index에 +2를 한 위치로 이동시킵니다.
아래로 모두 두칸씩 이동되는거죠.
이번에는 숫자의 합이나 평균이 아니라 문자를 합쳐봅시다.
import pandas as pd
dict_test = {
'col1': [1, 1, 2, 2, 3, 3, 3, 4],
'col2': [1000, 1100, 2100, 2050, 3000, 3100, 3200, 4200],
'col3': ['a', 'b', 'a', 'c', 'a', 'a', 'd', 'e']
}
df_test = pd.DataFrame(dict_test)
# print(df_test)
# print(type(df_test))
- Output
col1 col2 col3
0 1 1000 a
1 1 1100 b
2 2 2100 a
3 2 2050 c
4 3 3000 a
5 3 3100 a
6 3 3200 d
7 4 4200 e
<class 'pandas.core.frame.DataFrame'>
동일한 예시 DataFrame을 사용해봅시다.
위 DataFrame을 보면 col1에는 중복된 숫자들이 있습니다.
그리고 col3에는 알파벳이 적혀있구요.
여기서 만약 col1에 있는 동일한 값끼리 묶은 다음 col3에 있는 문자들을 list의 형태로 연결하고싶으면 어떻게해야할까요?
아래 예시를 봅시다.
df_test = pd.DataFrame(dict_test)
df_test = df_test.groupby(by=['col1'])['col3'].apply(list)
print(df_test)
print(type(df_test))
- Output
col1
1 [a, b]
2 [a, c]
3 [a, a, d]
4 [e]
Name: col3, dtype: object
<class 'pandas.core.series.Series'>
df_test에서 col1 기준으로 groupby를 한 후,
groupby된 상태의 col3에다가 list를 적용하였습니다.
따라서 결과는 col1별로 col3의 데이터가 list의 형태로 묶여진 Series가 반환되었습니다.
이것을 DataFrame으로 다시 변경하고싶으면 아래 예시처럼 reset_index를 사용하면 됩니다.
df_test = pd.DataFrame(df_test)
df_test.reset_index(drop=False, inplace=True)
print(df_test)
print(type(df_test))
- Output
col1 col3
0 1 [a, b]
1 2 [a, c]
2 3 [a, a, d]
3 4 [e]
<class 'pandas.core.frame.DataFrame'>
'Python > Python Pandas' 카테고리의 다른 글
Python Pandas : dropna (NaN value가 있는 row/column 제거하기) (0) | 2021.06.08 |
---|---|
Python Pandas : notna (누락값 여부 체크하기) (0) | 2021.03.18 |
Python Pandas : fillna (DataFrame에서 NaN값을 replace 하기) (0) | 2021.01.20 |
Python Pandas : to_clipboard (DataFrame 복사하기) (0) | 2021.01.12 |
Python Pandas : isin (각각의 요소가 DataFrame 또는 Series에 존재하는지 파악) (0) | 2021.01.07 |