查找并选择重复的行并比较它们的日期

时间:2019-09-05 15:33:12

标签: r

我有一个像下面这样的数据框,其中包含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,因为第二个重复项中的Date2是在2014年。

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

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

3 个答案:

答案 0 :(得分:4)

一种方法是使用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

答案 1 :(得分:1)

我们不需要将逻辑表达式与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))

答案 2 :(得分:1)

这里是一个选择:

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
相关问题