본문 바로가기
개발/Python

shift, rolling

by 피로물든딸기 2025. 10. 26.
반응형

전체 링크

 

shift() - 행을 "밀기"

- 이전 / 다음 행의 값을 참조할 때 사용

 

예제 - 다음 행과의 날짜 차이 구하기

import pandas as pd

# 예시 데이터 생성
data = {
    'date_str': ['2025-10-10', '2025-10-12', '2025-10-15', '2025-10-20']
}

df = pd.DataFrame(data)

# datetime 타입으로 변환
df['date'] = pd.to_datetime(df['date_str'])

# 다음 행과의 day 차이 계산
df['day_diff'] = df['date'] - df['date'].shift(1)
df['day_diff'] = df['day_diff'].dt.days  # timedelta를 일(day)로 변환

df

 

참고 - 뒤집기

df[::-1]


rolling() - 일정 구간 "창(window)"을 만들어 계산

- 이전 n개 구간의 평균, 합계, 표준편차 등 통계량을 구할 때 사용

 

custom 함수 사용 예시

- raw=True : numpy array로 전달 → 대부분 함수 작성이 편함

- raw=False : pandas Series로 전달 → index, name 사용 가능

import pandas as pd
import numpy as np

data = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9])

def my_func(x):    
    return np.sum(x)

# rolling 적용 후 함수 사용
result = data.rolling(window=3).apply(my_func, raw=True)
result


예제 1

 

- 이전 5개의 구간의 평균, 합계, 표준편차

import pandas as pd
import numpy as np

# 예시 데이터 생성
np.random.seed(42)
data = np.random.randint(1, 100, size=15)  # 1~100 사이 랜덤 정수 15개
dates = pd.date_range(start='2025-10-01', periods=15, freq='D')  # 하루 단위 날짜

df = pd.DataFrame({
    'date': dates,
    'value': data
})

# 이전 5개 구간에 대한 rolling 통계
df['rolling_mean'] = df['value'].rolling(window=5).mean()   # 평균
df['rolling_sum'] = df['value'].rolling(window=5).sum()     # 합계
df['rolling_std'] = df['value'].rolling(window=5).std()     # 표준편차

df


예제 2

 

- 이전 시간 (초, 분, 시) 

- datetime을 인덱스로 설정

import pandas as pd
import numpy as np

np.random.seed(42)

# 1) 초 단위 데이터 (1초 간격, 20개)
dates_sec = pd.date_range(start='2025-10-26 10:00:00', periods=20, freq='S')
values_sec = np.random.randint(1, 100, size=20)
df_sec = pd.DataFrame({'datetime': dates_sec, 'value': values_sec})
df_sec.set_index('datetime', inplace=True)
df_sec['mean_5s'] = df_sec['value'].rolling('5S').mean()
df_sec['sum_5s'] = df_sec['value'].rolling('5S').sum()
df_sec['std_5s'] = df_sec['value'].rolling('5S').std()

# 2) 분 단위 데이터 (1분 간격, 20개)
dates_min = pd.date_range(start='2025-10-26 10:00:00', periods=20, freq='T')
values_min = np.random.randint(1, 100, size=20)
df_min = pd.DataFrame({'datetime': dates_min, 'value': values_min})
df_min.set_index('datetime', inplace=True)
df_min['mean_5min'] = df_min['value'].rolling('5T').mean()
df_min['sum_5min'] = df_min['value'].rolling('5T').sum()
df_min['std_5min'] = df_min['value'].rolling('5T').std()

# 3) 시간 단위 데이터 (1시간 간격, 20개)
dates_hour = pd.date_range(start='2025-10-26 00:00:00', periods=20, freq='H')
values_hour = np.random.randint(1, 100, size=20)
df_hour = pd.DataFrame({'datetime': dates_hour, 'value': values_hour})
df_hour.set_index('datetime', inplace=True)
df_hour['mean_1h'] = df_hour['value'].rolling('1H').mean()
df_hour['sum_1h'] = df_hour['value'].rolling('1H').sum()
df_hour['std_1h'] = df_hour['value'].rolling('1H').std()

# 출력 확인
print("=== 초 단위 rolling ===")
print(df_sec)
print("\n=== 분 단위 rolling ===")
print(df_min)
print("\n=== 시간 단위 rolling ===")
print(df_hour)

 

=== 초 단위 rolling ===
                     value    mean_5s  sum_5s     std_5s
datetime                                                
2025-10-26 10:00:00     52  52.000000    52.0        NaN
2025-10-26 10:00:01     93  72.500000   145.0  28.991378
2025-10-26 10:00:02     15  53.333333   160.0  39.017090
2025-10-26 10:00:03     72  58.000000   232.0  33.196385
2025-10-26 10:00:04     61  58.600000   293.0  28.780202
2025-10-26 10:00:05     21  52.400000   262.0  33.508208
2025-10-26 10:00:06     83  50.400000   252.0  30.656158
2025-10-26 10:00:07     87  64.800000   324.0  26.499057
2025-10-26 10:00:08     75  65.400000   327.0  26.735744
2025-10-26 10:00:09     75  68.200000   341.0  26.892378
2025-10-26 10:00:10     88  81.600000   408.0   6.308724
2025-10-26 10:00:11     24  69.800000   349.0  26.357162
2025-10-26 10:00:12      3  53.000000   265.0  37.195430
2025-10-26 10:00:13     22  42.400000   212.0  36.909348
2025-10-26 10:00:14     53  38.000000   190.0  33.173785
2025-10-26 10:00:15      2  20.800000   104.0  20.729206
2025-10-26 10:00:16     88  33.600000   168.0  36.760033
2025-10-26 10:00:17     30  39.000000   195.0  32.924155
2025-10-26 10:00:18     38  42.200000   211.0  31.610125
2025-10-26 10:00:19      2  32.000000   160.0  35.270384

=== 분 단위 rolling ===
                     value  mean_5min  sum_5min   std_5min
datetime                                                  
2025-10-26 10:00:00     64  64.000000      64.0        NaN
2025-10-26 10:01:00     60  62.000000     124.0   2.828427
2025-10-26 10:02:00     21  48.333333     145.0  23.755701
2025-10-26 10:03:00     33  44.500000     178.0  20.856654
2025-10-26 10:04:00     76  50.800000     254.0  22.906331
2025-10-26 10:05:00     58  49.600000     248.0  22.187835
2025-10-26 10:06:00     22  42.000000     210.0  24.155745
2025-10-26 10:07:00     89  55.600000     278.0  28.183328
2025-10-26 10:08:00     49  58.800000     294.0  25.781777
2025-10-26 10:09:00     91  61.800000     309.0  28.960318
2025-10-26 10:10:00     59  62.000000     310.0  28.930952
2025-10-26 10:11:00     42  66.000000     330.0  22.737634
2025-10-26 10:12:00     92  66.600000     333.0  23.522330
2025-10-26 10:13:00     60  68.800000     344.0  21.924872
2025-10-26 10:14:00     80  66.600000     333.0  19.565275
2025-10-26 10:15:00     15  57.800000     289.0  30.613722
2025-10-26 10:16:00     62  61.800000     309.0  29.312114
2025-10-26 10:17:00     62  55.800000     279.0  24.211567
2025-10-26 10:18:00     47  53.200000     266.0  24.345431
2025-10-26 10:19:00     62  49.600000     248.0  20.403431

=== 시간 단위 rolling ===
                     value  mean_1h  sum_1h  std_1h
datetime                                           
2025-10-26 00:00:00     51     51.0    51.0     NaN
2025-10-26 01:00:00     55     55.0    55.0     NaN
2025-10-26 02:00:00     64     64.0    64.0     NaN
2025-10-26 03:00:00      3      3.0     3.0     NaN
2025-10-26 04:00:00     51     51.0    51.0     NaN
2025-10-26 05:00:00      7      7.0     7.0     NaN
2025-10-26 06:00:00     21     21.0    21.0     NaN
2025-10-26 07:00:00     73     73.0    73.0     NaN
2025-10-26 08:00:00     39     39.0    39.0     NaN
2025-10-26 09:00:00     18     18.0    18.0     NaN
2025-10-26 10:00:00      4      4.0     4.0     NaN
2025-10-26 11:00:00     89     89.0    89.0     NaN
2025-10-26 12:00:00     60     60.0    60.0     NaN
2025-10-26 13:00:00     14     14.0    14.0     NaN
2025-10-26 14:00:00      9      9.0     9.0     NaN
2025-10-26 15:00:00     90     90.0    90.0     NaN
2025-10-26 16:00:00     53     53.0    53.0     NaN
2025-10-26 17:00:00      2      2.0     2.0     NaN
2025-10-26 18:00:00     84     84.0    84.0     NaN
2025-10-26 19:00:00     92     92.0    92.0     NaN

예제 3

 

- 이전 날짜 (년, 월, 일)

- datetime을 인덱스로 설정

import pandas as pd
import numpy as np

np.random.seed(42)

# 예제 날짜 (연속적이지 않음)
dates = pd.to_datetime([
    '2025-01-05', '2025-01-20', '2025-02-03', '2025-02-18',
    '2025-03-01', '2025-04-10', '2025-06-05', '2025-09-15',
    '2025-12-25'
])
values = np.random.randint(10, 100, size=len(dates))

df = pd.DataFrame({
    'date': dates,
    'value': values
})

# datetime을 인덱스로 설정
df.set_index('date', inplace=True)

# --- 이전 30일(D) 구간 통계 ---
df['mean_30D'] = df['value'].rolling('30D').mean()
df['sum_30D'] = df['value'].rolling('30D').sum()
df['std_30D'] = df['value'].rolling('30D').std()

# --- 이전 2개월(M) 구간 통계 ---
df['mean_2M'] = df['value'].rolling('62D').mean()  # 월 단위는 평균 31일 기준
df['sum_2M'] = df['value'].rolling('62D').sum()
df['std_2M'] = df['value'].rolling('62D').std()

# --- 이전 1년(Y) 구간 통계 ---
df['mean_1Y'] = df['value'].rolling('365D').mean()
df['sum_1Y'] = df['value'].rolling('365D').sum()
df['std_1Y'] = df['value'].rolling('365D').std()

df


min_periods

- min_periods는 rolling에서 최소 데이터 개수 기준을 설정할 때 사용하는 옵션

 

rolling(window=N, min_periods=M)

- window=N : 이동 구간 크기

- min_periods=M : 구간 안에서 최소 M개의 값이 있어야 계산

 

- 기본값 : min_periods=None → window 크기와 동일 (즉, 구간에 값이 부족하면 NaN)

- 값이 충분하지 않으면 계산하지 않고 NaN 반환

 

예를 들어, window=5인데 첫 3개의 값밖에 없으면

- min_periods=5 → NaN

- min_periods=1 → 평균, 합계 계산

import pandas as pd
import numpy as np

np.random.seed(42)

# 띄엄띄엄 날짜 데이터
dates = pd.to_datetime([
    '2025-10-01', '2025-10-03', '2025-10-04',
    '2025-10-05', '2025-10-10', '2025-10-11',
    '2025-10-15', '2025-10-20'
])
values = [10, 20, 30, 40, 50, 60, 70, 80]

df = pd.DataFrame({
    'datetime': dates,
    'value': values
})

# datetime을 인덱스로 설정
df.set_index('datetime', inplace=True)

df['sum_3'] = df['value'].rolling(3).sum()

# 이전 데이터가 2개 이상이면 합
df['sum_3_min'] = df['value'].rolling(3, min_periods=2).sum() 

df['sum_3D'] = df['value'].rolling('3D').sum()
df['sum_3D_min'] = df['value'].rolling('3D', min_periods=2).sum()

df


이후의 행 처리

 

- roliling에서 지원하지 않음.

- 따라서 직접 계산

 

다음 2개의 행의 합

import pandas as pd

# 예시 데이터
df = pd.DataFrame({'value': [10, 20, 30, 40, 50]})
N = 2  # 다음 2개 행 합

# 방법 1: shift와 sum
# 현재 행 이후 2개의 합
df['next_N_sum'] = df['value'].shift(-1).fillna(0) + df['value'].shift(-2).fillna(0)
print(df)

'''
   value  next_N_sum
0     10        50.0  # 20 + 30
1     20        70.0  # 30 + 40
2     30        90.0  # 40 + 50
3     40        50.0  # 50 + 0
4     50         0.0  # 다음 값 없음
'''

 

apply로 이후 7일 구간의 합 계산

import pandas as pd
import numpy as np

dates = pd.to_datetime([
    '2025-10-01', '2025-10-03', '2025-10-04', '2025-10-07', '2025-10-10'
])
values = [10, 20, 30, 40, 50]

df = pd.DataFrame({'datetime': dates, 'value': values})

df.set_index('datetime', inplace=True)

# lambda로 이후 7일 구간 합계 계산
df['sum_7D_future'] = df.index.to_series().apply(
    lambda x: df.loc[(df.index > x) & (df.index <= x + pd.Timedelta(days=7)), 'value'].sum()
)

df

반응형

'개발 > Python' 카테고리의 다른 글

불편추정량 (Unbiased Estimator)  (0) 2025.11.15
Dictionary  (0) 2025.11.15
melt, stack, unstack  (0) 2025.10.26
map, apply, transform  (0) 2025.10.25
라벨 스무딩 (Label Smoothing)  (0) 2025.10.25

댓글