달나라 노트

Python Pandas : cummin, cummax (누적최소값, 누적최대값) 본문

Python/Python Pandas

Python Pandas : cummin, cummax (누적최소값, 누적최대값)

CosmosProject 2024. 8. 1. 20:10
728x90
반응형

 

 

 

cummin은 누적 최소값을 구하며

cummax는 누적 최대값을 구합니다.

 

이는 cumsum, cumprod와 매우 유사하게 작동합니다.

참고 cumsum, cumprod = https://cosmosproject.tistory.com/860

 

 

 

 

cummin부터 알아봅시다.

 

Syntax

cummin(skipna=True/False, axis=0/1)
cummax(skipna=True/False, axis=0/1)

 

- skipna

True일 경우 NaN값을 무시하고 계산합니다.

False일 경우 NaN값을 고려하고 계산합니다.

 

- axis

누적합을 구할 축을 지정합니다.

기본값은 0이며 0으로 지정해야 컬럼 기준 누적합이 됩니다.

 

 

 

 

import pandas as pd

dict_test = {
    'seq': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
    'id': [1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
    'qty': [200, 80, 150, 50, 10, 20, 180, 70, 100, 100]
}

df_test = pd.DataFrame(dict_test)
print(df_test)

df_test_temp = df_test.loc[:, 'qty'].cummin(skipna=True)
print(type(df_test_temp))
print(df_test_temp)



-- Result
   seq  id  qty
0    0   1  200
1    1   1   80
2    2   1  150
3    3   1   50
4    4   1   10
5    5   2   20
6    6   2  180
7    7   2   70
8    8   2  100
9    9   2  100


<class 'pandas.core.series.Series'>
0    200
1     80
2     80
3     50
4     10
5     10
6     10
7     10
8     10
9     10
Name: qty, dtype: int64

 

위 예시는 DataFrame의 qty 컬럼에 cummin을 적용한 결과입니다.

 

 

 

df_test_temp = df_test.loc[:, 'qty'].cummin(skipna=True)

 

cummin의 결과를 보면 200, 80, 80 등등의 값이 적힌 Series가 return되었습니다.

 

 

 

 

import pandas as pd

dict_test = {
    'seq': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
    'id': [1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
    'qty': [200, 80, 150, 50, 10, 20, 180, 70, 100, 100]
}

df_test = pd.DataFrame(dict_test)
print(df_test)

df_test_temp = df_test.loc[:, 'qty'].cummin(skipna=True)
print(type(df_test_temp))
print(df_test_temp)

df_test.loc[:, 'qty_cummin'] = df_test.loc[:, 'qty'].cummin(skipna=True)
print(df_test)



-- Result
   seq  id  qty
0    0   1  200
1    1   1   80
2    2   1  150
3    3   1   50
4    4   1   10
5    5   2   20
6    6   2  180
7    7   2   70
8    8   2  100
9    9   2  100


<class 'pandas.core.series.Series'>
0    200
1     80
2     80
3     50
4     10
5     10
6     10
7     10
8     10
9     10
Name: qty, dtype: int64


   seq  id  qty  qty_cummin
0    0   1  200         200
1    1   1   80          80
2    2   1  150          80
3    3   1   50          50
4    4   1   10          10
5    5   2   20          10
6    6   2  180          10
7    7   2   70          10
8    8   2  100          10
9    9   2  100          10

 

cummin의 결과를 좀 더 보기 쉽게 하기 위해 df_test의 qty_cummin 컬럼에 삽입했습니다.

 

 

 

 

 

   seq  id  qty  qty_cummin
0    0   1  200         200
1    1   1   80          80
2    2   1  150          80
3    3   1   50          50
4    4   1   10          10
5    5   2   20          10
6    6   2  180          10
7    7   2   70          10
8    8   2  100          10
9    9   2  100          10

 

이 결과를 보면 cummin의 기능을 알 수 있습니다.

qty 컬럼을 첫 행부터 읽어내고 첫행부터 현재 행까지의 값 중 최소값을 return하는 것입니다.

 

그래서 1행은 200이고

2행은 200, 80 중 최소값 = 80

3행은 200, 80, 150 중 최소값 = 80

4행은 200, 80, 150, 50 중 최소값 = 50

이런 식으로 계산이 되는 것입니다.

 

 

cummin은 이렇게 첫 행부터 순차적으로 더하기 때문에 순서가 중요합니다.

 

import pandas as pd

dict_test = {
    'seq': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
    'id': [1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
    'qty': [200, 80, 150, 50, 10, 20, 180, 70, 100, 100]
}

df_test = pd.DataFrame(dict_test)
df_test = df_test.sort_values(by=['seq'], ascending=False, inplace=False)
print(df_test)

df_test.loc[:, 'qty_cummin'] = df_test.loc[:, 'qty'].cummin(skipna=True)
print(df_test)



-- Result
   seq  id  qty
9    9   2  100
8    8   2  100
7    7   2   70
6    6   2  180
5    5   2   20
4    4   1   10
3    3   1   50
2    2   1  150
1    1   1   80
0    0   1  200


   seq  id  qty  qty_cummin
9    9   2  100         100
8    8   2  100         100
7    7   2   70          70
6    6   2  180          70
5    5   2   20          20
4    4   1   10          10
3    3   1   50          10
2    2   1  150          10
1    1   1   80          10
0    0   1  200          10

 

위 예시는 DataFrame의 값을 seq 컬럼을 기준으로 내림차순하여 cummin을 적용한 예시인데

cummin의 결과를 보면 그 값이 마찬가지로 DataFrame의 첫 행부터 고려하여 최소값을 return한다는 것을 알 수 있습니다.

 

 

 

 

 

cummax도 마찬가지입니다.

 

import pandas as pd

dict_test = {
    'seq': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
    'id': [1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
    'qty': [200, 80, 150, 50, 10, 20, 180, 70, 100, 100]
}

df_test = pd.DataFrame(dict_test)
print(df_test)

df_test_temp = df_test.loc[:, 'qty'].cummax(skipna=True)
print(type(df_test_temp))
print(df_test_temp)

df_test.loc[:, 'qty_cummax'] = df_test.loc[:, 'qty'].cummax(skipna=True)
print(df_test)



-- Result
   seq  id  qty
0    0   1  200
1    1   1   80
2    2   1  150
3    3   1   50
4    4   1   10
5    5   2   20
6    6   2  180
7    7   2   70
8    8   2  100
9    9   2  100


<class 'pandas.core.series.Series'>
0    200
1    200
2    200
3    200
4    200
5    200
6    200
7    200
8    200
9    200
Name: qty, dtype: int64


   seq  id  qty   qty_cummax
0    0   1  200          200
1    1   1   80          200
2    2   1  150          200
3    3   1   50          200
4    4   1   10          200
5    5   2   20          200
6    6   2  180          200
7    7   2   70          200
8    8   2  100          200
9    9   2  100          200

 

결과를 보면

1행은 200 중 최대값 = 200

2행은 200, 80 중 최대값 = 200

3행은 200, 80, 150 중 최대값 = 200

4행은 200, 80, 150, 50 중 최대값 = 200

이런식으로 계산이 되는 것이죠.

 

 

 

 

import pandas as pd

dict_test = {
    'seq': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
    'id': [1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
    'qty': [200, 80, None, 50, 10, 20, None, 70, 100, 100]
}

df_test = pd.DataFrame(dict_test)
print(df_test)

df_test.loc[:, 'qty_cummin'] = df_test.loc[:, 'qty'].cummin(skipna=True)
print(df_test)




-- Result
   seq  id    qty
0    0   1  200.0
1    1   1   80.0
2    2   1    NaN
3    3   1   50.0
4    4   1   10.0
5    5   2   20.0
6    6   2    NaN
7    7   2   70.0
8    8   2  100.0
9    9   2  100.0


   seq  id    qty  qty_cummin
0    0   1  200.0       200.0
1    1   1   80.0        80.0
2    2   1    NaN         NaN
3    3   1   50.0        50.0
4    4   1   10.0        10.0
5    5   2   20.0        10.0
6    6   2    NaN         NaN
7    7   2   70.0        10.0
8    8   2  100.0        10.0
9    9   2  100.0        10.0

 

이번에는 qty 컬럼에 NaN값을 넣어봤습니다.

 

 

   seq  id    qty  qty_cummin
0    0   1  200.0       200.0
1    1   1   80.0        80.0
2    2   1    NaN         NaN
3    3   1   50.0        50.0
4    4   1   10.0        10.0
5    5   2   20.0        10.0
6    6   2    NaN         NaN
7    7   2   70.0        10.0
8    8   2  100.0        10.0
9    9   2  100.0        10.0

 

결과를 보면 위와 같습니다.

 

1행은 200 중 최소값 = 200

2행은 200, 80 중 최소값 = 80

여기까진 동일합니다.

 

근데

3행은 200, 80, NaN이 됩니다. 이 경우 skipna=True로 지정되어있으나 3행은 그 자체의 값이 NaN이므로 NaN이 return됩니다.

4행도 특이한데

4행은 200, 80, NaN, 50 중 최소값 = 50이 됩니다.

 

여기서 skipna=True의 진짜 의미를 알 수 있는데

고려할 값 중에 NaN이 있으면 이것은 그냥 없는 셈 쳐서 skip하라는 것이 skipna=True의 의미입니다.

다만 해당 행이 NaN이라면 NaN을 return한다는 예외가 있죠.

 

 

 

 

import pandas as pd

dict_test = {
    'seq': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
    'id': [1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
    'qty': [200, 80, None, 50, 10, 20, None, 70, 100, 100]
}

df_test = pd.DataFrame(dict_test)
print(df_test)

df_test.loc[:, 'qty_cummin'] = df_test.loc[:, 'qty'].cummin(skipna=False)
print(df_test)



-- Result
   seq  id    qty
0    0   1  200.0
1    1   1   80.0
2    2   1    NaN
3    3   1   50.0
4    4   1   10.0
5    5   2   20.0
6    6   2    NaN
7    7   2   70.0
8    8   2  100.0
9    9   2  100.0


   seq  id    qty  qty_cummin
0    0   1  200.0       200.0
1    1   1   80.0        80.0
2    2   1    NaN         NaN
3    3   1   50.0         NaN
4    4   1   10.0         NaN
5    5   2   20.0         NaN
6    6   2    NaN         NaN
7    7   2   70.0         NaN
8    8   2  100.0         NaN
9    9   2  100.0         NaN

 

skipna=False 예시입니다.

1행 -> 200 중 최소값 = 200

2행 -> 200, 80 중 최소값 = 80

3행 -> 200, 80, NaN 중 최소값이나 3행 자체가 NaN이므로 = NaN

여기까진 동일합니다.

 

근데 보면 4행부터 결과가 모두 NaN으로 찍혀있습니다.

그 이유는 skipna=False로 지정하였기 때문에 고려할 값 중 NaN이 있으면 이를 skip하지 못하고 고려하게 되어 모두 NaN이 return되는 것입니다.

 

이는 cummin 뿐 아니라 cummax에도 동일하게 적용됩니다.

 

 

 

 

cummin, cummax 또한 groupby와 함께 사용할 수 있습니다.

 

 

import pandas as pd

dict_test = {
    'seq': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
    'id': [1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
    'qty': [200, 80, 150, 50, 10, 20, 180, 70, 100, 100]
}

df_test = pd.DataFrame(dict_test)
print(df_test)

df_test_cummin_with_groupby = df_test.groupby(by=['id'])[['qty']].apply(lambda df: df.cummin(skipna=True))
print(df_test_cummin_with_groupby)

df_test_cummin_with_groupby = df_test_cummin_with_groupby.reset_index(drop=False, inplace=False)
print(df_test_cummin_with_groupby)

df_test.loc[:, 'qty_cummin_groupby'] = df_test_cummin_with_groupby.loc[:, 'qty']
print(df_test)




-- Result
   seq  id  qty
0    0   1  200
1    1   1   80
2    2   1  150
3    3   1   50
4    4   1   10
5    5   2   20
6    6   2  180
7    7   2   70
8    8   2  100
9    9   2  100


      qty
id       
1  0  200
   1   80
   2   80
   3   50
   4   10
2  5   20
   6   20
   7   20
   8   20
   9   20


   id  level_1  qty
0   1        0  200
1   1        1   80
2   1        2   80
3   1        3   50
4   1        4   10
5   2        5   20
6   2        6   20
7   2        7   20
8   2        8   20
9   2        9   20


   seq  id  qty  qty_cummin_groupby
0    0   1  200                 200
1    1   1   80                  80
2    2   1  150                  80
3    3   1   50                  50
4    4   1   10                  10
5    5   2   20                  20
6    6   2  180                  20
7    7   2   70                  20
8    8   2  100                  20
9    9   2  100                  20

 

groupby와 cummin을 동시에 사용한 예시입니다.

 

 

df_test.groupby(by=['id'])[['qty']].apply(lambda df: df.cummin(skipna=True))

 

위 예시에서 보면 groupby의 lambda에 cummin을 적용하여 groupby 별 cummin을 적용하였습니다.

즉, id 컬럼의 값을 기준으로 동일한 id 값을 가진 행들의 qty에 대해서 cummin이 적용됩니다.

 

 

   seq  id  qty  qty_cummin_groupby
0    0   1  200                 200
1    1   1   80                  80
2    2   1  150                  80
3    3   1   50                  50
4    4   1   10                  10
5    5   2   20                  20
6    6   2  180                  20
7    7   2   70                  20
8    8   2  100                  20
9    9   2  100                  20

 

그래서 결과를 보면 id = 1인 행들에 대해서

id = 1의 1행 -> 200 중 최소값 = 200

id = 1의 2행 -> 200, 80 중 최소값 = 80

id = 1의 3행 -> 200, 80, 150 중 최소값 = 80

id = 1의 4행 -> 200, 80, 150, 50 중 최소값 = 50

id = 1의 5행 -> 200, 80, 150, 50, 10 중 최소값 = 10

 

id = 2의 1행 -> 20 중 최소값 = 20

id = 2의 2행 -> 20, 180 중 최소값 = 200

id = 2의 3행 -> 20, 180, 70 중 최소값 = 200

id = 2의 4행 -> 20, 180, 70, 100 중 최소값 = 200

id = 2의 5행 -> 20, 180, 70, 100, 100 중 최소값 = 200

 

이렇게 계산이 됩니다.

 

 

 

 

 

728x90
반응형
Comments