【问题标题】:How can I use mutate to create a new column based only on a subset of other rows of a data frame?如何使用 mutate 仅基于数据框其他行的子集创建新列?
【发布时间】:2019-03-31 12:25:55
【问题描述】:

我正在为如何表达我的问题而苦恼。我有一个帐户数据框,我想创建一个新列,用于标记在该帐户的 30 天内是否有另一个帐户具有重复的电子邮件。

我有一张这样的桌子。

AccountNumbers <- c(3748,8894,9923,4502,7283,8012,2938,7485,1010,9877)
EmailAddress <- c("John@gmail.com","John@gmail.com","Alex@outlook.com","Alan@yahoo.com","Stan@aol.com","Mary@outlook.com","Adam@outlook.com","Tom@aol.com","Jane@yahoo.com","John@gmail.com")

Dates <- c("2018-05-01","2018-05-05","2018-05-10","2018-05-15","2018-05-20",
       "2018-05-25","2018-05-30","2018-06-01","2018-06-05","2018-06-10")

df <- data.frame(AccountNumbers,EmailAddress,Dates)

print(df)

AccountNumbers     EmailAddress      Dates
3748           John@gmail.com    2018-05-01
8894           John@gmail.com    2018-05-05
9923           Alex@outlook.com  2018-05-10
4502           Alan@yahoo.com    2018-05-15
7283           Stan@aol.com      2018-05-20
8012           Mary@outlook.com  2018-05-25
2938           Adam@outlook.com  2018-05-30
7485           Tom@aol.com       2018-06-01
1010           Jane@yahoo.com    2018-06-05
9877           John@gmail.com    2018-06-10 

John@gmail.com 出现了 3 次,我想标记前两行,因为它们都在 30 天内出现,但我不想标记第三行。

AccountNumbers     EmailAddress      Dates        DuplicateEmailFlag
3748           John@gmail.com    2018-05-01                  1
8894           John@gmail.com    2018-05-05                  1
9923           Alex@outlook.com  2018-05-10                  0
4502           Alan@yahoo.com    2018-05-15                  0
7283           Stan@aol.com      2018-05-20                  0
8012           Mary@outlook.com  2018-05-25                  0
2938           Adam@outlook.com  2018-05-30                  0
7485           Tom@aol.com       2018-06-01                  0
1010           Jane@yahoo.com    2018-06-05                  0
9877           John@gmail.com    2018-06-10                  0

我一直在尝试在 mutate 中使用 ifelse(),但我不知道是否可以告诉 dplyr 只考虑在考虑行的 30 天内的行。

编辑:为了澄清,我想看看每个帐户周围的 30 天。因此,如果我有这样一个场景,即每 30 天恰好添加一次相同的电子邮件地址,那么该电子邮件的所有出现都应该被标记。

【问题讨论】:

  • 您要搜索的 dplyr 函数是 group_by()。这是 dplyr 包的一个非常强大且基本的功能,您会发现自己经常使用它。我也会写一个解决方案,除非有人打败我。
  • 我很清楚 'group_by()' 并且经常在很多事情上使用它。据我了解如何使用它,它对我没有帮助,因为每个日期的组都会有所不同。如果在 30 天内存在相同的电子邮件,我想添加一个标志。因此,如果我有这样一个场景,即每 30 天恰好添加一次相同的电子邮件地址,那么它每次都会被标记。
  • 您希望按 EmailAddress 列进行分组。看起来其他人已经给了你很好的答案。

标签: r dplyr


【解决方案1】:

似乎有效。首先,我定义了数据框。

AccountNumbers <- c(3748,8894,9923,4502,7283,8012,2938,7485,1010,9877)
EmailAddress <- c("John@gmail.com","John@gmail.com","Alex@outlook.com","Alan@yahoo.com","Stan@aol.com","Mary@outlook.com","Adam@outlook.com","Tom@aol.com","Jane@yahoo.com","John@gmail.com")

Dates <- c("2018-05-01","2018-05-05","2018-05-10","2018-05-15","2018-05-20",
           "2018-05-25","2018-05-30","2018-06-01","2018-06-05","2018-06-10")

df <- data.frame(number = AccountNumbers, email = EmailAddress, date = as.Date(Dates))

接下来,我通过电子邮件进行分组,并检查前 30 天或后 30 天内是否有条目。我还将NAs(对应于只有一个条目的案例)替换为0。最后,我取消分组。

df %>% 
  group_by(email) %>% 
  mutate(dupe = coalesce(date - lag(date) < 30, (date - lead(date) < 30))) %>% 
  mutate(dupe = replace_na(dupe, 0)) %>% 
  ungroup

这给了,

# # A tibble: 10 x 4
#    number email            date        dupe
#     <dbl> <fct>            <date>     <dbl>
#  1   3748 John@gmail.com   2018-05-01     1
#  2   8894 John@gmail.com   2018-05-05     1
#  3   9923 Alex@outlook.com 2018-05-10     0
#  4   4502 Alan@yahoo.com   2018-05-15     0
#  5   7283 Stan@aol.com     2018-05-20     0
#  6   8012 Mary@outlook.com 2018-05-25     0
#  7   2938 Adam@outlook.com 2018-05-30     0
#  8   7485 Tom@aol.com      2018-06-01     0
#  9   1010 Jane@yahoo.com   2018-06-05     0
# 10   9877 John@gmail.com   2018-06-10     0

根据需要。


编辑:这隐含地假设您的数据按日期排序。如果没有,您需要添加一个额外的步骤来执行此操作。

【讨论】:

    【解决方案2】:

    我认为这得到了你想要的:

    df %>% 
      group_by(EmailAddress) %>%
      mutate(helper = cumsum(coalesce(if_else(difftime(Dates, lag(Dates), 'days') <= 30, 0, 1), 0))) %>%
      group_by(EmailAddress, helper) %>%
      mutate(DuplicateEmailFlag = (n() >= 2)*1) %>%
      ungroup() %>%
      select(-helper)
    
    # A tibble: 10 x 4
       AccountNumbers EmailAddress     Dates      DuplicateEmailFlag
                <dbl> <chr>            <date>                  <dbl>
     1           3748 John@gmail.com   2018-05-01                  1
     2           8894 John@gmail.com   2018-05-05                  1
     3           9923 Alex@outlook.com 2018-05-10                  0
     4           4502 Alan@yahoo.com   2018-05-15                  0
     5           7283 Stan@aol.com     2018-05-20                  0
     6           8012 Mary@outlook.com 2018-05-25                  0
     7           2938 Adam@outlook.com 2018-05-30                  0
     8           7485 Tom@aol.com      2018-06-01                  0
     9           1010 Jane@yahoo.com   2018-06-05                  0
    10           9877 John@gmail.com   2018-06-10                  0
    

    注意:

    我认为@Lyngbakr 的解决方案更适合您的问题。如果重复组的大小可能会发生变化(例如,您想在 30 天内检查 3 或 4 个条目,而不是 2 个),我的会更合适。

    稍作修改的数据

    AccountNumbers <- c(3748,8894,9923,4502,7283,8012,2938,7485,1010,9877)
    EmailAddress <- c("John@gmail.com","John@gmail.com","Alex@outlook.com","Alan@yahoo.com","Stan@aol.com","Mary@outlook.com","Adam@outlook.com","Tom@aol.com","Jane@yahoo.com","John@gmail.com")
    
    Dates <- as.Date(c("2018-05-01","2018-05-05","2018-05-10","2018-05-15","2018-05-20",
               "2018-05-25","2018-05-30","2018-06-01","2018-06-05","2018-06-10"))
    
    df <- data.frame(AccountNumbers,EmailAddress,Dates, stringsAsFactors = FALSE)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-03
      相关资源
      最近更新 更多