【问题标题】:Filter data.frame by date range in R在R中按日期范围过滤data.frame
【发布时间】:2017-12-28 13:44:11
【问题描述】:

我有一个这样的 DF:

Date <- c("10/17/17","11/11/17","11/23/17","11/25/17","12/3/17","12/10/17","12/16/17")
Ben <- c("1294",NA,"8959","2345",NA,"0303",NA)
James <- c(NA,"4523","3246",NA,"2394","8877","1427")
Alex <- c("3754","1122","5582",NA,"0094",NA,NA)
df1 <- data.frame(Date,Ben,James,Alex)

#df1
Date          Ben     James     Alex
10/17/17      1294    NA        3754
11/11/17      NA      4523      1122
11/23/17      8959    3246      5582
11/25/17      2345    NA        NA
12/3/17       NA      2394      0094
12/10/17      0303    8877      NA
12/16/17      NA      1427      NA

如您所见,DF 是按日期排序的。我正在尝试将每列的最新日期后 2 周内的值放入新的 DF 中,如下所示:

#df2
Ben     James     Alex
0303    1427      0094
NA      8877      5582
NA      2394      NA

Ben 只有一个列出的值,因为在 2017 年 12 月 10 日的 2 周内只有一个非 NA 值,这是 Ben 的列中具有非 NA 值的最新日期。詹姆斯最近的非北美日期是 17 年 12 月 16 日。他的三个值都在该日期的两周内:1427、8877 和 2394。Alex 的最新日期是 12/3/17。他在最近日期的两周内有两个值:0094 和 5582。新 data.frame 的行数应该等于最长的列。在各自的两周范围内条目较少的列应使用 NA 来填充数据,例如 Ben 的列。

我目前正在使用以下代码,它只是过滤每列中的最后 3 个非 NA:

df2 &lt;- lapply(df1[-1], function(x) tail(x[!is.na(x)], n = 3))

【问题讨论】:

  • 请以可重现的方式分享您的数据集(使用dput 函数)。
  • 您能否给出您希望从上面的示例中看到的完整输出?我还看到日期11/23/1711/29/17 在两周之内,11/29/1712/10/17 也在两周之内,但12/10/1711/23/17 不在两周之内。所以请说明你的确切日期需要以及你如何需要它
  • df2 代表我正在寻找的基于 df1 中给出的数据的完整输出。

标签: r


【解决方案1】:

使用基数 r 作为子集:

lapply(df1[-1],function(x)x[which((m<-tail(df1$Date[!is.na(x)],1)-df1$Date)>=0&m<=14)])->result
max(lengths(result))->len 
do.call(cbind.data.frame,lapply(result,`length<-`,len))

    Ben James Alex
1 <NA>  2394 5582
2 0303  8877 <NA>
3 <NA>  1427 0094

我刚刚意识到这些是根据您提供的数据编码为字符的

要完全符合预期结果,我们将:

 do.call(cbind.data.frame,lapply(result,function(x) `length<-`(rev(x),len)))
  Ben James Alex
1 0303  1427 0094
2 <NA>  8877 <NA>
3 <NA>  2394 5582

【讨论】:

  • 这很接近,但从所有列的最新日期的两周内获取数据,这不是我想要的。 Alex 的数据应该包括 0094 和 5582,因为这两个数据都在他最近的数据点 0094 的 2017 年 11 月 29 日的两周内。我正在尝试这样的事情,但无法让它工作:df2 &lt;- lapply(df1[-1],function(x) subset(df1,(tail(Date,1)-Date&lt;=14)))
  • 我现在明白你的意思了
  • 这似乎只列出了两行数据:两周范围内的第一行或最后一行。虽然我提供的示例数据在输出中没有多于两行的列,但我的实际数据可以生成多于两行的输出。
  • 那么在这种情况下,我想你将不得不给出一个不同的例子来满足你的需求。因为这里我们确实产生了所需的输出
  • 我已经更新了我的数据。请注意输出如何忽略了 James 的“8877”,因为它只显示日期范围内的第一个和最后一个条目,而“8877”落在第一个和最后一个之间的日期。我不太确定如何解决这个问题。
【解决方案2】:

无论我是否充分理解您要查找的内容,以下代码都会对您有所帮助:

我已经加载了你的数据集(带有dput 函数)

dataset <- structure(list(Date = structure(c(17456, 17481, 17493, 17495, 
17499, 17510, 17516), class = "Date"), Ben = c(1294L, NA, 8959L, 
2345L, NA, 303L, NA), James = c(NA, 4523L, 3246L, NA, NA, 8877L, 
1427L), Alex = c(3754L, 1122L, 5582L, NA, 94L, NA, NA)), .Names = c("Date", 
"Ben", "James", "Alex"), row.names = c(NA, -7L), class = "data.frame")

然后加载以下包:

library(lubridate)
library(tidyverse)

修复last_date并将格式更改为Date变量:

last_date <- mdy("12/16/17")
dataset$Date <- mdy(dataset$Date)

现在,让我们只选择你想要的行:

dataset_filtered <- dataset %>% 
    filter(Date<=last_date & Date>=(last_date-days(14)))

你将拥有:

        Date Ben James Alex
1 2017-12-10 303  8877   NA
2 2017-12-16  NA  1427   NA

请下次使用dput 函数,不一定是圣诞节 ;-)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-17
    • 1970-01-01
    • 2021-05-25
    • 2018-06-19
    相关资源
    最近更新 更多