【问题标题】:Find and selecting duplicates rows and comparing their dates查找并选择重复行并比较它们的日期
【发布时间】:2019-09-05 15:33:12
【问题描述】:

我有一个如下所示的数据框,其中包含 96,000 行和不同数量的相同 ID。我想选择具有相同 ID 的行,然后从日期最早的行中选择销售额。

   ID     Date1      Date2      Date3     Sales  
 ------ ---------- ---------- ---------- ------- 
  3351   7/18/18    1/8/2017   9/7/2016   $240   
  3351              9/15/14               $670   
  3351   4/5/2017   9/7/16                       
  8222              6/6/2013   2/5/2008   $943    

在这种情况下,对于 ID 3351,我们会选择 670 美元,因为第二个 dup 中的 Date2 是 2014 年。

for(i in length(data))
{
  if(duplicated(dat17[i,1]) == TRUE)
    {
       pmin(dat17[1,7:9], dat17[2,7:9])
    }
}

我正在尝试使用 for 循环来查找重复项并进行比较,但我不确定如何使用 duplicated() 函数给出的多行。 pmin() 仅适用于向量,我需要使用数据框中的数据。

【问题讨论】:

    标签: r


    【解决方案1】:

    一种方法是使用dplyr 包,它使这类事情变得更容易。

    library(dplyr)
    
    df <- read.table(text = "ID     Date1      Date2      Date3     Sales  
      3351   7/18/18    1/8/2017   9/7/2016   $240   
      3351   NA         9/15/14    NA         $670   
      3351   4/5/2017   9/7/16     NA         NA         
      8222   NA         6/6/2013   2/5/2008   $943  ",
      stringsAsFactors = FALSE,
      header = TRUE) %>%
      # make sure the date variables are in date format for sorting to work properly
      mutate_at(vars(starts_with("Date")),lubridate::mdy)
    
    df %>%
      # calculate the minimum date for each row using pmin
      mutate(min_date = pmin(Date1,Date2,Date3,na.rm = TRUE)) %>%
      # arrange from lowest date to highest date
      arrange(min_date) %>%
      # for each ID
      group_by(ID) %>%
      # keep the first one
      slice(1) %>%
      # ungroup to allow future calculations
      ungroup()
    
    # A tibble: 2 x 6
    #      ID Date1      Date2      Date3      Sales min_date  
    #   <int> <date>     <date>     <date>     <chr> <date>    
    # 1  3351 NA         2014-09-15 NA         $670  2014-09-15
    # 2  8222 NA         2013-06-06 2008-02-05 $943  2008-02-05
    

    【讨论】:

      【解决方案2】:

      这是一种选择:

      library(tidyverse) 
      library(lubridate)
      
      df <-
        tibble(
          id = c(3351, 3351, 8222, 8222),
          date1 = c("2018-07-18", NA_character_, "2017-01-03", "2016-03-02"),
          date2 = c("2016-03-04", "2015-03-02", NA_character_, "2017-04-05"),
          sales = c(240, 670, NA_integer_, 300)
        )
      
      df
      # A tibble: 4 x 4
           id date1      date2      sales
        <dbl> <chr>      <chr>      <dbl>
      1  3351 2018-07-18 2016-03-04   240
      2  3351 NA         2015-03-02   670
      3  8222 2017-01-03 NA            NA
      4  8222 2016-03-02 2017-04-05   300
      

      第一步是将各种日期列收集到一个列中:

      df %>% 
        gather(key = date_col, value = date, date1:date2)
      
      # A tibble: 8 x 4
           id sales date_col date      
        <dbl> <dbl> <chr>    <chr>     
      1  3351   240 date1    2018-07-18
      2  3351   670 date1    NA        
      3  8222    NA date1    2017-01-03
      4  8222   300 date1    2016-03-02
      5  3351   240 date2    2016-03-04
      6  3351   670 date2    2015-03-02
      7  8222    NA date2    NA        
      8  8222   300 date2    2017-04-05
      

      然后您可以按 ID 分组并过滤以找到最早的日期。

      df %>% 
        gather(key = date_col, value = date, date1:date2) %>% 
        filter(!is.na(date), !is.na(sales)) %>% 
        mutate(date = ymd(date)) %>% 
        group_by(id) %>% 
        filter(date == min(date)) %>% 
        ungroup()
      
      # A tibble: 2 x 4
           id sales date_col date      
        <dbl> <dbl> <chr>    <date>    
      1  8222   300 date1    2016-03-02
      2  3351   670 date2    2015-03-02
      

      【讨论】:

      • 这是整洁的做事方式。如果你也有更多的日期列,那就太好了。
      【解决方案3】:

      我们不需要将逻辑表达式与 TRUE/FALSE 进行比较。它已经是base R 中的逻辑输出(未使用外部包)

      i1 <- !duplicated(dat17[[1]])
      

      此外,在进行比较之前,请确保将“日期”列转换为 Date

      dat17[2:4] <- lapply(dat17[2:4], as.Date, format = "%m/%d/%y")
      cbind(dat17[i1,], new = do.call(pmin, c(dat17[2:4][i1,], na.rm = TRUE)))
      #  ID      Date1      Date2      Date3 Sales        new
      #1 3351 2018-07-18 2020-01-08 2020-09-07  $240 2018-07-18
      #4 8222       <NA> 2020-06-06 2020-02-05  $943 2020-02-05
      

      注意for 循环只是循环一个值length(data) 返回一个元素。另外,当下一行应该是“dat17”时,不确定这里的“数据”是什么

      数据

      dat17 <- structure(list(ID = c(3351L, 3351L, 3351L, 8222L), Date1 = c("7/18/18", 
      NA, "4/5/2017", NA), Date2 = c("1/8/2017", "9/15/14", "9/7/16", 
      "6/6/2013"), Date3 = c("9/7/2016", NA, NA, "2/5/2008"), Sales = c("$240", 
      "$670", NA, "$943")), class = "data.frame", row.names = c(NA, 
      -4L))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-17
        • 2013-12-30
        • 2015-07-08
        • 1970-01-01
        • 2021-01-31
        相关资源
        最近更新 更多