[Pandas 기초] 7. 시계열 데이터 처리
Python Library 중 하나인 Pandas에서 시계열 데이터를 처리하는 방법을 알아보자.
시계열 데이터
- 행과 행에 시간의 순서(흐름)가 있고
- 행과 행의 시간 간격이 동일한 데이터 (엄격한 기준임)
- Time Series = Sequential Data 라고도 부름
날짜 요소 추출
날짜 타입으로 변환
- 보통, 데이터에서 날짜는 data type이 object로 되어있음
- 이를
data['Date'] = pd.to_datetime(data['Date'])
와 같이 datetime으로 변경해준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sales = pd.read_csv("https://raw.githubusercontent.com/DA4BAM/dataset/master/ts_sales_simple.csv")
products = pd.read_csv("https://raw.githubusercontent.com/DA4BAM/dataset/master/ts_product_master.csv")
# 판매액 계산하기
temp = pd.merge(sales, products)
temp['Amt' ] = temp['Qty'] * temp['Price']
temp['Amt'] = (temp['Amt']/1000).round() # 단위 1000달러
# 집계
data1 = temp.groupby(['Date', 'Category'], as_index = False)['Amt'].sum()
data2 = temp.groupby(['Date'], as_index = False)['Amt'].sum()
data11 = data1.pivot('Date', 'Category', 'Amt').reset_index()
data = pd.merge(data2, data11)
data.head()
Date | Amt | Drink | Food | Grocery | Household Goods | |
---|---|---|---|---|---|---|
0 | 2013-01-01 | 20.0 | 7.0 | 4.0 | 6.0 | 3.0 |
1 | 2013-01-02 | 3938.0 | 604.0 | 549.0 | 1663.0 | 1122.0 |
2 | 2013-01-03 | 2885.0 | 444.0 | 376.0 | 1222.0 | 843.0 |
3 | 2013-01-04 | 2907.0 | 490.0 | 386.0 | 1252.0 | 779.0 |
4 | 2013-01-05 | 3831.0 | 704.0 | 505.0 | 1560.0 | 1062.0 |
- 데이터가 위와 같을 때, Date 칼럼을 Datetime으로 변경해보자
1
2
# data 확인
data.info()
1
2
3
4
5
6
7
8
9
10
11
12
13
<class 'pandas.core.frame.DataFrame'>
Int64Index: 31 entries, 0 to 30
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Date 31 non-null object
1 Amt 31 non-null float64
2 Drink 31 non-null float64
3 Food 31 non-null float64
4 Grocery 31 non-null float64
5 Household Goods 31 non-null float64
dtypes: float64(5), object(1)
memory usage: 1.7+ KB
1
2
3
4
5
# datetime으로 변환
data['Date'] = pd.to_datetime(data['Date'])
# 확인
data.info()
1
2
3
4
5
6
7
8
9
10
11
12
13
<class 'pandas.core.frame.DataFrame'>
Int64Index: 31 entries, 0 to 30
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Date 31 non-null datetime64[ns]
1 Amt 31 non-null float64
2 Drink 31 non-null float64
3 Food 31 non-null float64
4 Grocery 31 non-null float64
5 Household Goods 31 non-null float64
dtypes: datetime64[ns](1), float64(5)
memory usage: 1.7 KB
- format = ‘’
pd.to_datetime(date, format = '%d/%m/%Y')
- format = ‘%d/%m/%Y’ 입력되는 날짜가 이런 형태야~~ 라고 알려주는 옵션
1
2
3
date = pd.Series(['03-01-2023', '03-02-2023', '03-03-2023'])
date = pd.to_datetime(date)
date
1
2
3
4
0 2023-03-01
1 2023-03-02
2 2023-03-03
dtype: datetime64[ns]
1
2
3
date = pd.Series(['03-01-2023', '03-02-2023', '03-03-2023'])
date = pd.to_datetime(date, format = '%d-%m-%Y') #입력받은 날짜 데이터 형식이 '%d-%m-%Y'!
date
1
2
3
4
0 2023-01-03
1 2023-02-03
2 2023-03-03
dtype: datetime64[ns]
날짜 요소 추출
- 날짜 타입의 변수로부터 날짜의 요소를 뽑아낼 수 있음
data['yaer'] = data['date'].dt.year
와 같이 뽑아내고 할당할 수 있음- 사진과 같이 다양한 method가 있음
1
2
3
# datetime 에서 날짜 요소 추출 해보기
data['weekday'] = data['Date'].dt.weekday
data.head(3)
Date | Amt | Drink | Food | Grocery | Household Goods | weekday | |
---|---|---|---|---|---|---|---|
0 | 2013-01-01 | 20.0 | 7.0 | 4.0 | 6.0 | 3.0 | 1 |
1 | 2013-01-02 | 3938.0 | 604.0 | 549.0 | 1663.0 | 1122.0 | 2 |
2 | 2013-01-03 | 2885.0 | 444.0 | 376.0 | 1222.0 | 843.0 | 3 |
시간에 따른 흐름 추출하기 : Time Lag
- 시계열 데이터에 사용
- shift, rolling, diff 가 있다.
.shift()
- 시계열 데이터에서 시간의 흐름 전후로 정보를 이동시킬 때 사용
temp['Amt_lag'] = temp['Amt'].shift(periods=n)
과 같이 사용- n행 shift 한다는 의미임. periods 생략 가능. 기본값은 1
1
2
3
4
5
6
7
8
9
10
11
12
temp = data.loc[:,['Date','Amt']]
# 전날 매출액 열을 추가합시다.
temp['Amt_lag'] = temp['Amt'].shift() #default = 1
# 전전날 매출액 열을 추가.
temp['Amt_lag2'] = temp['Amt'].shift(2) # 2행 shift
# 다음날 매출액 열을 추가합시다.
temp['Amt_lag_1'] = temp['Amt'].shift(-1)
temp.head()
Date | Amt | Amt_lag | Amt_lag2 | Amt_lag_1 | |
---|---|---|---|---|---|
0 | 2013-01-01 | 20.0 | NaN | NaN | 3938.0 |
1 | 2013-01-02 | 3938.0 | 20.0 | NaN | 2885.0 |
2 | 2013-01-03 | 2885.0 | 3938.0 | 20.0 | 2907.0 |
3 | 2013-01-04 | 2907.0 | 2885.0 | 3938.0 | 3831.0 |
4 | 2013-01-05 | 3831.0 | 2907.0 | 2885.0 | 4066.0 |
.rolling().mean()
- 시간의 흐름에 따라 일정 기간 동안 평균을 이동하면서 구하기
- .rolling(n):
- n 기본값은 1
- min_periods : 최소 데이터 수
- min_periods 설정이 없으면, n일까지는 이전 데이터가 없기 때문에 NaN이 뜨지만, 설정하게되면 설정한 값부터 값을 내줌
.rolling().mean()
은 이동평균값
1
2
3
4
# 7일 이동평균 매출액을 구해 봅시다.
temp['Amt_MA7_1'] = temp['Amt'].rolling(7).mean()
temp['Amt_MA7_2'] = temp['Amt'].rolling(7, min_periods = 1).mean()
temp.head(10)
Date | Amt | Amt_lag | Amt_lag2 | Amt_lag_1 | Amt_MA7_1 | Amt_MA7_2 | |
---|---|---|---|---|---|---|---|
0 | 2013-01-01 | 20.0 | NaN | NaN | 3938.0 | NaN | 20.000000 |
1 | 2013-01-02 | 3938.0 | 20.0 | NaN | 2885.0 | NaN | 1979.000000 |
2 | 2013-01-03 | 2885.0 | 3938.0 | 20.0 | 2907.0 | NaN | 2281.000000 |
3 | 2013-01-04 | 2907.0 | 2885.0 | 3938.0 | 3831.0 | NaN | 2437.500000 |
4 | 2013-01-05 | 3831.0 | 2907.0 | 2885.0 | 4066.0 | NaN | 2716.200000 |
5 | 2013-01-06 | 4066.0 | 3831.0 | 2907.0 | 2700.0 | NaN | 2941.166667 |
6 | 2013-01-07 | 2700.0 | 4066.0 | 3831.0 | 2533.0 | 2906.714286 | 2906.714286 |
7 | 2013-01-08 | 2533.0 | 2700.0 | 4066.0 | 2462.0 | 3265.714286 | 3265.714286 |
8 | 2013-01-09 | 2462.0 | 2533.0 | 2700.0 | 2110.0 | 3054.857143 | 3054.857143 |
9 | 2013-01-10 | 2110.0 | 2462.0 | 2533.0 | 2405.0 | 2944.142857 | 2944.142857 |
.diff()
- 특정 시점 데이터, 이전시점 데이터와의 차이 구하기
temp['Amt_D1'] = temp['Amt'].diff(n)
과 같이 사용- n행 전과 차이를 구한다는 의미
1
2
3
temp['Amt_D1'] = temp['Amt'].diff()
temp['Amt_D2'] = temp['Amt'].diff(2)
temp.head(5)
Date | Amt | Amt_lag | Amt_lag2 | Amt_lag_1 | Amt_MA7_1 | Amt_MA7_2 | Amt_D1 | Amt_D2 | |
---|---|---|---|---|---|---|---|---|---|
0 | 2013-01-01 | 20.0 | NaN | NaN | 3938.0 | NaN | 20.0 | NaN | NaN |
1 | 2013-01-02 | 3938.0 | 20.0 | NaN | 2885.0 | NaN | 1979.0 | 3918.0 | NaN |
2 | 2013-01-03 | 2885.0 | 3938.0 | 20.0 | 2907.0 | NaN | 2281.0 | -1053.0 | 2865.0 |
3 | 2013-01-04 | 2907.0 | 2885.0 | 3938.0 | 3831.0 | NaN | 2437.5 | 22.0 | -1031.0 |
4 | 2013-01-05 | 3831.0 | 2907.0 | 2885.0 | 4066.0 | NaN | 2716.2 | 924.0 | 946.0 |
This post is licensed under CC BY 4.0 by the author.