달나라 노트

Python Pandas : shift (행 위치 옮기기) 본문

Python/Python Pandas

Python Pandas : shift (행 위치 옮기기)

CosmosProject 2021. 9. 28. 23:08
728x90
반응형

 

 

 

 

Pandas의 shift method는 DataFrame이나 Series에 적용해서 행의 위치를 일정 칸수씩 이동시킵니다.

 

바로 예시를 통해 알아봅시다.

 

import pandas as pd

dict_test = {
    'col1': [
        1, 1, 1, 1, 1, 1,
        2, 2, 2, 2,
        3, 3, 3,
        4, 4, 4
    ],
    'col2': [
        'a', 'a', 'a', 'b', 'b', 'b',
        'a', 'a', 'b', 'b',
        'a', 'a', 'b',
        'a', 'b', 'b'
    ],
    'col3': [
        1000, 1100, 1200, 1300, 1050, 1100,
        2100, 2050, 2000, 2200,
        3000, 3100, 3200,
        4200, 4100, 4150
    ],
    'col4': [
        1, 2, 3, 4, 5, 6,
        7, 8, 9, 10,
        11, 12, 13,
        14, 15, 16
    ]
}

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

df_shifted = df_test.shift(-1)
print(df_shifted)
print(type(df_shifted))




-- Result
    col1 col2  col3  col4
0      1    a  1000     1
1      1    a  1100     2
2      1    a  1200     3
3      1    b  1300     4
4      1    b  1050     5
5      1    b  1100     6
6      2    a  2100     7
7      2    a  2050     8
8      2    b  2000     9
9      2    b  2200    10
10     3    a  3000    11
11     3    a  3100    12
12     3    b  3200    13
13     4    a  4200    14
14     4    b  4100    15
15     4    b  4150    16

    col1 col2    col3  col4
0    1.0    a  1100.0   2.0
1    1.0    a  1200.0   3.0
2    1.0    b  1300.0   4.0
3    1.0    b  1050.0   5.0
4    1.0    b  1100.0   6.0
5    2.0    a  2100.0   7.0
6    2.0    a  2050.0   8.0
7    2.0    b  2000.0   9.0
8    2.0    b  2200.0  10.0
9    3.0    a  3000.0  11.0
10   3.0    a  3100.0  12.0
11   3.0    b  3200.0  13.0
12   4.0    a  4200.0  14.0
13   4.0    b  4100.0  15.0
14   4.0    b  4150.0  16.0
15   NaN  NaN     NaN   NaN
<class 'pandas.core.frame.DataFrame'>

위 예시는 df_test라는 DataFrame을 생성한 후 이 DataFrame에 shift를 적용한 것입니다.

 

df_shifted를 보면 DataFrame의 모든 행의 값이 하나씩 위로 올라간걸 볼 수 있습니다.

 

하나씩 위로 올라간것은 shift의 인자로서 -1이 적혔기 때문이고, -1은 위쪽으로 한칸씩 옮기라는 뜻입니다.

현재 index보다 1씩 작은(-1) index의 위치로 옮기라는 것입니다.

 

그리고 index=15인 행은 다음 행이 없으니 NaN값으로 표시된 것을 알 수 있죠.

 

또한 shift가 적용된 대상이 DataFrame인 df_test이므로 return되는 데이터도 DataFrame입니다.

 

 

 

 

 

 

import pandas as pd

dict_test = {
    'col1': [
        1, 1, 1, 1, 1, 1,
        2, 2, 2, 2,
        3, 3, 3,
        4, 4, 4
    ],
    'col2': [
        'a', 'a', 'a', 'b', 'b', 'b',
        'a', 'a', 'b', 'b',
        'a', 'a', 'b',
        'a', 'b', 'b'
    ],
    'col3': [
        1000, 1100, 1200, 1300, 1050, 1100,
        2100, 2050, 2000, 2200,
        3000, 3100, 3200,
        4200, 4100, 4150
    ],
    'col4': [
        1, 2, 3, 4, 5, 6,
        7, 8, 9, 10,
        11, 12, 13,
        14, 15, 16
    ]
}

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

df_shifted = df_test.shift(1)
print(df_shifted)
print(type(df_shifted))




-- Result
    col1 col2  col3  col4
0      1    a  1000     1
1      1    a  1100     2
2      1    a  1200     3
3      1    b  1300     4
4      1    b  1050     5
5      1    b  1100     6
6      2    a  2100     7
7      2    a  2050     8
8      2    b  2000     9
9      2    b  2200    10
10     3    a  3000    11
11     3    a  3100    12
12     3    b  3200    13
13     4    a  4200    14
14     4    b  4100    15
15     4    b  4150    16

    col1 col2    col3  col4
0    NaN  NaN     NaN   NaN
1    1.0    a  1000.0   1.0
2    1.0    a  1100.0   2.0
3    1.0    a  1200.0   3.0
4    1.0    b  1300.0   4.0
5    1.0    b  1050.0   5.0
6    1.0    b  1100.0   6.0
7    2.0    a  2100.0   7.0
8    2.0    a  2050.0   8.0
9    2.0    b  2000.0   9.0
10   2.0    b  2200.0  10.0
11   3.0    a  3000.0  11.0
12   3.0    a  3100.0  12.0
13   3.0    b  3200.0  13.0
14   4.0    a  4200.0  14.0
15   4.0    b  4100.0  15.0
<class 'pandas.core.frame.DataFrame'>

반면에 shift의 인자로 1을 전달하면 모든 행의 값이 아래쪽으로 1칸씩 밀린 것을 알 수 있습니다.

 

index=0인 행은 이전 행이 없으므로 NaN으로 표시되었습니다.

 

이렇게 몇 칸을 옮기고싶은지에 대한 숫자를 shift의 인자로서 전달하면 원하는 만큼 이동이 가능합니다.

 

 

 

 

 

 

 

 

import pandas as pd

dict_test = {
    'col1': [
        1, 1, 1, 1, 1, 1,
        2, 2, 2, 2,
        3, 3, 3,
        4, 4, 4
    ],
    'col2': [
        'a', 'a', 'a', 'b', 'b', 'b',
        'a', 'a', 'b', 'b',
        'a', 'a', 'b',
        'a', 'b', 'b'
    ],
    'col3': [
        1000, 1100, 1200, 1300, 1050, 1100,
        2100, 2050, 2000, 2200,
        3000, 3100, 3200,
        4200, 4100, 4150
    ],
    'col4': [
        1, 2, 3, 4, 5, 6,
        6, 7, 8, 9,
        10, 11, 12,
        13, 14, 15
    ]
}

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

df_shifted = df_test.loc[:, 'col4'].shift(-1)
print(df_shifted)
print(type(df_shifted))




-- Result
    col1 col2  col3  col4
0      1    a  1000     1
1      1    a  1100     2
2      1    a  1200     3
3      1    b  1300     4
4      1    b  1050     5
5      1    b  1100     6
6      2    a  2100     6
7      2    a  2050     7
8      2    b  2000     8
9      2    b  2200     9
10     3    a  3000    10
11     3    a  3100    11
12     3    b  3200    12
13     4    a  4200    13
14     4    b  4100    14
15     4    b  4150    15

0      2.0
1      3.0
2      4.0
3      5.0
4      6.0
5      6.0
6      7.0
7      8.0
8      9.0
9     10.0
10    11.0
11    12.0
12    13.0
13    14.0
14    15.0
15     NaN
Name: col4, dtype: float64
<class 'pandas.core.series.Series'>

shift는 DataFrame의 하나의 행에만 적용할 수도 있습니다.

 

위 예시는 df_test의 col4에만 shift를 적용시켰습니다.

 

loc[:, 'col4']를 보면 column이름인 col4에 대괄호가 쳐져있지 않으므로 이것은 col4를 Series로 반환합니다.

 

따라서 위 예시에서 shift는 Series에 적용된 것과 같으므로 shift의 return값도 Series입니다.

 

 

 

 

 

 

 

 

import pandas as pd

dict_test = {
    'col1': [
        1, 1, 1, 1, 1, 1,
        2, 2, 2, 2,
        3, 3, 3,
        4, 4, 4
    ],
    'col2': [
        'a', 'a', 'a', 'b', 'b', 'b',
        'a', 'a', 'b', 'b',
        'a', 'a', 'b',
        'a', 'b', 'b'
    ],
    'col3': [
        1000, 1100, 1200, 1300, 1050, 1100,
        2100, 2050, 2000, 2200,
        3000, 3100, 3200,
        4200, 4100, 4150
    ],
    'col4': [
        1, 2, 3, 4, 5, 6,
        6, 7, 8, 9,
        10, 11, 12,
        13, 14, 15
    ]
}

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

df_shifted = df_test.loc[:, ['col4']].shift(-1)
print(df_shifted)
print(type(df_shifted))




-- Result
    col1 col2  col3  col4
0      1    a  1000     1
1      1    a  1100     2
2      1    a  1200     3
3      1    b  1300     4
4      1    b  1050     5
5      1    b  1100     6
6      2    a  2100     6
7      2    a  2050     7
8      2    b  2000     8
9      2    b  2200     9
10     3    a  3000    10
11     3    a  3100    11
12     3    b  3200    12
13     4    a  4200    13
14     4    b  4100    14
15     4    b  4150    15

    col4
0    2.0
1    3.0
2    4.0
3    5.0
4    6.0
5    6.0
6    7.0
7    8.0
8    9.0
9   10.0
10  11.0
11  12.0
12  13.0
13  14.0
14  15.0
15   NaN
<class 'pandas.core.frame.DataFrame'>

이번엔 loc.[:, ['col4']] 처럼 column이름에 대괄호를 쳐서 loc가 DataFrame을 return하게 했습니다.

 

따라서 여기에 적용된 shift도 DataFrame에 대해 적용되는 것이므로 shift의 return값도 DataFrame입니다.

 

shift는 자신이 적용된 대상의 data type과 동일한 data type의 결과를 return합니다.

 

 

 

 

 

 

 

 

import pandas as pd

dict_test = {
    'col1': [
        1, 1, 1, 1, 1, 1,
        2, 2, 2, 2,
        3, 3, 3,
        4, 4, 4
    ],
    'col2': [
        'a', 'a', 'a', 'b', 'b', 'b',
        'a', 'a', 'b', 'b',
        'a', 'a', 'b',
        'a', 'b', 'b'
    ],
    'col3': [
        1000, 1100, 1200, 1300, 1050, 1100,
        2100, 2050, 2000, 2200,
        3000, 3100, 3200,
        4200, 4100, 4150
    ],
    'col4': [
        1, 2, 3, 4, 5, 6,
        6, 7, 8, 9,
        10, 11, 12,
        13, 14, 15
    ]
}

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

df_group_shifted = df_test.groupby(by=['col1', 'col2'])[['col4']].shift(-1)
print(df_group_shifted)
print(type(df_group_shifted))




-- Result
    col1 col2  col3  col4
0      1    a  1000     1
1      1    a  1100     2
2      1    a  1200     3
3      1    b  1300     4
4      1    b  1050     5
5      1    b  1100     6
6      2    a  2100     6
7      2    a  2050     7
8      2    b  2000     8
9      2    b  2200     9
10     3    a  3000    10
11     3    a  3100    11
12     3    b  3200    12
13     4    a  4200    13
14     4    b  4100    14
15     4    b  4150    15

    col4
0    2.0
1    3.0
2    NaN
3    5.0
4    6.0
5    NaN
6    7.0
7    NaN
8    9.0
9    NaN
10  11.0
11   NaN
12   NaN
13   NaN
14  15.0
15   NaN
<class 'pandas.core.frame.DataFrame'>

shift는 groupby와 함께 사용될 수 있습니다.

 

위 예시를 보면 col1, col2를 기준으로 groupby를 하고 groupby된 col4에 shift를 적용합니다.

 

따라서 결과를 보면 shift가 동일한 col1, col2값을 가진 행들의 그룹 내에서 적용된 것을 볼 수 있습니다.

(index=0, 1, 2 행이 동일한 col1, col2 값을 가지고있으므로 index=0, 1, 2에 있는 col4값을 위쪽으로 한 칸씩 올린 모습을 볼 수 있습니다. index=2는 동일한 col1, col2값을 가진 다음 행이 없으므로 NaN으로 표시되는 것도 볼 수 있죠.)

 

 

 

 

 

 

 

import pandas as pd

import pandas as pd

dict_test = {
    'col1': [
        1, 1, 1, 1, 1, 1,
        2, 2, 2, 2,
        3, 3, 3,
        4, 4, 4
    ],
    'col2': [
        'a', 'a', 'a', 'b', 'b', 'b',
        'a', 'a', 'b', 'b',
        'a', 'a', 'b',
        'a', 'b', 'b'
    ],
    'col3': [
        1000, 1100, 1200, 1300, 1050, 1100,
        2100, 2050, 2000, 2200,
        3000, 3100, 3200,
        4200, 4100, 4150
    ],
    'col4': [
        1, 2, 3, 4, 5, 6,
        6, 7, 8, 9,
        10, 11, 12,
        13, 14, 15
    ]
}

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


df_test.loc[:, 'col5'] = df_test.groupby(by=['col1'])['col3'].shift(-2)
print(df_test)




-- Result
    col1 col2  col3  col4
0      1    a  1000     1
1      1    a  1100     2
2      1    a  1200     3
3      1    b  1300     4
4      1    b  1050     5
5      1    b  1100     6
6      2    a  2100     6
7      2    a  2050     7
8      2    b  2000     8
9      2    b  2200     9
10     3    a  3000    10
11     3    a  3100    11
12     3    b  3200    12
13     4    a  4200    13
14     4    b  4100    14
15     4    b  4150    15

    col1 col2  col3  col4    col5
0      1    a  1000     1  1200.0
1      1    a  1100     2  1300.0
2      1    a  1200     3  1050.0
3      1    b  1300     4  1100.0
4      1    b  1050     5     NaN
5      1    b  1100     6     NaN
6      2    a  2100     6  2000.0
7      2    a  2050     7  2200.0
8      2    b  2000     8     NaN
9      2    b  2200     9     NaN
10     3    a  3000    10  3200.0
11     3    a  3100    11     NaN
12     3    b  3200    12     NaN
13     4    a  4200    13  4150.0
14     4    b  4100    14     NaN
15     4    b  4150    15     NaN

 

위같은 방식으로 groupby와 shift로 이동된 데이터를 원본 DataFrame의 어떤 column에 할당할 수도 있습니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

import pandas as pd

dict_test = {
    'col1': [
        1, 1, 1, 1, 1, 1,
        2, 2, 2, 2,
        3, 3, 3,
        4, 4, 4
    ],
    'col2': [
        'a', 'a', 'a', 'b', 'b', 'b',
        'a', 'a', 'b', 'b',
        'a', 'a', 'b',
        'a', 'b', 'b'
    ],
    'col3': [
        1000, 1100, 1200, 1300, 1050, 1100,
        2100, 2050, 2000, 2200,
        3000, 3100, 3200,
        4200, 4100, 4150
    ],
    'col4': [
        1, 2, 3, 4, 5, 6,
        6, 7, 8, 9,
        10, 11, 12,
        13, 14, 15
    ]
}

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

df_rolling_sum_1 = df_test.groupby(by=['col1', 'col2'])[['col4']].rolling(2).apply(sum)
print(df_rolling_sum_1)
print(type(df_rolling_sum_1))

df_rolling_sum_2 = df_test.groupby(by=['col1', 'col2'])[['col4']].rolling(2).apply(sum).shift(-1)
print(df_rolling_sum_2)
print(type(df_rolling_sum_2))




-- Result
    col1 col2  col3  col4
0      1    a  1000     1
1      1    a  1100     2
2      1    a  1200     3
3      1    b  1300     4
4      1    b  1050     5
5      1    b  1100     6
6      2    a  2100     6
7      2    a  2050     7
8      2    b  2000     8
9      2    b  2200     9
10     3    a  3000    10
11     3    a  3100    11
12     3    b  3200    12
13     4    a  4200    13
14     4    b  4100    14
15     4    b  4150    15

              col4
col1 col2         
1    a    0    NaN
          1    3.0
          2    5.0
     b    3    NaN
          4    9.0
          5   11.0
2    a    6    NaN
          7   13.0
     b    8    NaN
          9   17.0
3    a    10   NaN
          11  21.0
     b    12   NaN
4    a    13   NaN
     b    14   NaN
          15  29.0
<class 'pandas.core.frame.DataFrame'>

              col4
col1 col2         
1    a    0    3.0
          1    5.0
          2    NaN
     b    3    9.0
          4   11.0
          5    NaN
2    a    6   13.0
          7    NaN
     b    8   17.0
          9    NaN
3    a    10  21.0
          11   NaN
     b    12   NaN
4    a    13   NaN
     b    14  29.0
          15   NaN
<class 'pandas.core.frame.DataFrame'>

shift는 rolling과도 같이 사용될 수 있습니다.

 

위 예시를 보면 col1, col2를 기준으로 그룹화된 DataFrame의 col4에 2개 행(현재행, 그 이전행)에 대해 rolling sum을 진행한 것이 df_rolling_sum_1이고,

 

여기에 shift를 추가로 적용한게 df_rolling_sum_2입니다.

 

이 두 결과를 비교해보면 데이터는 똑같으나 shift(-1)이 적용된 결과는 동일한 group(=동일한 col1, col2 값을 가진 행들) 내에서 col4의 rooling sum 값이 한줄씩 위로 옮겨긴걸 볼 수 있습니다.

 

 

 

 

 

 

 

 

import pandas as pd

dict_test = {
    'col1': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    'col2': ['a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'b'],
    'col3': [1000, 1200, 1100, 1050, 1300, 900, 1500, 2000, 1800, 1600]
}

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

df_rolling_sum = df_test.groupby(by=['col2'])[['col3']].rolling(2).apply(sum).shift(-1)
df_rolling_sum = df_rolling_sum.reset_index(drop=False, inplace=False)
print(df_rolling_sum)
print(type(df_rolling_sum))

df_test.loc[:, 'new_col3'] = df_rolling_sum.loc[:, 'col3']
print(df_test)
print(type(df_test))




-- Result
   col1 col2  col3
0     1    a  1000
1     2    a  1200
2     3    a  1100
3     4    a  1050
4     5    b  1300
5     6    b   900
6     7    b  1500
7     8    b  2000
8     9    b  1800
9    10    b  1600

  col2  level_1    col3
0    a        0  2200.0
1    a        1  2300.0
2    a        2  2150.0
3    a        3     NaN
4    b        4  2200.0
5    b        5  2400.0
6    b        6  3500.0
7    b        7  3800.0
8    b        8  3400.0
9    b        9     NaN
<class 'pandas.core.frame.DataFrame'>

   col1 col2  col3  new_col3
0     1    a  1000    2200.0
1     2    a  1200    2300.0
2     3    a  1100    2150.0
3     4    a  1050       NaN
4     5    b  1300    2200.0
5     6    b   900    2400.0
6     7    b  1500    3500.0
7     8    b  2000    3800.0
8     9    b  1800    3400.0
9    10    b  1600       NaN
<class 'pandas.core.frame.DataFrame'>

위 예시는 rolling sum과 shift를 적용한 결과를 df_test의 new_col3라는 새로운 컬럼에 할당하고 있는 예시입니다.

 

보시면 rolling sum + shift(-1)의 결과로 생성된 df_rolling_sum의 col3의 값이 df_test의 new_col3에 그대로 할당된것을 볼 수 있죠.

 

 

 

 

 

 

 

 

 

728x90
반응형
Comments