杜雨,EasyCharts团队成员,R语言中文社区专栏作者,兴趣方向为:Excel商务图表,R语言数据可视化,地理信息数据可视化。个人公众号:数据小魔方(微信ID:datamofang),“数据小魔方”创始人。
日期与时间格式数据处理通常在数据过程中要相对复杂一些,因为其不仅涉及到不同国家表示方式的差异,本身结构也较为复杂,在R语言和Python中,存在着不止一套方法来处理日期与时间,因而做一个清洗的梳理与对比将会很有价值。
本文针对R语言与Python中常用日期与时间函数进行简要对比介绍,力求简单明了,覆盖常用的处理方法。
----------
R
---------
在R语言中,涉及到日期与时间处理的函数主要有以下四套:
as.Date()函数:
POSIXt/POSIXct函数:
chron包:
lubridate包:
前两个是R语言的base包内置函数,as.Date主要用于处理常用的日期数据(无时间),POSIXt/POSIXct函数则可以用于处理日期时间数据(同时控制时区)。lubridate包和chron包(无法控制时区)则不仅包含常用的日期与时间数据处理函数,还完善了一些日期日期计算与时区时区转换的若干函数。
Sys.Date() #当前日期 #[1] “-10-03”
date() #显示当前日期和时间
Sys.time() #显示当前日期与时间 #[1] “-10-03 14:21:07 CST”
以上三个函数是R的内建日期函数,之后的案例会频繁用到。
as.Date()
日期与时间变量的格式通常在文件导入之后就丢失了(有些特殊文件格式确实会有保留机制),导入之后会统一还原为字符串,需要我们自行根据其格式进行日期与时间格式的转换。
R语言默认的日期格式按照识别优先级,分别是”%Y-%m-%d” 或者 “%Y/%m/%d”,倘若你导入之前的日期是此种格式,那么在使用as.Date()格式进行日期转换时,便无需显式声明该日期的原始格式,软件会自动按照优先级进行匹配转换。
mydata<-as.Date(wodate);class(mydata);mydata[1] "Date"[1] "-07-13" "-07-12"wodate<-c("-07-13","-07-12");class(wodate)[1] "character"
mydata<-as.Date(wodate);class(mydata);mydata[1] "Date"[1] "-07-13" "-07-12"wodate<-c("/07/13","/07/12");class(wodate)[1] "character"
而且在月份和具体日期上并没有严格规定的占位(比如1月写成01,5日写成05,写作-7-3这种格式也是可以识别的)。
as.Date("-7-13")[1] "-07-13" as.Date("-7-3")[1] "-07-03"as.Date("/7/13")[1] "-07-13"
除了这两种可自动识别的日期写法格式之外,剩余的日期格式均需要做格式声明:
mydate<-as.Date(wodate,"%m/%d/%Y");mydate[1] "-07-13" "-07-12" wodate<-c("07|13|","07|12|")###月日年 mydate<-as.Date(wodate,"%m|%d|%Y");mydate[1] "-07-13" "-07-12" wodate<-c("07~13~","07~12~")###月日年 mydate<-as.Date(wodate,"%m~%d~%Y");mydate[1] "-07-13" "-07-12"wodate<-c("07/13/","07/12/")###月日年
可以看到,只要正确声明了原始的日期格式,as.Date()都可以完美的解析出标准日期并输出。
当你已经获得了一个标准日期格式之后,你可以通过format(date,format=) 函数进行日期元素的提取,比如你可以从标准日期中提取出年份、月份、具体日期、季度、星期、周度等。当然base包中也提供了一套简单调用函数:
years()\quarters()\months()\weekdays()\days()
#########日期格式代码:########———————————————- 代码 |值 |-------------------------------%d | 日期(十进制数) |%m | 月份(十进制数) |%b | 月份(缩略的) |%B | 月份(全称) |%y | 年(2位数) |%Y | 年(4位数) |-------------------------------
format(date,format=):
format(Sys.Date(),format="%Y") #[1] "" format(Sys.Date(),format="%y") #[1] "17" #输出月份: format(Sys.Date(),format="%b") #[1] "10月" format(Sys.Date(),format="%B") #[1] "十月" format(Sys.Date(),format="%m") #[1] "10" #输出星期: format(Sys.Date(),format="%A") #[1] "星期二" format(Sys.Date(),format="%a") #[1] "周二"# 自定义输出: format(Sys.Date(),format="%Y年%m月%d日") #[1] "10月03日"#输出年份:
直接使用内置函数提取日期:
[1] "星期二" months(Sys.Date()) #取日期对象的月份; [1] "十月" days(Sys.Date()) #提取日期对象的具体日期。 [1] 3 quarters(Sys.Date()) #提取日期对象的季度; [1] "Q4"weekdays(Sys.Date()) #取日期对象所处的周几;
使用as.Date()函数可以非常方面的输出连续 时间序列:
seq(from=as.Date("1976-07-04"),by="1 day",length=10)[1] "1976-07-04" "1976-07-05" "1976-07-06" "1976-07-07" "1976-07-08" "1976-07-09" "1976-07-10" "1976-07-11" "1976-07-12"[10] "1976-07-13"seq(from=as.Date("2000-06-01"),to=as.Date("2001-08-01"),by="2 weeks")[1] "2000-06-01" "2000-06-15" "2000-06-29" "2000-07-13" "2000-07-27" "2000-08-10" "2000-08-24" "2000-09-07" "2000-09-21"[10] "2000-10-05" "2000-10-19" "2000-11-02" "2000-11-16" "2000-11-30" "2000-12-14" "2000-12-28" "2001-01-11" "2001-01-25"[19] "2001-02-08" "2001-02-22" "2001-03-08" "2001-03-22" "2001-04-05" "2001-04-19" "2001-05-03" "2001-05-17" "2001-05-31"[28] "2001-06-14" "2001-06-28" "2001-07-12" "2001-07-26"
POSIXt/POSIXct函数:
这两个函数虽然都可以同时处理日期与时间数据,并且控制时区,但是 其内部对于日期与时间储存的格式不同,POSIXct类将日期/时间值作为1970年1月1日以来的秒数存储,而POSIXt类则将其作为一个具有秒、分、小时、日、月、年等元素的列表存储。因而POSIXct函数使用的更为频繁,这里以POSIXct函数为主进行讲解。
POSIXct函数与as.Date()函数类似,在日期输入时,默认支持的日期格式是包含月日年,由斜杠或者破折号分割。日期与时间之间用空格隔开,时间格式为小时:分钟:秒数。
/10/03
/10/03 11:56
/10/03 11:56:45
以上是三种POSIXct支持的日期输入格式。
mydata<-c("-10-03 11:56","-10-03 11:56:45")as.POSIXlt(mydata)[1] "-10-03 11:56:00 CST" "-10-03 11:56:00 CST"mydata<-c("/10/03","/10/03","/10/03 11:56","/10/03 11:56:45")as.POSIXlt(mydata)[1] "-10-03 CST" "-10-03 CST" "-10-03 CST" "-10-03 CST"
对于一些复杂的日期/时间格式,你可以通过声明正确的格式,让as.POSIXlt完成标准输出。
as.POSIXlt("03/十月/ 12:09:30",format="%d/%B/%Y %H:%M:%S")[1] "-10-03 12:09:30 CST"as.POSIXlt("03/10月/ 12:09:30",format="%d/%b/%Y %H:%M:%S")[1] "-10-03 12:09:30 CST"
备注:
(这里的月份格式是基于PC系统日期格式而定,我的系统是简体中文,所以月份对应的b、B分别表示为10月、十月,如果是英文系统,应该对应Oct、October)。
这里需要说明的是,以上通过as.POSIXlt函数输出的时间/日期格式,仍然可以使用format(date,format=)函数或者years()\quarters()\months()\weekdays()\days()进行时间与日期函数元素的提取。
因为以上格式输出多了小时、分钟、秒等,所以类似提取日期函数元素一样,内置函数中也提供了hours()\seconds()\minutes()进行小时、分钟和秒的提取。
minutes(as.POSIXlt("03/十月/ 12:09:30",format="%d/%B/%Y %H:%M:%S"))[1] 9 seconds(as.POSIXlt("03/十月/ 12:09:30",format="%d/%B/%Y %H:%M:%S"))[1] 30hours(as.POSIXlt("03/十月/ 12:09:30",format="%d/%B/%Y %H:%M:%S"))[1] 12
chron包:
chron包也提供了时间与日期函数的处理方法,但是该包最大的不同是在输出格式上比较特别,它将时间与日期作为两部分独立的对象。
library("chron")chron(dates=c("10/01/17","10/03/17"),times=c("12:30:45","15:40:02"))[1] (10/01/17 12:30:45) (10/03/17 15:40:02)
chron函数需要两个必备参数,日期部分和时间部分,日期接受的默认参数是月份(十进制)、日期值(十进制)、年份(四位或者两位),中间用“/”隔开,时间格式按照常规格式书写,用冒号隔开。当你的输入日期与时间符合以上默认格式时,可不必显式声明收入格式。当你不指定输出日期与时间格式时,默认输出格式与默认收入格式相同,日期与时间之间被组合成一个日期时间单位,中间用空格隔开。
chron(dates=c("17/10/01","17/10/03"),times=c("12:30:45","15:40:02"),format=c("y/m/d","h:m:s"))[1] (17/10/01 12:30:45) (17/10/03 15:40:02)
当你输入的日期不符合chron函数默认时间格式时,需要显式声明收入日期的格式,便于chron函数进行识别与解析,此时可不指定输出格式,输出按照默认格式输出。
chron(dates=c("17/10/01","17/10/03"),times=c("12:30:45","15:40:02"),format=c("y/m/d","h:m:s"),out.format=c("y-m-d","h:m:s"))[1] (17-10-01 12:30:45) (17-10-03 15:40:02)
当你输入格式与默认格式不符,而且同时想要自定义输出格式的时候,需要同时声明输入格式和输出格式。
mydata<-chron(dates=c("17/10/01","17/10/03"),times=c("12:30:45","15:40:02"),format=c("y/m/d","h:m:s"),out.format=c("y-m-d","h:m:s"))
同样,chron格式日期仍然可以支持format函数或者years()\quarters()\months()\weekdays()\days()\hours()\seconds()\minutes()函数的调用进行时间 与日期元素提取。
[1] "10" "10" [1] "01" "03"format(mydata,format="%Y") format(mydata,format="%m") format(mydata,format="%d") [1] "" ""
[1] 4Q 4Q[1] Oct Oct[1] Sun Tue[1] 1 3 [1] 12 15 [1] 30 40 [1] 45 2years(mydata);quarters(mydata);months(mydata);weekdays(mydata);days(mydata);hours(mydata);minutes(mydata);seconds(mydata)[1]
lubridate包:
lubridate包是著名的ggplot2作者哈德利威科姆大神写的,为了配合他的数据可视化百宝箱tidyverse一起工作。该包封装了大量简化 时间与日期操作的函数,也是我平时用于处理时间日期使用频率最高的包。
library(“lubridate”)
lubridate可以识别的日期格式非常丰富。
ymd("0604") #[1] "-06-04" mdy("06-04-") #[1] "-06-04" dmy("04/06/") #[1] "-06-04"ymd()/mdy()/dmy()#转化日期:
year() #从日期中提取年份:
year("/10/24") #[1] year("-10-24") #[1]
提取季度、月份、周、日期(支持短横杠和左斜杠表示的日期格式)
quarter()/month()/week()/day()
month("/10/24") #[1] 10 week("/10/24") #[1] 43 day("/10/24") #[1] 24quarter("/10/24") #[1] 4
提取时间元素(小时、分钟、秒)
hour()/minute()/second()
minute("-08-10 14:20:01") #[1] 20 second("-08-10 14:20:01") [1] 1hour("-08-10 14:20:01") #[1] 14
以上函数均支持向量操作(这是显而易见,毕竟R中没有标量)。
Python:
Python中的常用时间与日期处理函数除了Pandas内置的时间对象之外,还有datetime\time模块。
datetime
timestamp
Pandas
1、datetime
datetime.datetime(, 10, 3, 13, 10, 41, 477912)nowtime.strftime('%Y-%m-%d %H:%M:%S') #对该日期进行格式化输出 '-10-03 13:10:41'type(nowtime)datetime.datetimeimport datetimenowtime = datetime.datetime.now();nowtime #获取当前时间与日期
datetime.datetime.now函数可以获取当前系统的日期,该日期是一个datetime.datetime对象,内部含有年份、月份、日、小时、分钟、秒和数值化日期的信息。可以通过strftime方法输出为我们常见的日期格式。
mytime=datetime.datetime.strptime(time,'%Y-%m-%d %H:%M:%S')mytime.strftime('%Y-%m-%d %H:%M:%S') '-10-03 13:05:21'time = '-10-03 13:05:21'
如果是外部输入的日期,可以先转化为datetime.datetime对象之后,使用strftime函数进行格式输出。
mytime=datetime.datetime.strptime(time,'%m-%d-%Y %H:%M:%S')mytime.strftime('%Y-%m-%d %H:%M:%S') '-10-03 13:05:21'time = '10-03- 13:05:21'
导入的日期需要声明正确的书写格式,输出时也可以自定义输出的日期显示格式。
mytime.strftime('%m-%d-%Y %H:%M:%S')'10-03- 13:05:21'
datetime.date对象可以直接输出year、month、day、hour、minute、second属性。
10 3 13 5 21mytime.year;mytime.month;mytime.day;mytime.hour;mytime.minute;mytime.second
2、timestamp
第二类日期时间对象是timestamp,又称时间戳。
time.struct_time(tm_year=, tm_mon=10, tm_mday=3, tm_hour=13, tm_min=33, tm_sec=38, tm_wday=1, tm_yday=276, tm_isdst=0)import timetime.localtime() #获取系统当前日期:
timeArray = time.strptime(a, "%Y-%m-%d %H:%M:%S") #输入一个日期: time.struct_time(tm_year=, tm_mon=10, tm_mday=3, tm_hour=13, tm_min=40, tm_sec=0, tm_wday=1, tm_yday=276, tm_isdst=-1)otherStyleTime = time.strftime("%Y/%m/%d %H:%M:%S", timeArray);otherStyleTime #按照定义的格式输出 '/10/03 13:40:00'a = "-10-03 13:40:00"
3、pandas日期对象
import pandas as pdpandas中的date_range方法可以根据参数需要生成指定的时间序列:pandas.date_range(start=None, end=None, periods=None, freq=’D’, tz=None, normalize=False, name=None, closed=None, **kwargs)
重点关注其中的前四个参数,start表示日期起点,end表示日期终点,periods表示日期长度,freq表示日期的频率。(四个参数必须满足其中三个方可输出时间序列,freq有默认为天的从参数)。
pd.date_range('-09-25 12:59:30','-10-03 12:59:30',freq="H") pd.date_range('-09-25 12:59:30',periods=10)pd.date_range(end='-09-25 12:59:30',periods=10)pd.date_range('-09-25 12:59:30','-10-03 12:59:30')
当然Python序列处理的函数在Python中无处不在,这里仅介绍以上几个经常会用到的高频函数。想要深入了解Python中的时间序列处理模式,还是需要深入研究其源文档。
本文参考文献:
/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431937554888869fb52b812243dda6103214cd61d0c2000
/pandas-docs/stable/generated/pandas.date_range.html
在线课程请点击文末原文链接:
往期案例数据请移步本人GitHub:
/ljtyduyu/DataWarehouse/tree/master/File
公众号后台回复关键字即可学习
回复R R语言快速入门免费视频
回复统计 统计方法及其在R中的实现
回复用户画像民生银行客户画像搭建与应用
回复大数据 大数据系列免费视频教程
回复可视化 利用R语言做数据可视化
回复数据挖掘 数据挖掘算法原理解释与应用
回复机器学习R&Python机器学习入门