分享

数据挖掘专题 | 计算生存时间

 生物_医药_科研 2019-01-17

需求

假设有一组患者,确诊时间是2017/5/26、2017/10/26、2016/11/10、2014/5/1、2018/8/1, 最后一次随访日期是2019-01-15,患者均存活,如何计算存活时间(天)?

我们首先想到的是用减法,但是有两个问题:

1、数据读取在R中时,日期是以字符串的形式存在的,不能直接用于相减:

  1. start_time = c('2017/5/26', '2017/10/26', '2016/11/10', '2014/5/1', '2018/8/1')

  2. end_time = '2019-01-15'

2、如何根据真实的日历,正确得到天数!

基础用法

日期值通常以字符串的形式输入到R中,基础函数 as.Date() 可以用于将其转换为Date类型:

  1. as.Date('02-15-2019')

Error in charToDate(x) : 字符串的格式不够标准明确

报错,是因为默认输入的日期顺序为yyyy-mm-dd,即年-月-日,非该顺序时需要准确设置年、月和日在日期数据中的真实顺序:

  1. as.Date('02-15-2019', '%m-%d-%Y')    # 月-日-年

[1] '2019-02-15'

注意,字段中间的链接符也要求与输入一致,否则会由于无法正确识别而返回NA,如下:

  1. as.Date('02-15-2019', '%m/%d/%Y')

[1] NA

其他常用的函数:

Sys.Date()可以返回当天的日期(年-月-日)

[1] '2019-01-15'

date()获取当前的具体时间

[1] 'Tue Jan 15 11:47:58 2019'

如上,测试的日期是2019年1月15日 周二,时间是中午11:47:58

进一步的,我们可以从日期数据中获取信息:

  1. as.numeric(format(Sys.Date(), '%m'))    # 当前的月份

相较而言,lubridate包中有一种更简单的提取方法:

  1. month(Sys.Date())

[1] 1

lubridate

https://lubridate./

lubridate包简化了日期/时间数据处理,可以用于读取解析提取日期/时间内容(例如年份、 月份、时间等),以及进行算术运算

Date-time data can be frustrating to work with in R. R commands for date-times are generally unintuitive and change depending on the type of date-time object being used.Lubridate makes it easier to do the things R does with date-times and possible to do the things R does not.

使用说明:

https://cran./web/packages/lubridate/vignettes/lubridate.html

参考手册:

https:///rstudio/cheatsheets/master/lubridate.pdf

安装加载:

  1. p_load(lubridate)

lubridate包中也有类似 Sys.Date()date() 的函数:

  1. today()

[1] '2019-01-15'

  1. now()

[1] '2019-01-15 19:38:57 CST'

as_date(now()) 将日期时间型数据转换为日期型,即只保留年月日信息!

读取/解析


使用lubridate包中的函数读取日期'2019-02-15',只需要明确年(y)月(m)日(d)的顺序,然后按照同样的顺序排列字母 y、m 和 d, 组成能够解析日期的 lubridate 函数名称。

Identify the order in which the year, month, and day appears in your dates. Now arrange 'y', 'm', and 'd' in the same order. This is the name of the function in lubridate that will parse your dates.

  1. mdy('02-15-2019')    # mdy表示日期的顺序为月-日-年

同理,其他顺序的读取:

  1. ymd(20190215)

  2. dmy('15/02/2019')

  3. dmy('15-Feb-2019')

  4. mdy('February, 15th, 2019')

[1] '2019-02-15'

可见,输入数据的格式更加灵活。支持不带引号的数值!

注意,如果年月日顺序与设定不一致,则会返回NA且报出警告:

[1] NAWarning message:All formats failed to parse. No formats found.

如果输入的是日期时间型数据,即包含小时(h)分(m)秒(s)信息,则在其后加一个下划线,以及 h、m 和 s 之中的一个或多个字母,如下:

  1. ymd_hms('2019-02-15 11:47:58')

[1] '2019-02-15 11:47:58 UTC'

提取


lubridate包可以很方便的提取日期时间数据中的信息:

  1. date = ymd_hms('2019-02-15 11:47:58')

  2. second(date)    # 58,即58秒

  3. minute(date)    # 47,即47分

  4. hour(date)        # 11,即11点

  5. month(date)        # 2,即2月

  6. day(date)    # 15,即15号

  7. wday(date)    # 6,即一周的第6天,默认周日为1,所以是周五

    mday(date)    # 15,即一个月中的第15天

  8. yday(date)    # 46,即一年的第46天

  9. week(date)    # 7,即一年的第7周(从2019-01-01开始)

  10. year(date)    # 2019,即2019年

  11. tz(date)    # 'UTC'时区

同时,支持直接对原日期时间内容进行修改:

  1. month(date) = 1

  2. date

[1] '2019-01-15 11:47:58 UTC'

除了修改原变量,还可以通过 update 函数生成一个新的日期时间:

  1. update(date, year = 2020, month = 2, mday = 2, hour = 2)

[1] '2020-02-02 02:47:58 UTC'

进一步的,可以对年、季、月、日、时等进行舍入取整操作:

Valid base units are 'second', 'minute', 'hour', 'day', 'week', 'month', 'bimonth', 'quarter', 'season', 'halfyear' and 'year'.

  1. round_date(date, 'hour')    # 在小时水平四舍五入

[1] '2019-01-15 12:00:00 UTC'

floor_date()ceiling_date()分别用于向下和向上取整!

  1. floor_date(date, 'month')    # 对月份向下取整

[1] '2019-01-01 UTC'

计算


对日期数据的数学运算包括减法、加法和除法。其中最常见的可能就是计算两个时间点之间的时间间隔(Time Intervals)了:

  1. interval(ymd('19900101'), today())    # 新的日期在后

[1] 1990-01-01 UTC--2019-01-15 UTC

计算两者之间相差的天数,最直接的:

  1. today() - ymd('19900101')

Time difference of 10606 days

也可以使用基础函数 difftime,其units参数默认单位为天,但能设置为'secs', 'mins', 'hours', 'days', 'weeks':

  1. difftime(today(), ymd(19900101), units = 'weeks')

但是不能设置为'month' 和 'year'!

difftime() handles all time units up to weeks.

如果想要获取间隔的年数

  1. year(today()) - year(ymd('19900101'))    # 29

或者使用lubridate包中的 time_length 函数,默认以秒为单位计算间隔的时间长度,可以通过unit参数设置为其它单位。与 difftime 中units参数设置不同的地方在于支持'month' 和 'year',如下:

a  age_years = time_length(today()-ymd('19900101'), 'year')   # 返回年龄,以年为单位

  trunc(age_years)        # 取整(朝0的方向)

  # 等同于

  trunc(time_length(interval(ymd('19900101'), today()), 'years'))

答案

现在,我们可以来解决文章开头的需求:

方法1:

  1. as.numeric(as.Date(end_time, '%Y-%m-%d') - as.Date(start_time, '%Y/%m/%d'))

方法2:

didifftime(ymd(end_time), ymd(start_time), 'days')

方法3:

time_length(ymd(end_time)-ymd(start_time), 'days')

这里,我们只列出了三种,但实际上通过本文,可以写出更多变体的解决方案哦!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多