웹사이트 사용자의 세션 로그인 기록, 비트코인 등 주식 시세 시계열 데이터, 병원 환자 체류 시간, 그 어떤 로그(Log) 데이터를 받더라도 “날짜와 절대적 시간”은 해당 데이터를 지배하는 가장 핵심적인 맥락이자 기둥입니다.
그러나 시간 데이터는 악마의 재능과 함정을 깊이 숨기고 있습니다. 표기된 2023-01-01은 아무리 봐도 숫자 같지만 시스템 뼈대 컴퓨터 입장에선 단순한 `문자(Character 텍스트)` 박스일 뿐이며, 여기에 산술적으로 1년을 더할 때 평달 365일을 더할지 윤년(366일)을 더할지, 주말 휴일은 언제인지 고려해야 할 물리적 우주 변수가 끝이 없습니다.
이 지옥 같고 복잡한 실무 날짜 계산을 단 몇 개의 직관적인 영단어 함수 이름으로 통합 및 자동화시킨 tidyverse 생태계의 절대적 구세주 패키지, lubridate 의 심연을 마스터해 봅시다!
1. 못생기고 규격 없는 문자열을 스마트한 타임머신(Date 객체)으로 일괄 변환
글로벌 지사나 타 시스템에서 제각기 다르게 다운로드된 다양한 형태의 문자열 포맷 예컨대 "20230228", "02-28-2023"를 R 엔진이 요일 계산이나 개월 수 계산까지 수학적으로 할 수 있는 ‘진짜 유기적인 시간 데이터 객체’로 만들려면 변환 순서 규칙만 명확히 기억하면 됩니다. Year(년), Month(월), Day(일)의 첫 글자를 영문으로 직관적으로 따서 앞뒤 순서대로 엮은 타이핑 함수가 바로 해답입니다.
library(lubridate)
# 1. 아시아인 전용: 년-월-일 순서로 타이핑되어 있다면? ymd!
ymd("20220228")
> [1] "2022-02-28"
# 2. 미국인 전용: 월-일-년 순서로 적힌 텍스트라면? mdy!
mdy("02/28/2022")
> [1] "2022-02-28"
# 3. 유럽인 전용: 일-월-년 구분기호가 특이하게 점(.)으로 되어있어도 척척!
dmy("28.02.2022")
> [1] "2022-02-28"
수백 개의 날짜 데이터가 함수에 배열로 던져 들어가는 순간, 제잡동사니로 제각기 섞여 달랐던 문자열이 단일화된 깔끔한 ISO 날짜 표준 객체 포맷(YYYY-MM-DD)으로 마법처럼 변환 및 정리됩니다!
2. 파편화된 핵심 속성 정보만 가위로 쏙쏙 뽑아내기
날짜를 단순 텍스트가 아닌 Date 스마트 객체로 세팅 완료해두면 무서운 활용성이 열리게 됩니다. 특정 날짜에서 그 날이 속한 요일, 1년 중 몇 번째 주차(Week)인지, 기업 재무용 분기 정보 등을 손쉽게 뜯어내어 새로운 분석 열(Column)로 달아 통계에 쓸 수 있습니다.
my_date <- ymd("2023-04-12")
# Q. 이 날의 달력상 '월(Month)' 팩터만 스캔해서 뽑아줘!
month(my_date)
> [1] 4
# Q. 이 날이 1년(총 52주) 진행 캘린더 중 몇 번째 '주차'에 위치해?
week(my_date)
> [1] 15
# Q. 재무 및 영업 실적 기업 분석에 필수! 해당 분기(Quarter) 넘버는?
quarter(my_date)
> [1] 2
# Q. 대망의 요일 자동 추적 계산! (label = TRUE 이면 월, 화 형태의 직관적 텍스트로 나옴)
wday(my_date, label = TRUE)
> [1] 수
> Levels: 일 < 월 < 화 < 수 < 목 < 금 < 토
3. 진정한 날짜 더블링 더하기 계산의 심연: months() vs dmonths()
금융 데이터 등에서 애를 먹는, 가장 많이 헷갈리면서도 치명적인 날짜 기간 산술 계산의 묘미입니다.
질문: “올해 3월 31일의 정확히 한 달 뒤는 수학적으로 며칠일까요?”
비즈니스 룰과 사람 논리에 따라 “그냥 무조건 한 달이 지났으니 달력을 넘겨 4월이 되고, 원래 달의 기준 끝 날짜니까 4월 30일이겠지?”, 혹은 “물리적 절대 규칙상 무조건 한달은 30일이 기준이니까 30일 * 24시간을 더한 시점이겠지?” 등 생각이 다릅니다. 이 문제를 해결하기 위해 R lubridate 엔진은 이 두 가지 관점을 함수명 하나로 완벽히 분리했습니다.
① 달력 넘기기 아날로그 개념 (단순 months)
순수하게 “1개월”이라는 달력판의 월(Month) 이름 포지션만 기계적으로 업데이트(+1)합니다. 그런데 3월 31일에서 달만 숫자 4로 바꾸게 되면 우리 달력계수계에 존재하지 않는 환상의 날짜인 “4월 31일”이라는 심각한 논리적 모순이 발생하여, 엔진은 계산 불능 선언(NA) 에러 뱉어버립니다!
ymd("2023-03-31") + months(1)
> [1] NA
② 절대 불변 물리적인 초단위 시간 축 (d가 붙은 dmonths)
듀레이션(Duration, 우주적 지속 절대 시간)의 약자인 d를 앞에 스위치로 붙이면, 한 달(1 Month)을 철저히 초 단위(Seconds)로 계산된 물리적인 대략 “절대 소요 30.4375일의 타임 폭”으로 고정 세팅해서 절대 변수로 계산해버립니다!
# 윤달이 포함된 계산 등의 변수에도 흔들림 없는 초단위 절대량 덧셈!
ymd("2023-02-01") + dmonths(1)
> [1] "2023-03-03 10:30:00 UTC"
설명하자면, 2023년 2월은 28일밖에 없기 때문에, 이 날짜에 월 한 개 수준의 압도적인 물리 시간량 30.4375일을 그냥 폭탄처럼 얹어버리면 달력을 순식간에 관통하고 넘어가 3월 3일 오전 경으로 결과가 안착되어 나옵니다. (윤년 366일짜리 해의 경우에도 months(1)은 여전히 2월 29일을 유지하지만, dyears(1)은 정확히 통계적 365.25일을 더하는 등 치명적인 결산 미세 차이가 발생하니 이커머스 매출 분석 등 비즈니스 분석 목적에 맞춰 d의 유무를 필히 잘 채택하여 사용해야 합니다.)
4. 절대적 나이, 누적 경과 기간(Duration/Interval) 쉽게 구하기
가입일이나 생년월일을 기준으로 현재 today() 시점까지 인간의 세월이 도대체 얼마나 흘렀는지, 정확히 소수점 나이로 몇 살인지를 계산하고 싶을 땐 시간 간격 분할 연산을 구사하면 끝납니다.
# 오늘까지 전체 소요된 타임라인의 일수(Days Difference / Time diff)
my_age_duration <- today() - ymd("1999-04-28")
# 흐른 전체 일수 덩어리를 물리적 절대 1년 단위량(dyears) 객체로 산술나누기하여 실제 사람 나이 산출!
as.numeric(my_age_duration / dyears(1))
> [1] 23.97262
정리하자면 최신 lubridate 패키지는 프로그래머 골병의 원인인 시간 세계관의 블랙홀 같은 수십 개 예외 케이스(윤년 계산, 큰달, 작은달 방어, 타임존 등)를 완벽하게 뒤에서 방어해 주는 강력한 자동 보호구입니다. 날짜 컬럼의 데이터를 분석 파이프라인에서 마주하게 되면 다른 전통적 베이스 코딩은 전부 잊으시더라도 ymd() 변환과 추출함수(month, wday) 2가지 파이프라인만은 생명줄처럼 꼭 머릿속에 기억해보시길 적극 권장합니다!
당신이 좋아할 만한 콘텐츠
by Google Adsense