【发布时间】:2019-09-29 14:54:32
【问题描述】:
我想实现以下目标:
- 根据数据框 orders 中的多列过滤数据框 catalogs,针对数据框 orders 中的每一行,并将结果存储在数据框订单。 (成功)
- 计算数据框 orders 中的日期与新列表列中的另一个日期之间的差异。
表s_orders 包含不同人的订单数据(帐户密钥)。表s_catalogs 包含发送到每个帐户密钥的所有目录
对于每个订单,我都想知道:
- 是否以及从前一个订单(或开始)到焦点订单前一天发送了哪些目录。更具体地说,消费者在
s_catalogs$CATDATE收到了一份(纸质)目录。我想知道每个订单在上一个订单 (s_orders$PREVORDER) 和最新订单之间收到了哪些目录。因为一些消费者没有之前的订单,所以我将之前的订单日期 startdate 设置为 date("1999-12-31"),这是我的数据集的开始。 - 然后我想对目录数据做一些计算。 (在本例中:计算目录日期和订单日期之间的差异)
为此,我编写了一个函数getCatalogs,它将帐户密钥和两个日期作为输入,并输出一个包含另一个表结果的数据框。 如果有人有更好、更有效的解决方案,将不胜感激?也许有某种加入?
我认为我的主要问题是如何交替使用 mutate、pmap、管道、pluck 来在多个表上构建复杂的查询。
期望结果和问题部分概述了我的实际问题。
# packages needed
library("dplyr")
library("lubridate")
library("purrr")
#library("tidyverse")
示例数据
(我从我的数据中抽取了一些用户。s_ 代表“样本”)
# orders
s_orders <- structure(list(ACCNTKEY = c(2806, 2806, 2806, 3729, 3729, 3729,
3729, 4607, 4607, 4607, 4607, 4742, 11040, 11040, 11040, 11040,
11040, 17384), ORDDATE = structure(c(11325, 11703, 11709, 11330,
11375, 11384, 12153, 11332, 11445, 11589, 11713, 11333, 11353,
11429, 11662, 11868, 11960, 11382), class = "Date")), class = c("tbl_df",
"tbl", "data.frame"), row.names = c(NA, -18L))
# # A tibble: 18 x 2
# ACCNTKEY ORDDATE
# <dbl> <date>
# 1 2806 2001-01-03
# 2 2806 2002-01-16
# 3 2806 2002-01-22
# 4 3729 2001-01-08
# 5 3729 2001-02-22
# 6 3729 2001-03-03
# 7 3729 2003-04-11
# 8 4607 2001-01-10
# 9 4607 2001-05-03
# 10 4607 2001-09-24
# 11 4607 2002-01-26
# 12 4742 2001-01-11
# 13 11040 2001-01-31
# 14 11040 2001-04-17
# 15 11040 2001-12-06
# 16 11040 2002-06-30
# 17 11040 2002-09-30
# 18 17384 2001-03-01
# catalogs
s_catalogs <- structure(list(ACCNTKEY = c("2806", "2806", "4607", "2806", "4607",
"4607", "4607"), CATDATE = structure(c(11480, 11494, 11522, 11858,
11886, 12264, 12250), class = "Date"), CODE = c("2806/07/2001",
"2806/21/2001", "4607/19/2001", "2806/20/2002", "4607/18/2002",
"4607/31/2003", "4607/17/2003")), row.names = c(NA, -7L), class = c("tbl_df",
"tbl", "data.frame"))
# # A tibble: 7 x 3
# ACCNTKEY CATDATE CODE
# <chr> <date> <chr>
# 1 2806 2001-06-07 2806/07/2001
# 2 2806 2001-06-21 2806/21/2001
# 3 4607 2001-07-19 4607/19/2001
# 4 2806 2002-06-20 2806/20/2002
# 5 4607 2002-07-18 4607/18/2002
# 6 4607 2003-07-31 4607/31/2003
# 7 4607 2003-07-17 4607/17/2003
计算滞后订单日期
# calculate previous order date for each order in s_orders
s_orders<-s_orders %>%
group_by(ACCNTKEY) %>%
arrange(ORDDATE) %>%
mutate(PREVORDER=as_date(lag(ORDDATE)))
所以现在我们知道了之前的顺序(如果有的话)
函数 getCatalogs(感谢改进)
因此,以下函数 getCatalogs 返回一个数据帧,其中包含该帐户密钥在订单之前(或实际上在 startdate 和 之间收到的最后一个订单/目录之间收到的目录结束日期)。
# in case _startdate_ is missing then I set it to some starting value
getCatalogs<-function(key,startdate,enddate){
if(is.na(startdate)){
startdate<-as_date(date("1999-12-31"))
}
tmp <- s_catalogs[s_catalogs$ACCNTKEY==key &
s_catalogs$CATDATE<enddate &
s_catalogs$CATDATE>=startdate,]
if (NROW(tmp)>0){
return(tmp)
}else{return(NA)}
}
使用函数
让我们在 listcolumn
中为每个订单获取所有目录# For each row in s_orders search in dataframe s_catalogs all catalogs that were received for that account key before the order date but after the previous order.
s_orders <- s_orders %>% as_tibble() %>%
mutate(catalogs =
pmap(c(list(ACCNTKEY),list(PREVORDER),list(ORDDATE)),.f= function(x,y,z){getCatalogs(x,y,z)}))
此行例如获取最新目录的日期,这是我需要的:
s_orders %>% pluck("catalogs") %>% pluck(13) %>% pluck("CATDATE") %>% max()
# [1] "2001-06-21"
想要的结果:
现在我想检索上述日期与订单日期 (ORDDATE) 之间的天数。 以下代码完全正确,但仅在第 13 行是正确的。
# get amount of days since last catalog
s_orders3 <- s_orders %>%
mutate(diff = ORDDATE - s_orders %>%
pluck("catalogs") %>% pluck(13) %>% pluck("CATDATE") %>% max())
# # A tibble: 18 x 5
# ACCNTKEY ORDDATE PREVORDER catalogs diff
# <dbl> <date> <date> <list> <time>
# 1 2806 2001-01-03 NA <lgl [1]> -169 days
# 2 3729 2001-01-08 NA <lgl [1]> -164 days
# 3 4607 2001-01-10 NA <lgl [1]> -162 days
# 4 4742 2001-01-11 NA <lgl [1]> -161 days
# 5 11040 2001-01-31 NA <lgl [1]> -141 days
# 6 3729 2001-02-22 2001-01-08 <lgl [1]> -119 days
# 7 17384 2001-03-01 NA <lgl [1]> -112 days
# 8 3729 2001-03-03 2001-02-22 <lgl [1]> -110 days
# 9 11040 2001-04-17 2001-01-31 <lgl [1]> -65 days
# 10 4607 2001-05-03 2001-01-10 <lgl [1]> -49 days
# 11 4607 2001-09-24 2001-05-03 <tibble [1 × 3]> 95 days
# 12 11040 2001-12-06 2001-04-17 <lgl [1]> 168 days
# 13 2806 2002-01-16 2001-01-03 <tibble [2 × 3]> 209 days
# 14 2806 2002-01-22 2002-01-16 <lgl [1]> 215 days
# 15 4607 2002-01-26 2001-09-24 <lgl [1]> 219 days
# 16 11040 2002-06-30 2001-12-06 <lgl [1]> 374 days
# 17 11040 2002-09-30 2002-06-30 <lgl [1]> 466 days
# 18 3729 2003-04-11 2001-03-03 <lgl [1]> 659 days
手动检查:
date("2002-01-16")-date("2001-06-21")
# Time difference of 209 days
问题
但是,代码会从每一行的订单日期中减去相同的日期。我希望它使用属于每个特定行的日期。
所以问题是如何用一些命令替换%>% pluck(13) %>%,该命令将此技巧应用于每一行并将其放在差异列中。
我真的在寻找一种使用 purrr 或 dplyr 或其他同样高效和清晰的软件包的解决方案。
【问题讨论】:
-
感谢您为解决问题所做的大量工作,但如果您可以隔离您遇到的问题,我们可能更容易提供帮助(也可能让您进行调试) ,可能分成单独的问题,或者将其缩减为问题的基本部分。请参阅minimal reproducible example 的 minimal 部分
-
@camille tnx 为您提供反馈!最小的问题在“期望的结果”和“问题”部分。您将需要以上的一切。当然,我可以删除“我试过”部分中的所有内容。然而,这些失败的尝试可能会为答案提供指导。
-
您能否详细说明一下?:“是否以及从上一个订单(或开始)到焦点订单前一天发送了哪些目录”
-
亲爱的@VitaliAvagyan,我刚刚更新了这篇文章,对此进行了一些详细说明。感谢您指出这一点!
-
感谢您的编辑,@Dr.T. ,我会试一试...
标签: r dictionary dplyr pipe purrr