R) 전처리 - 시간데이터 핸들링-01

R) 전처리 - 시간데이터 핸들링-01

데이터를 다루다 보면 시간데이터 처리는 필수적이다. 기본 함수를 활용한 시간데이터 생성 및 변환을 알아보자.

텍스트 처리

특정 패키지의 함수를 사용하는 것이 아니라면 R에서는 겉보기에 표준 날짜 형식처럼 보이는 데이터도 일반 텍스트로 처리를 한다. R에서 제공하는 시간 관련 함수를 사용하려면 이를 우선 시간 형식으로 변환해야되며 대표적으로 사용하는 함수는 다음과 같다.

as.POSIXct(): 텍스트를 시간데이터로 변환
as.POSIXlt(): 텍스트를 시간데이터로 변환
as.Date(): 숫자 또는 텍스트를 시간데이터(날짜)로 변환

as.POSIXct()

as.POSIXct() 함수는 다음과 같이 두 형식의 날짜 입력을 에러 없이 처리하여 시간데이터로 변환한다.

1
2
3
4
5
as.POSIXct("2077-12-28")
## [1] "2077-12-28 KST"

as.POSIXct("2077/12/28")
## [1] "2077-12-28 KST"

함수가 지원하는 입력 형식을 확인하려면 함수의 도움말에서 확인할 수 있다.
as.POSIX*의 도움말

도움말을 참고하여 여러 형식의 입력과 결과를 보면 다음과 같다.

1
2
3
4
5
6
7
8
as.POSIXct("2077-12-28 12") # 1
## [1] "2077-12-28 KST"

as.POSIXct("2077-12-28 12:34")
## [1] "2077-12-28 12:34:00 KST"

as.POSIXct("2077-12-28 12:34:56")
## [1] "2077-12-28 12:34:56 KST"

첫 번째 코드의 경우 시간정보가 있더라도 에러가 발생하지 않고, 무시하고 날짜 정보만 반환하기 때문에 사용에 유의해야 한다. as.POSIXct() 함수를 사용하면서 시간 정보까지 살리고 싶다면 다음과 같이 코드를 작성할 수 있다.

1
2
as.POSIXct("2077-12-28 12:00")
## [1] "2077-12-28 12:00:00 KST"

다음과 같이 함수에서 지원하지 않는 형식의 텍스트를 입력하면 에러가 발생하기 때문에 텍스트 처리 함수인 gsub() 등을 활용하여 표준 형식으로 바꿔주는 것이 좋다.

1
as.POSIXct("2077@12@28")

as.POSIXlt.character(x, tz, ...)에서 다음과 같은 에러가 발생했습니다:
문자열이 표준서식을 따르지 않습니다

여기서 표준형식(서식)이란 yyyy-mm-dd HH:MM:SS 와 같은 형식으로 년월일은 하이픈(-)으로 구분하고 시분초는 콜론(:)으로 구분하며 년월일과 시분초는 띄어쓰기를 한 칸 한 것을 말한다.

사실 시간데이터는 숫자로 처리가 가능하다. as.numeric() 함수로 이 가능성을 확인해볼 수 있다.

1
2
as.numeric(as.POSIXct("2077-12-28"))
## [1] 3407842800

어떻게 나온 숫자인지는 모르겠지만 일단 굉장히 큰 숫자가 나왔다. 숫자의 의미를 파악하기 위해 as.POSIXct.numeric() 함수를 쓸 수 있으며 이는 “origin” 인자에 값을 지정해주기만 한다면 as.POSIXct() 함수를 사용한 결과와 같다.

1
2
3
4
5
6
7
8
as.POSIXct.numeric(100, origin = "2000-01-01")
## [1] "2000-01-01 09:01:40 KST"

as.POSIXct.numeric(100, origin = "2000-01-01", tz = "UTC")
## [1] "2000-01-01 00:01:40 UTC"

as.POSIXct(100, origin = "2000-01-01", tz = "UTC")
## [1] "2000-01-01 00:01:40 UTC"

as.POSIXct() 함수에서 숫자 100은 100초를 의미하며 시간대(time zone)를 지정하지 않으면 시스템 설정시간(여기서는 한국 표준시, KST)을 따른다. 참고로 UTC는 세계표준시이며 KST는 UTC +09:00 이다. 그리고 시간처리를 숫자 기반으로 하는 경우는 대부분 기준 시간(origin)이 “1970-01-01 00:00:00”으로 설정되어있다. 이를 확실히 확인하기 위해 다음과 같이 코드를 작성할 수 있다.

1
2
as.POSIXct(as.numeric(as.POSIXct("2077-12-28")), origin = "1970-01-01")
## [1] "2077-12-28 KST"

as.POSIXlt()

이 함수는 as.POSIXct() 함수와 어떤것이 다를까?

1
2
3
4
5
6
7
8
9
10
11
12
13
as.POSIXlt("2077-12-28")
## [1] "2077-12-28 KST"

as.POSIXlt("2077/12/28")
## [1] "2077-12-28 KST"
as.POSIXlt("2077-12-28 12")
## [1] "2077-12-28 KST"

as.POSIXlt("2077-12-28 12:34")
## [1] "2077-12-28 12:34:00 KST"

as.POSIXlt("2077-12-28 12:34:56")
## [1] "2077-12-28 12:34:56 KST"

상기 코드를 보면 다른점이 없어보인다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
time_ct = as.POSIXct("2077-12-28")
time_lt = as.POSIXlt("2077-12-28")
time_ct
## [1] "2077-12-28 KST"
time_lt
## [1] "2077-12-28 KST"

class(time_ct)
## [1] "POSIXct" "POSIXt"
class(time_lt)
## [1] "POSIXlt" "POSIXt"

attr(time_ct, "tzone")
## [1] ""
attr(time_lt, "tzone")
## NULL

객체의 클래스와 어트리뷰트 부분에서 살짝 다른 것을 알 수 있다. 그리고 RStudio에서도 객체가 표기되는 것이 다른 것을 볼 수 있다.
as.POSIX*의 객체 차이

사실상 데이터를 다루면서 다중 시간대를 다루는 일이 거의 없기 때문에 as.POSIXct() 함수와 as.POSIXlt() 관련해서는 별다른 차이가 없다고 봐도 무방하다.

as.Date()

이 함수는 입력이 시분초 까지 명시되어있더라도 날짜만 반환한다.

1
2
3
4
5
as.Date("2077-12-28 12:34:56")
## [1] "2077-12-28"

as.Date(50000, origin = "2000-01-01")
## [1] "2136-11-23"

복수의 시간데이터 생성

기존 텍스트 변환도 있지만 직접 특정 timestamp를 생성해야되는 경우도 있다. 이 때 사용할 수 있는 것이 seq() 함수이다. 이 함수는 수열(sequence)생성이 기본인데, 입력값을 날짜로 넣는 경우 생성되는 결과도 시간데이터 형식을 가진다. seq() 함수의 사용 예제는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
seq(as.Date("2030-01-01"), as.Date("2034-01-10"), by = "year")
## [1] "2030-01-01" "2031-01-01" "2032-01-01" "2033-01-01" "2034-01-01"

seq(as.Date("2030-01-01"), as.Date("2032-01-10"), by = "quarter")
## [1] "2030-01-01" "2030-04-01" "2030-07-01" "2030-10-01" "2031-01-01"
## [6] "2031-04-01" "2031-07-01" "2031-10-01" "2032-01-01"

seq(as.Date("2030-01-01"), as.Date("2030-12-01"), by = "month")
## [1] "2030-01-01" "2030-02-01" "2030-03-01" "2030-04-01" "2030-05-01"
## [6] "2030-06-01" "2030-07-01" "2030-08-01" "2030-09-01" "2030-10-01"
## [11] "2030-11-01" "2030-12-01"

seq(as.Date("2010-01-01"), as.Date("2010-02-10"), by = "week")
## [1] "2010-01-01" "2010-01-08" "2010-01-15" "2010-01-22" "2010-01-29"
## [6] "2010-02-05"

seq(as.Date("2010-01-01"), as.Date("2010-01-10"), by = "day")
## [1] "2010-01-01" "2010-01-02" "2010-01-03" "2010-01-04" "2010-01-05"
## [6] "2010-01-06" "2010-01-07" "2010-01-08" "2010-01-09" "2010-01-10"

seq(as.Date("2010-01-01"), as.Date("2010-01-10"), by = "2 day") # 1
## [1] "2010-01-01" "2010-01-03" "2010-01-05" "2010-01-07" "2010-01-09"

seq(as.Date("2010-01-01"), as.Date("2010-01-10"), by = "2 days") # 2
## [1] "2010-01-01" "2010-01-03" "2010-01-05" "2010-01-07" "2010-01-09"

“by” 인자에 시간 관련 단위를 명시해주어야 하는데 year/quarter/month/week/day/hour/min/sec 와 같은 값을 지정할 수 있고, 마지막의 1번, 2번 코드처럼 간격을 주고싶다면 숫자를 먼저 쓰고 한 칸 띄운 다음에 시간단위를 입력하여야 하며, 꼭 복수로 쓰지 않아도 알아서 잘 동작한다.

마지막으로 매월 말일 데이터를 생성하려면 다음과 같다.

1
2
3
4
seq(as.Date("2030-01-01"), as.Date("2030-12-01"), by = "month") - 1
## [1] "2029-12-31" "2030-01-31" "2030-02-28" "2030-03-31" "2030-04-30"
## [6] "2030-05-31" "2030-06-30" "2030-07-31" "2030-08-31" "2030-09-30"
## [11] "2030-10-31" "2030-11-30"

시스템 시간 확인

현재 로컬시스템의 시간을 확인하고자 한다면 Sys.time() 함수를 사용하도록 하자. 작업로그를 기록이나 연산시간 측정에 유용하게 사용된다.

1
2
Sys.time()
## [1] "2021-09-20 14:35:55 KST"
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×