【數據分析】R|時間格式處理|date format & lubridate
在R之中,我們有時會需要時間的轉換。常常抓到網路資料後,得到的timestamp欄位可能是char或是num的格式,這時候就可以採用內建的as.date或取用lubridate這個package。但在了解怎麼用後面的函數從字串中轉成時間前,得先知道什麼是標準的時間格式,才知道怎麼得到想要的結果。
比方,我習慣將現在系統時間a <- Sys.time()存起來,再來就能直接用month(a), day(a), hour(a)直接得到月、日、小時的資訊,方便我直接將抓取到的資料為檔案命名。
所以這時候,反而回過頭用as.POSIXct自己根據資料內容觀察,自行設定format會較方便。例如:
如果再複雜一點,可以先用RegEx搭配相關擷取函數清理掉非數字,且保留日期和星期的特殊字,再將結果用這裡提到的方法整理成標準時間即可。
下一篇我會補充講解如何將as_datetime的結果修正,把時區轉換成自訂的時區。
標準時間格式
class為「POSIXlt」和「POSIXct」,包含資料的格式為"%Y-%m-%d %H:%M:%S"。- "年-月-日 時:分:秒" 在日期間以「-」區隔,時間以「:」區隔,兩者以一個空白分隔。
- %m 小寫是月(month), %M 大寫是分(Minute) → 時間的格式都是大寫。
- 以我們台灣來講,CST = China Standard Time,也就是常聽到的中原標準時間,是我們這個經度所位在的時區。相對於UTC地球標準時間要加上八小時。即為UTC+8。
- UTC = Coordinated Universal Time是像秒一樣的公定標準,格林威治標準時間GMT = Greenwich Mean Time所在時區與該時間相同。
- now()之中可以設定時區 → now(tzone = "UTC") 會得到比CST少8小時的結果。
轉換為日期
首先先看日期的部分,實作上,常碰到的是三種狀況:- 長相已經是標準日期(Ex: 2018-11-09),但型別為character
- 長相是數字(Ex: 17844),型別為numeric
- 各式長相的時間(Ex: "November 9, 2018"、"09/11/2018"),型別為character
面對這些該如何怎麼解決呢?
解決方法:as.Date搭配format設定
[1] as.Date("2018-11-09")
→"2018/11/09"也可以直接放入,自動轉換成-
[2] as.Date(17844, origin)
→系統預設origin為1970-01-01,它會自動從這天開始得到17844天後之日期。
[3] as.Date("November 9, 2018", format="%B %d, %Y")
→%B用來抓取月份的英文全名(%b則為縮寫)January vs. Jan
→%A則是抓取星期幾的英文名(%a也為縮寫)Friday vs. Fri
[4] as.Date("09/11/2018", format="%d/%m/%Y")
注意
如果[3]類行不通,是跟語言設定有關,原因為預設之locale為「Chinese (Traditional)_Taiwan.950」,處理內容須為「十一月 09, 2018」才有效。處理方法是將locale語言做改變,依序步驟如下:
- lct <- Sys.getlocale("LC_TIME") 取得當前的語言
- Sys.setlocale("LC_TIME", "C") 設定語言
- 將 [3] 英文版的內容輸入於此即可!
- Sys.setlocale("LC_TIME", lct) 重新設定為原語言
有趣的是,中文的「%A是星期」五,「%a是週」五。
轉換為標準時間格式
再來看看時間,常碰到的也是三種狀況:- 長相已經是標準時間格式的樣子,但型別為character
- 長相是數字(Ex: 1541111111),型別為numeric
- 各式長相的時間(Ex: "Nov 9, 2018 11:35:06"),型別為character
這些又該如何怎麼解決呢?
解決方法:as.POSIXct 或 as.POSIXlt(想知道他們有什麼不同可以點這)
[1] as.POSIXct("2018-11-09 15:17:18 CST")
[2] as.POSIXlt(1541111111, origin="1970-01-01 00:00:00")
→ 得到 "2018-11-02 06:25:11 CST"
→ 得到 "2018-11-02 06:25:11 CST"
[3] as.POSIXlt("Nov 9, 2018 15:17:18", format="%b %d, %Y %H:%M:%S")
→ 得到 "2018-11-09 15:17:18 CST"
→ 得到 "2018-11-09 15:17:18 CST"
解決方法:直接用Lubridate套件(package)
[1] as_datetime("2018-11-09 15:17:18 CST")
[2] as_datetime(1541111111)
[3] mdy_hms("Nov 9, 2018 11:35:06")
注意
缺點是轉換出來的結果會將時區統一變成UTC,所以需要額外做時區轉換,待下篇再著墨這部分。
那Lubridate的函數能解決轉換成日期的問題嗎?
當然可以!來看第一區塊怎麼快速轉換,如下:
[1] as_date("2018-11-09")或ymd("2018-11-09")
[2] as_date(17844)
[3] mdy("November 9, 2018")
[4] dmy("09/11/2018")
非常強大,包含%B都能處理並能自動忽略其他非數字,函數會自動依照你訂的順序找到相符的結果,輸出標準格式的日期出來。(但如果有數字的話會受到干擾)
Lubridate
含有許多專門針對日期時間所設計的函數。除了像上述轉換為POSIXct標準格式,還包含了年月日時分秒的快速取用(反過來,把標準時間轉成自己想要的輸出),以及對時區的轉換。比方,我習慣將現在系統時間a <- Sys.time()存起來,再來就能直接用month(a), day(a), hour(a)直接得到月、日、小時的資訊,方便我直接將抓取到的資料為檔案命名。
結語
Lubridate對於稍微醜又不會太醜(?)的時間日期做修正,是非常好用的,然而對於混雜的時間和日期就無法處理,比如"Nov 9 11:35:06, 2018"這種時間安插在日期之間的資料,它就沒有md_hms_y之類的Function處理,而直接用mdy_hms又會回報錯誤。所以這時候,反而回過頭用as.POSIXct自己根據資料內容觀察,自行設定format會較方便。例如:
- as.POSIXlt("Nov 9,11:35:06,2018", format="%b %d,%H:%M:%S,%Y")
如果再複雜一點,可以先用RegEx搭配相關擷取函數清理掉非數字,且保留日期和星期的特殊字,再將結果用這裡提到的方法整理成標準時間即可。
下一篇我會補充講解如何將as_datetime的結果修正,把時區轉換成自訂的時區。
留言