使用R?计算观察值在数据集中存在的次数。 (具有多个条件)

时间:2019-05-19 14:48:50

标签: r

因此,我有大约2800个观测值的数据集。标头看起来像这样:

ItemName ItemNumber PromotedDate
ItemA    14321      12/31/2018
ItemB    14335      11/18/2018
ItemC    14542      10/05/2018

我希望能够向该数据集Number.Times.Promoted.Last.3.Months添加一个新列,该列将计算在PromotedDate变量的最后三个月中数据集中每个项目存在多少次。 / p>

我尝试创建一些代码(如下),但是每行返回0。当我尝试使用商品编号进行尝试时,我得到了整个数据集中的观测数量。

df$Number.Times.Promoted.Last.Three.Months <- sum(df$ItemNumber == df$ItemNumber & 
                                                    df$PromotedDate < df$PromotedDate & 
                                                    df$PromotedDate > (as.Date(df$PromotedDate - 100)),
                                                  na.rm=TRUE)))

我很想让代码返回自PromotedDate变量以来过去3个月中提升数据集中每个项目的实际次数,并将其附加到数据的每一行(df)。希望能帮助您找出我做错了什么。谢谢!

2 个答案:

答案 0 :(得分:0)

注意:在链接的文件中有一个错字,第一个ItemB以小写的i开始。即使未更正,下面的代码也可以工作。

我发现以下解决方案有点复杂,但是确实可以解决问题。

library(lubridate)

fun <- function(x){
  ifelse(month(x) == 12 & day(x) == 31,
         x - days(31 + 30 + 31),
         x - months(3)
  )
}

df <- readxl::read_xlsx("example_20190519.xlsx")
df$PromotedDate <- as.Date(df$PromotedDate)

sp <- split(df, tolower(df$ItemName))
res <- lapply(sp, function(DF){
  tmp <- as.Date(fun(DF$PromotedDate), origin = "1970-01-01")
  sapply(seq_len(nrow(DF)), function(i){
    sum(DF$PromotedDate[i] > DF$PromotedDate & DF$PromotedDate > tmp[i])
  })
})

df$New.3.Months <- NA
for(nm in names(res)) {
  df$New.3.Months[tolower(df$ItemName) == nm] <- res[[nm]]
}

现在测试以查看结果是否与示例.xlsx文件中的结果相同。

all.equal(df$Times.Promoted.Last.3.Months, df$New.3.Months)
#[1] TRUE

最后的清理。

rm(sp)

答案 1 :(得分:0)

这是一个可以简化的解决方案,它依赖于dplyrfuzzyjoin

首先,我将日期定义为90天前**,然后将其与列表本身一起加入,并在每个商品匹配中输入促销日期为“自90天之前”和“直到当前日期”的促销日期。每个项目日期的行数是90天内的促销数量。通过减去代表自己的行,我们可以得出先前促销的次数。

**“提前90天”比“提前3mo”更简单,长度各不相同,并且在某些日期可以争论:5月30日之前的3个月是什么?

预备

library(dplyr); library(fuzzyjoin); library(lubridate)
df <- readxl::read_excel(
  "~/Downloads/example_20190519.xlsx", 
  col_types = c("text", "numeric", "date", "numeric"))
df_clean <- df %>% select(-Times.Promoted.Last.3.Months)

解决方案

df_clean %>%
  mutate(PromotedDate_less90 = PromotedDate - days(90)) %>%

  # Pull in all matches (including current row) with matching Item and Promoted Date 
  #   that is between Promoted Date and 90 days prior.
  fuzzy_left_join(df_clean, 
                  by = c("ItemName" = "ItemName",
                         "ItemNumber" = "ItemNumber",
                         "PromotedDate_less90" = "PromotedDate",
                         "PromotedDate" = "PromotedDate"),
                  match_fun = list(`==`, `==`, `<=`, `>=`)
                  ) %>%
  group_by(ItemName     = ItemName.x, 
           ItemNumber   = ItemNumber.x, 
           PromotedDate = PromotedDate.x) %>%
  summarize(promotions_in_prior_90d = n() - 1) %>%
  ungroup()

输出(顺序不同,但目标匹配)

# A tibble: 12 x 4
   ItemName ItemNumber PromotedDate        promotions_in_prior_90d
   <chr>         <dbl> <dttm>                                <dbl>
 1 ItemA         10021 2018-09-19 00:00:00                       0
 2 ItemA         10021 2018-10-15 00:00:00                       1
 3 ItemA         10021 2018-11-30 00:00:00                       2
 4 ItemA         10021 2018-12-31 00:00:00                       2
 5 itemB         10024 2018-12-15 00:00:00                       0
 6 ItemB         10024 2018-04-02 00:00:00                       0
 7 ItemB         10024 2018-06-05 00:00:00                       1
 8 ItemB         10024 2018-12-01 00:00:00                       0
 9 ItemC         19542 2018-07-20 00:00:00                       0
10 ItemC         19542 2018-11-17 00:00:00                       0
11 ItemC         19542 2018-12-01 00:00:00                       1
12 ItemC         19542 2018-12-14 00:00:00                       2