创建新列,在每行R上添加30天

时间:2014-01-10 15:53:48

标签: r transform rows

我有一个带有两个变量,名称和日期的df。我想创建一个新列(new_dates),它取第一个属于每个人的日期(每个人在此列中只有一个重复的日期),并在行下降时为每个日期添加30天。

所需的输出如下。因此每个人的row1保存原始日期,row2保存row1 + 30,row3保持row2 + 30,依此类推。

dff
   names      dates  new_dates
1   john 2010-06-01 2010-06-01
2   john 2010-06-01 2010-07-01
3   john 2010-06-01 2010-07-31
4   john 2010-06-01 2010-08-30
5   mary 2010-07-09 2010-07-09
6   mary 2010-07-09 2010-08-08
7   mary 2010-07-09 2010-09-07
8   mary 2010-07-09 2010-10-07
9    tom 2010-06-01 2010-06-01
10   tom 2010-06-01 2010-07-01
11   tom 2010-06-01 2010-07-31
12   tom 2010-06-01 2010-08-30

我以为我可以使用变换。这是我的尝试 - 但它对我不起作用。

dt <- transform(df, new_date = c(dates[2]+30, NA))

3 个答案:

答案 0 :(得分:1)

抱歉,快速阅读问题,并没有意识到你最初在做什么。

绝对是一种蛮力方法,我的编程不是,你怎么说,优雅,但它似乎给出了理想的结果:

df <- psych::read.clipboard()

df <- data.frame(names = df$names,
                 dates = as.Date(df$dates))

library(lubridate)


tmp <- unlist(lapply(unique(df$names), function(x) {
                  tmp <- df[df$names == x, 2, drop = FALSE]
                  sapply(1:dim(tmp)[1], function(y) {
                    tmp[1, 1] + days(30) * (y - 1)
                    })
                } ))

df$new_dates <- as.Date(tmp, origin = '1970-01-01')

> df
   names      dates  new_dates
1   john 2010-06-01 2010-06-01
2   john 2010-06-01 2010-07-01
3   john 2010-06-01 2010-07-31
4   john 2010-06-01 2010-08-30
5   mary 2010-07-09 2010-07-09
6   mary 2010-07-09 2010-08-08
7   mary 2010-07-09 2010-09-07
8   mary 2010-07-09 2010-10-07
9    tom 2010-06-01 2010-06-01
10   tom 2010-06-01 2010-07-01
11   tom 2010-06-01 2010-07-31
12   tom 2010-06-01 2010-08-30

答案 1 :(得分:1)

data.table让这很容易。转换为数据表后,它基本上就是一个命令。您的版本遇到的主要问题是您需要先按名称拆分数据,这样您就可以获得每个人的最短日期,然后在每个日期添加适当的30天。

library(data.table)
df$dates <- as.Date(df$dates)
dt <- as.data.table(df)
dt[, 
   list(dates, new_dates=min(dates) + 0:(length(dates) - 1L) * 30), 
   by=names
]
#     names      dates  new_dates
#  1:  john 2010-06-01 2010-06-01
#  2:  john 2010-06-01 2010-07-01
#  3:  john 2010-06-01 2010-07-31
#  4:  john 2010-06-01 2010-08-30
#  5:  mary 2010-07-09 2010-07-09
#  6:  mary 2010-07-09 2010-08-08
#  7:  mary 2010-07-09 2010-09-07
#  8:  mary 2010-07-09 2010-10-07
#  9:   tom 2010-06-01 2010-06-01
# 10:   tom 2010-06-01 2010-07-01
# 11:   tom 2010-06-01 2010-07-31
# 12:   tom 2010-06-01 2010-08-30

编辑:这是一个版本,希望能说明你的工作原因。我仍然更喜欢data.table,但希望因为这基本上非常接近你正在做的事情,所以它清楚地说明你需要改变什么:

re_date <- function(df) {
  transform(
    df[order(df$dates), ], 
    new_dates=min(dates) + 30 * 0:(length(dates) - 1L)
) }
do.call(rbind, lapply(split(df, df$name), re_date))

从底线(do.call...)开始,split调用会生成一个包含三个数据框的列表,一个包含John的值,一个用于Mary的值,另一个用于Tom的值。然后,lapply会通过re_date函数运行每个数据框,这会添加new_dates列,最后do.call / rbind将其重新拼接一起成为一个数据框架。

答案 2 :(得分:0)

你正在寻找的东西对我来说有点混乱。我假设您从一个看起来像这样的小数据框开始:

> df <- data.frame(names=c("john","mary","tom"),dates=c(as.Date("2010-06-01"),as.Date("2010-07-09"),as.Date("2010-06-01")))
> df
  names      dates
1  john 2010-06-01
2  mary 2010-07-09
3   tom 2010-06-01

然后想要在数据框中添加N行,这些行包含新的日期列。如果是这样,我确信有一些预先打包的方法可以执行此操作,但您也可以使用两个嵌套的lapply()调用。最里面的调用只是添加一个新列,其中newdates被设置为30的倍数加上你的原始日期,然后最外面的调用将以30的倍数传递。例如:

> do.call(rbind,lapply(30*0:3,function(y) do.call(rbind,lapply(1:nrow(df),function(x) data.frame(names=df$names[x],dates=df$dates[x],newdates=df$dates[x]+y)))))
   names      dates   newdates
1   john 2010-06-01 2010-06-01
2   mary 2010-07-09 2010-07-09
3    tom 2010-06-01 2010-06-01
4   john 2010-06-01 2010-07-01
5   mary 2010-07-09 2010-08-08
6    tom 2010-06-01 2010-07-01
7   john 2010-06-01 2010-07-31
8   mary 2010-07-09 2010-09-07
9    tom 2010-06-01 2010-07-31
10  john 2010-06-01 2010-08-30
11  mary 2010-07-09 2010-10-07
12   tom 2010-06-01 2010-08-30

无论如何,这种方法并不理想,可能会令人困惑,所以请告诉我这是否是您正在寻找的内容,我可以提供有关正在发生的事情的更多详细信息。