【问题标题】:Solving Leetcode SQL Question in R using plyr, dplyr and lubridate使用 plyr、dplyr 和 lubridate 解决 R 中的 Leetcode SQL 问题
【发布时间】:2021-10-22 06:22:27
【问题描述】:

我正在尝试在 R 中解决以下 Leetcode SQL 数据库问题。

问题:编写一个 R 查询,报告从今天起最多 90 天内的每个日期,该日期首次登录的用户数。假设今天是 2019-06-30。

链接到 Leetcode 问题:https://leetcode.com/problems/new-users-daily-count/

数据如下所示:

Traffic <- cbind.data.frame(user_id = c(1,1,1,2,2,3,3,3,4,4,4,5,5,5,5),
                            activity = c("login","homepage","logout","login","logout","login","jobs",
                                         "logout","login","groups","logout","login","logout","login",
                                         "logout"),
                            activity_date = c("2019-05-01","2019-05-01","2019-05-01","2019-06-21",
                                              "2019-06-21","2019-01-01","2019-01-01","2019-01-01",
                                              "2019-06-21","2019-06-21","2019-06-21","2019-03-01",
                                              "2019-03-01","2019-06-21","2019-06-21"))

我在 R 中使用 lubridate()dplyr() 尝试了两种方法

方法一:使用interval()as.period()函数。

library("lubridate")
library("plyr")
library("dplyr")
library("data.table")

Today = lubridate::ymd("2019-06-30")

Traffic %>% dplyr::filter(activity == "login") %>% dplyr::filter(lubridate::day(lubridate::as.period(lubridate::interval(Today, lubridate::ymd(activity_date)), unit = "days")) <= 90) %>%
  plyr::ddply(.(user_id), transform, rank = rank(activity_date, ties.method = "min")) %>%
                dplyr::filter(rank == 1) %>% dplyr::group_by(activity_date) %>% 
  dplyr::summarise(user_count = n())

这种方法在下面给了我错误的答案。

方法二:

Traffic %>% dplyr::filter(activity == "login") %>% dplyr::filter(abs(lubridate::day(Today) - lubridate::day(lubridate::ymd(activity_date))) <= 90 &
                                                                   abs(lubridate::month(Today) - lubridate::month(lubridate::ymd(activity_date))) < 3) %>%
  plyr::ddply(.(user_id), transform, rank = rank(activity_date, ties.method = "min")) %>%
  dplyr::filter(rank == 1) %>% dplyr::group_by(activity_date) %>% 
  dplyr::summarise(user_count = n())

这在下面给了我一个更好的答案,但结果行之一的计数错误。

正确答案如下:

我想找出方法 1 不起作用的原因以及方法 2 的第二行计数错误的原因。

【问题讨论】:

  • 你应该避免使用plyr
  • 嗨,当然!您将如何使用 dplyr 的窗口函数解决问题的排名部分?
  • 嗨,马丁,您能否更具体地说明为什么要避免使用 plyr?我发现它对于在子组中排名非常有用。是不是比 dplyr 慢,效率低?
  • 您的第一个解决方案不起作用,因为日期间隔产生负数(它们是过去的)。将比较设置为&gt;= -90 应该可以。
  • 我认为plyr 的大多数函数在dplyr 中都有类似的实现,但它们会相互屏蔽某些函数。我从来没有错过plyr

标签: r date time dplyr lubridate


【解决方案1】:

谢谢,@马丁。当我尝试在 R 中实现您的方法时,出现以下错误: enter image description here

我稍微修改了代码,现在可以使用了:

library(dplyr)
library(lubridate)

Today <- ymd("2019-06-30")

Traffic %>% 
  filter(activity == "login") %>% 
  mutate(diff = ymd(activity_date) - Today) %>% 
  group_by(user_id) %>% 
  filter(all(abs(diff) <= 90)) %>% 
  group_by(activity_date) %>%
  dplyr::summarise(user_count = n()) %>%
  dplyr::mutate(login_date = activity_date) %>% dplyr::select(login_date, user_count)

在下面给出正确答案: enter image description here

【讨论】:

  • 您可以通过将第二个 group_by 替换为 group_by(login_date = activity_date) 并删除代码的最后一行来简化代码。此外,您不需要在summarize 前面使用dplyr::plyr 是否仍然加载?也许这会导致显示的错误。
【解决方案2】:

我会使用dplyrlubridate 方法:

library(dplyr)
library(lubridate)

Today <- ymd("2019-06-30")

Traffic %>% 
  filter(activity == "login") %>% 
  mutate(diff = ymd(activity_date) - Today) %>% 
  group_by(user_id) %>% 
  filter(all(abs(diff) <= 90)) %>% 
  ungroup() %>% 
  count(activity_date)

返回

# A tibble: 2 x 2
  activity_date     n
  <chr>         <int>
1 2019-05-01        1
2 2019-06-21        2

要回答您的问题:您需要过滤掉所有最早登录日期距 2019 年 6 月 30 日超过 90 天的user_id。所以user_id需要被过滤掉。我不认为排名在这里是正确的方法,所以基本上这就是我对你两个问题的回答。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-16
    • 2022-12-03
    • 1970-01-01
    • 2022-01-12
    相关资源
    最近更新 更多