【问题标题】:Create new variable based on function of other variables根据其他变量的函数创建新变量
【发布时间】:2018-07-02 14:10:54
【问题描述】:

如何将整列作为参数传递给函数,然后创建一个新列作为其他两个函数的函数?例如,以this 为日期添加月份的出色功能,并以这个示例数据框为例:

df <- structure(
  list(
date = structure(
  c(
    17135,
    17105,
    17105,
    17074,
    17286,
    17317,
    17317,
    17347,
    17105,
    17317
  ),
  class = "Date"
),
monthslater = c(10,
                11, 13, 14, 3, 3, 3, 3, 4, NA)
  ),
  .Names = c("date", "monthslater"),
  row.names = c(NA, 10L),
  class = "data.frame"
)

我想创建一个新列,在其中将列 datemonthslater 中的条目传递给函数 add.months 我原以为这样会起作用:

df$newdate <- add.months(df$date, df$monthslater)

但事实并非如此。

函数的完整代码是:

add.months <- function(date,n) seq(date, by = paste(n, "months"), length = 2)[2]

【问题讨论】:

  • 我认为您的 add.months-function 没有正确添加月份。例如,在第 9 行中,newdate 应该是 2 月 28 日,而add.months 应该是 3 月 3 日。
  • @Jaap 很好发现!

标签: r function date dataframe


【解决方案1】:

使用lubridate-package 中的%m+%

library(lubridate)
df$newdate <- df$date %m+% months(df$monthslater)

给予:

> df
         date monthslater    newdate
1  2016-11-30          10 2017-09-30
2  2016-10-31          11 2017-09-30
3  2016-10-31          13 2017-11-30
4  2016-09-30          14 2017-11-30
5  2017-04-30           3 2017-07-30
6  2017-05-31           3 2017-08-31
7  2017-05-31           3 2017-08-31
8  2017-06-30           3 2017-09-30
9  2016-10-31           4 2017-02-28
10 2017-05-31           4 2017-09-30

以类似的方式,您还可以添加天数或年数:

df$newdate2 <- df$date %m+% days(df$monthslater)
df$newdate3 <- df$date %m+% years(df$monthslater)

给出:

> df
         date monthslater    newdate   newdate2   newdate3
1  2016-11-30          10 2017-09-30 2016-12-10 2026-11-30
2  2016-10-31          11 2017-09-30 2016-11-11 2027-10-31
3  2016-10-31          13 2017-11-30 2016-11-13 2029-10-31
4  2016-09-30          14 2017-11-30 2016-10-14 2030-09-30
5  2017-04-30           3 2017-07-30 2017-05-03 2020-04-30
6  2017-05-31           3 2017-08-31 2017-06-03 2020-05-31
7  2017-05-31           3 2017-08-31 2017-06-03 2020-05-31
8  2017-06-30           3 2017-09-30 2017-07-03 2020-06-30
9  2016-10-31           4 2017-02-28 2016-11-04 2020-10-31
10 2017-05-31           4 2017-09-30 2017-06-04 2021-05-31

【讨论】:

    【解决方案2】:

    或者使用基础 R:

    df$newdate <- mapply(add.months, df[[1]], df[[2]], SIMPLIFY = FALSE)
    
    > df
             date monthslater    newdate
    1  2016-11-30          10 2017-09-30
    2  2016-10-31          11 2017-10-01
    3  2016-10-31          13 2017-12-01
    4  2016-09-30          14 2017-11-30
    5  2017-04-30           3 2017-07-30
    6  2017-05-31           3 2017-08-31
    7  2017-05-31           3 2017-08-31
    8  2017-06-30           3 2017-09-30
    9  2016-10-31           4 2017-03-03
    10 2017-05-31           4 2017-10-01
    

    【讨论】:

    • mapply 在这里会更好,因为您在多个向量中逐行迭代。
    【解决方案3】:

    对于您当前的具体问题,请考虑 mapply 将这两个向量逐元素传递到定义的函数中。由于 monthslater 包含 NA,请在定义的函数中添加 tryCatch

    add.months <- function(date, n) {
      tryCatch(seq(date, by = paste(n, "months"), length = 2)[2],
               warning = function(w) return(NA),
               error = function(e) return(NA))
    }
    
    df$newdate <- as.Date(mapply(add.months, df$date, df$monthslater), origin="1970-01-01")
    df
    
    #          date monthslater    newdate
    # 1  2016-11-30          10 2017-09-30
    # 2  2016-10-31          11 2017-10-01
    # 3  2016-10-31          13 2017-12-01
    # 4  2016-09-30          14 2017-11-30
    # 5  2017-04-30           3 2017-07-30
    # 6  2017-05-31           3 2017-08-31
    # 7  2017-05-31           3 2017-08-31
    # 8  2017-06-30           3 2017-09-30
    # 9  2016-10-31           4 2017-03-03
    # 10 2017-05-31          NA       <NA>
    

    另外,请注意 author's item 涉及 2 月底,因此 #9 提前 3 天延长。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-15
      • 1970-01-01
      相关资源
      最近更新 更多