lubridate
lubridate
팩키지 1날짜-시간 데이터는 작업하기 까다로운데 이유는 형식이 너무나 다양해서, 날짜-시간 정보를 담긴 데이터를 파싱해서 R에 인식시키기가 손이 많이 가기 때문이다.
이런 문제를 해결하기 위해서 다양한 팩키지들이 개발되어 활용되고 있다. 예를 들어, chron
, timeDate
, zoo
, xts
, its
, tis
, timeSeries
, fts
, tseries
팩키지를 통해서 날짜/시간 데이터를 처리하지만, lubridate
를 활용하여 살펴본다.
lubridate
팩키지 기능 요약
- 날짜-시간 데이터를 식별하고 파싱한다.
- 년, 월, 일, 시, 분, 초 같은 날짜-시간 구성요소를 추출하고 변형한다.
- 날짜-시간 사이 기간을 정확하게 계산한다.
- 시간대와 일광 절약 시간을 처리한다.
lubridate
함수 구문 비교문자열을 날짜 자료형으로 변환하는 코드를 Base
메쏘드와 lubridate
함수를 비교하면 lubridate
팩키지를 사용할 경우 유용성이 쉽게 확인된다.
Base R 함수 | lubridate 함수 |
---|---|
date <- as.POSIXct(“01-01-2010”, format = “%d-%m-%Y”, tz = “UTC”) | date <- dmy(“01-01-2010”) |
as.numeric(format(date, “%m”)) or as.POSIXlt(date)$month + 1 | month(date) |
date <- as.POSIXct(format(date, “%Y-2-%d”), tz = “UTC”) | month(date) <- 2 |
date <- seq(date, length = 2, by = “-1 day”)[2] | date <- date - days(1) |
as.POSIXct(format(as.POSIXct(date), tz = “UTC”), tz = “GMT”) | with_tz(date, “GMT”) |
ymd()
함수를 사용해서 연도, 월, 일 문자열 정보를 인자로 넘겨 날짜-시간 자료형으로 변형한다.
[1] "2011-06-04"
[1] "2011-06-04"
날짜/시간 형식으로 전환하는데 ymd_hms()
함수가 가장 흔히 사용된다. 시간대를 특정하는데 tz
인자를 사용한다.
[1] "2011-06-04 12:00:00 KST"
[1] "2011-08-10 14:00:00 KST"
워낙 다양한 문자열로 다양한 방식으로 날짜/시간을 표시하기 때문에 format=
인자로 파싱을 하는데 다음 날짜/기간 관련 기호를 활용한다.
문자 | 의미 |
---|---|
d |
일(day of month) |
m |
월 |
y |
세기 없는 년도 |
Y |
세기 있는 년도 |
H |
시간(24기준) |
M |
분 |
S |
초 |
a |
축약된 요일명 |
A |
전체 요일명 |
b |
축약된 월명 |
B |
전체 월명 |
I |
시간(12기준) |
p |
오전/우호(AM/PM) |
z |
시간대 |
lubridate
팩키지 dmy_hms()
함수를 사용하는 것도 방법이고 parse_date_time()
함수로 orders=
를 지정해서 푸는 것도 방법이다.
[1] "2017-01-25 22:17:30 UTC"
[1] "2017-01-25 10:17:30 UTC"
make_date()
경우에 따라서는 연도, 월, 일, 시, 분, 초가 각기 다른 칼럼에 담긴 경우도 있다. 이런 경우 make_date()
함수를 사용해서 날짜/시간 자료형으로 데이터를 변환시킨다.
make_date_df <- tribble(~"년", ~"월", ~"일",
2000, 10, 31,
2018, 08, 07,
1973, 10, 03
)
make_date_df %>%
mutate(`날짜` = make_date(`년`, `월`, `일`))
# A tibble: 3 x 4
년 월 일 날짜
<dbl> <dbl> <dbl> <date>
1 2000 10 31 2000-10-31
2 2018 8 7 2018-08-07
3 1973 10 3 1973-10-03
“연-월-일 시:분:초” 형태로 된 데이터를 “연-월-일” 형태로 변환하고자 하는 경우 as.Date()
함수를 사용해서 날짜/시간 자료형을 날짜 형태로 변환시킨다.
ymd_hms()
함수로 밀리초 단위 문자열을 날짜시간 자료형으로 변환시킨다.as.Date()
함수로 “날짜시간” 자료형을 시간은 떼내고 “날짜” 자료형으로 변환시킨다.[1] "1985-04-25 14:38:28" "2012-11-13 17:04:47" "1980-02-03 21:50:44"
[4] "2014-03-27 10:56:33" "1989-02-05 01:17:52"
# A tibble: 5 x 2
날짜시간 시간
<dttm> <date>
1 1985-04-25 14:38:28 1985-04-25
2 2012-11-13 17:04:47 2012-11-13
3 1980-02-03 21:50:44 1980-02-03
4 2014-03-27 10:56:33 2014-03-27
5 1989-02-05 01:17:52 1989-02-05
second
, minute
, hour
, day
, wday
, yday
, week
, month
, year
, tz
함수를 사용해서 날짜와 시간 정보를 데이터에서 추출한다. wday
함수와 month
함수는 선택옵션으로 label
인자를 갖게 되어 숫자를 요일과 월명으로 출력할 수 있다.
[1] 0
[1] "2011-06-04 12:00:25 KST"
[1] 7
[1] 토
Levels: 일 < 월 < 화 < 수 < 목 < 금 < 토
with_tz
와 force_tz
함수로 시간대 관리 작업을 제어한다.
[1] "2011-06-30 19:00:00 CDT"
약속시간을 잘못알아 시간대를 변경할 경우 force_tz
함수로 시간대를 변경한다.
[1] "2011-07-01 23:00:00 KST"
interval()
함수를 사용해서 시간 간격(time interval)을 계산할 수 있다.
[1] 2011-06-04 12:00:00 KST--2011-08-10 14:00:00 KST
동일하게 %--%
함수를 사용해서도 가능하다.
[1] 2011-06-04 12:00:00 KST--2011-08-10 14:00:00 KST
시간 간격이 겹치는지 확인하고자 새로운 시간 간격 객체를 생성하자.
[1] 2011-07-20 NZST--2011-08-31 NZST
두 시간 간격이 겹치는지 확인해 보자.
[1] TRUE
그 외에도 setdiff
, int_start
, int_end
, int_flip
, int_shift
, int_aligns
, union
, intersect
, setdiff
, %within%
다양한 함수를 통해 작업이 가능하다.
[1] 2011-06-04 12:00:00 KST--2011-07-19 21:00:00 KST
기간(interval)은 특정 기간이다. 즉, 특정된 날짜에 구속된다. lubridate
함수는 duration 과 period 클래스를 제공한다.
lubridate
에서 시간 범위를 표현하는 두가지 다른 개념이 존재한다. PERIOD
와 DURATION
이 그것이다.
period |
duration |
---|---|
사람이 인지하는 시간 범위 | 기계가 인지하는 시간 범위 |
가변적인 시간범위 | 고정된 시간 범위 |
minutes() = “1M 0S” |
dminutes() = “60s (~1 minutes)” |
PERIOD
와 DURATION
을 R에서 다루는 함수는 다음과 같다. PERIOD
함수에 앞에 d
를 붙인다.
시간 범위 | Duration | Period |
---|---|---|
초(Second) | dseconds() |
seconds() |
분(Minute) | dminutes() |
minutes() |
시(Hour) | dhours() |
hours() |
일(Day) | ddays() |
days() |
주(Week) | dweeks() |
weeks() |
월(Month) | – | months() |
년(Year) | dyears() |
years() |
[1] "2M 0S"
[1] "120s (~2 minutes)"
기간(duration)의 경우 1년은 항상 365일이 되지만, 시기(Period)는 시각표가 직관적으로 제시하는 것과 같은 방식으로 변동하게 된다. 예를 들어, 기간은 윤년이 있는 경우 정직하게 숫자를 제시하지만, 시기는 예상하는 바를 제시하게 된다.
[1] FALSE
[1] "2012-01-01"
[1] "2012-01-01"
[1] TRUE
[1] "2012-12-31"
[1] "2013-01-01"
기간과 시기를 사용해서 날짜-시간에 대한 기본 연산도 할 수 있다.
[1] FALSE FALSE FALSE TRUE TRUE TRUE
오클랜드에 얼마나 머무를까?
[1] 67.08333
[1] 33.54167
[1] 96600
나머지 연산자와 정수 나눗셈을 할 수도 있다.
[1] 2
[1] 2011-08-04 12:00:00 KST--2011-08-10 14:00:00 KST
[1] "6d 2H 0M 0S"
[1] "2m 6d 2H 0M 0S"
lubridate
는 벡터화가 되어 있어 바로 함수와 인터랙티브한 방식으로 적용이 가능하다.
위키백과사전에서 대한민국의 대통령 목록 확인된 대통령 재임기간은 다음과 같다.
대통령 취임일과 종료일을 입력하고 시작일과 종료일을 날짜 자료형으로 변형시키게 되면 연산이 가능하다. 따라서 615선언 이후 즉, 노태우 대통령이후 대통령만 추려서 재임기간을 사람이 인식하는 일반적인 재임기간과 절대시간 기준으로 나눠본다. 그리고 나서 정렬을 해야 하는데 현재 interval
객체가 데이터프레임에 들어가면 정렬하는 기능은 지원되고 있지 않다. 따라서 다음과같은 표로 확인을 한다.
president_dat <- tribble(~"이름", ~"시작일", ~"종료일",
"이승만", "1948-08-15", "1960-04-26",
"윤보선", "1960-08-02", "1962-03-23",
"박정희", "1963-12-17", "1979-10-26",
"최규하", "1979-12-06", "1980-08-16",
"전두환", "1980-09-01", "1988-02-24",
"노태우", "1988-02-25", "1993-02-24",
"김영삼", "1993-02-25", "1998-02-24",
"김대중", "1998-02-25", "2003-02-24",
"노무현", "2003-02-25", "2008-02-24",
"이명박", "2008-02-25", "2013-02-24",
"박근혜", "2013-02-25", "2016-12-09",
"문재인", "2017-05-10", "2022-05-10")
president_df <- president_dat %>%
mutate(`시작일` = lubridate::ymd(`시작일`),
`종료일` = lubridate::ymd(`종료일`)) %>%
filter(`종료일` > ymd("1988-06-15")) %>% # 노태우 대통령 이후 ~
mutate(`시작종료` = interval(`시작일`, `종료일`)) %>%
mutate(`재임기간` = as.period(`시작종료`)) %>% # 사람이 인지하는 시간
mutate(`절대시간` = as.duration(`시작종료`)) %>% # 절대적인 시간
mutate(`정렬키` = unclass(lubridate::int_length(`시작종료`)))
president_df %>%
knitr::kable()
이름 | 시작일 | 종료일 | 시작종료 | 재임기간 | 절대시간 | 정렬키 |
---|---|---|---|---|---|---|
노태우 | 1988-02-25 | 1993-02-24 | 1988-02-25 UTC–1993-02-24 UTC | 4y 11m 30d 0H 0M 0S | 157766400s (~5 years) | 157766400 |
김영삼 | 1993-02-25 | 1998-02-24 | 1993-02-25 UTC–1998-02-24 UTC | 4y 11m 30d 0H 0M 0S | 157680000s (~5 years) | 157680000 |
김대중 | 1998-02-25 | 2003-02-24 | 1998-02-25 UTC–2003-02-24 UTC | 4y 11m 30d 0H 0M 0S | 157680000s (~5 years) | 157680000 |
노무현 | 2003-02-25 | 2008-02-24 | 2003-02-25 UTC–2008-02-24 UTC | 4y 11m 30d 0H 0M 0S | 157680000s (~5 years) | 157680000 |
이명박 | 2008-02-25 | 2013-02-24 | 2008-02-25 UTC–2013-02-24 UTC | 4y 11m 30d 0H 0M 0S | 157766400s (~5 years) | 157766400 |
박근혜 | 2013-02-25 | 2016-12-09 | 2013-02-25 UTC–2016-12-09 UTC | 3y 9m 14d 0H 0M 0S | 119491200s (~3.79 years) | 119491200 |
문재인 | 2017-05-10 | 2022-05-10 | 2017-05-10 UTC–2022-05-10 UTC | 5y 0m 0d 0H 0M 0S | 157766400s (~5 years) | 157766400 |
# president_df %>%
# arrange(`정렬키`)
# Error in arrange_impl(.data, dots) :
# Column `시작종료` classes Period and Interval from lubridate are currently not supported.
두번째로 총선과 지방선거를 넣고 재임기간동안 선거가 얼마나 많이 일어났는지 확인해보자. 위키백과사전, 대한민국의 선거에서 데이터를 받아 정리한다.
지방선거 시작된 이후 선거만 추출하고 재임기간 계산해서 반환하는 Helper 함수를 작성해서 각 대통령별로 해당 재임기간 있었던 선거를 개수한다.
# 1987년 이후 총선/대선/지선 선거일
election_df <- tribble(~"선거", ~"선거일",
"1987년 개헌 국민투표", "1987-10-27",
"제13대 대통령 선거", "1987-12-16",
"제13대 국회의원 선거", "1988-04-26",
"제14대 국회의원 선거", "1992-03-24",
"제14대 대통령 선거", "1992-12-18",
"제1회 지방선거", "1995-06-27",
"제15대 국회의원 선거", "1996-04-11",
"제15대 대통령 선거", "1997-12-18",
"제2회 지방선거", "1998-06-04",
"제16대 국회의원 선거", "2000-04-13",
"제3회 지방선거", "2002-06-13",
"제16대 대통령 선거", "2002-12-19",
"제17대 국회의원 선거", "2004-04-15",
"제4회 지방선거", "2006-05-31",
"제17대 대통령 선거", "2007-12-19",
"제18대 국회의원 선거", "2008-04-09",
"제5회 지방선거", "2010-06-02",
"제19대 국회의원 선거", "2012-04-11",
"제18대 대통령 선거", "2012-12-19",
"제6회 지방선거", "2014-06-04",
"제20대 국회의원 선거", "2016-04-13",
"제19대 대통령 선거", "2017-05-09",
"제7회 지방선거", "2018-06-13")
# 지방선거 시작된 이후 선거만 추출
election_df <- election_df %>%
mutate(`선거일` = ymd(`선거일`)) %>%
filter(`선거일` > ymd("1995-01-01"))
# 재임기간 계산해서 반환하는 Helper 함수
get_reign <- function(president_name) {
president_reign <- president_dat %>%
filter(`이름` == president_name) %>%
mutate(`시작일` = lubridate::ymd(`시작일`),
`종료일` = lubridate::ymd(`종료일`)) %>%
mutate(`시작종료` = interval(`시작일`, `종료일`)) %>%
pull(`시작종료`)
return(president_reign)
}
get_reign("노무현")
[1] 2003-02-25 UTC--2008-02-24 UTC
# 선거일별 재임중인 대통령 여부
(reign_election_df <- election_df %>%
arrange(`선거일`) %>%
mutate(`김영삼` = `선거일` %within% get_reign("김영삼"),
`김대중` = `선거일` %within% get_reign("김대중"),
`노무현` = `선거일` %within% get_reign("노무현"),
`이명박` = `선거일` %within% get_reign("이명박"),
`박근혜` = `선거일` %within% get_reign("박근혜"),
`문재인` = `선거일` %within% get_reign("문재인")) )
# A tibble: 18 x 8
선거 선거일 김영삼 김대중 노무현 이명박 박근혜 문재인
<chr> <date> <lgl> <lgl> <lgl> <lgl> <lgl> <lgl>
1 제1회 지방선거 1995-06-27 TRUE FALSE FALSE FALSE FALSE FALSE
2 제15대 국회의원 선거~ 1996-04-11 TRUE FALSE FALSE FALSE FALSE FALSE
3 제15대 대통령 선거 1997-12-18 TRUE FALSE FALSE FALSE FALSE FALSE
4 제2회 지방선거 1998-06-04 FALSE TRUE FALSE FALSE FALSE FALSE
5 제16대 국회의원 선거~ 2000-04-13 FALSE TRUE FALSE FALSE FALSE FALSE
6 제3회 지방선거 2002-06-13 FALSE TRUE FALSE FALSE FALSE FALSE
7 제16대 대통령 선거 2002-12-19 FALSE TRUE FALSE FALSE FALSE FALSE
8 제17대 국회의원 선거~ 2004-04-15 FALSE FALSE TRUE FALSE FALSE FALSE
9 제4회 지방선거 2006-05-31 FALSE FALSE TRUE FALSE FALSE FALSE
10 제17대 대통령 선거 2007-12-19 FALSE FALSE TRUE FALSE FALSE FALSE
11 제18대 국회의원 선거~ 2008-04-09 FALSE FALSE FALSE TRUE FALSE FALSE
12 제5회 지방선거 2010-06-02 FALSE FALSE FALSE TRUE FALSE FALSE
13 제19대 국회의원 선거~ 2012-04-11 FALSE FALSE FALSE TRUE FALSE FALSE
14 제18대 대통령 선거 2012-12-19 FALSE FALSE FALSE TRUE FALSE FALSE
15 제6회 지방선거 2014-06-04 FALSE FALSE FALSE FALSE TRUE FALSE
16 제20대 국회의원 선거~ 2016-04-13 FALSE FALSE FALSE FALSE TRUE FALSE
17 제19대 대통령 선거 2017-05-09 FALSE FALSE FALSE FALSE FALSE FALSE
18 제7회 지방선거 2018-06-13 FALSE FALSE FALSE FALSE FALSE TRUE
# 대통령 재임 기간 중 선거횟수
reign_election_df %>%
select(-`선거`, -`선거일`) %>%
gather(`대통령`, `선거여부`) %>%
group_by(`대통령`) %>%
summarise(`선거횟수` = sum(`선거여부`)) %>%
arrange(-`선거횟수`)
# A tibble: 6 x 2
대통령 선거횟수
<chr> <int>
1 김대중 4
2 이명박 4
3 김영삼 3
4 노무현 3
5 박근혜 2
6 문재인 1