整理数据框-将一列分成三份

时间:2019-03-21 21:37:13

标签: r dataframe spread

我有一个看起来像这样的数据集:

Ord_ID      Supplier     Trans_Type     Date
1           A            PO             2/3/18
1           A            Receipt        2/15/18
2           B            PO             2/4/18
2           B            Receipt        3/13/18
3           C            PO             2/7/18
3           C            Receipt        3/1/18
3           C            Receipt        3/5/18
3           C            Receipt        3/29/18
4           B            PO             2/9/18
4           B            Receipt        2/20/18
4           B            Receipt        2/27/18
5           D            PO             2/18/18
5           D            Receipt        4/2/18

基本上,我需要将“日期”列分为3个不同的列。我需要一个PO_Date列,该列列出每个订单的最早收货日期,以及每个订单的最后收货日期。由于某些订单只有一个收货日期,因此第二列和第三列应该相同。我尝试使用spread(),但我想是因为每个无效的订单都有不同的收货日期。我该如何做到这一点?

所需结果:

Ord_ID     Supplier    PO_Date   First_Receipt_Date    Last_Receipt_Date
1          A           2/3/18    2/15/18               2/15/18
2          B           2/4/18    3/13/18               3/13/18
3          C           2/7/18    3/1/18                3/29/18
4          B           2/9/18    2/20/18               2/27/18
5          D           2/18/18   4/2/18                4/2/18

5 个答案:

答案 0 :(得分:3)

使用dplyr。首先,确保列Date为日期格式。假设数据框被命名为mydata

library(dplyr)
mydata <- mydata %>% 
  mutate(Date = as.Date(Date, "%m/%d/%y")

现在,您可以过滤Receipt,计算最大/最小日期,然后过滤PO的原始数据并将它们结合在一起:

mydata %>% 
  filter(Trans_Type == "Receipt") %>% 
  group_by(Ord_ID, Supplier) %>% 
  summarise(First_Receipt_Date = min(Date), 
            Last_Receipt_Date = max(Date)) %>% 
  ungroup() %>%
  left_join(filter(mydata, Trans_Type == "PO")) %>% 
  select(Ord_ID, Supplier, PO_Date = Date, First_Receipt_Date, Last_Receipt_Date)

结果:

  Ord_ID Supplier PO_Date    First_Receipt_Date Last_Receipt_Date
   <int> <chr>    <date>     <date>             <date>           
1      1 A        2018-02-03 2018-02-15         2018-02-15       
2      2 B        2018-02-04 2018-03-13         2018-03-13       
3      3 C        2018-02-07 2018-03-01         2018-03-29       
4      4 B        2018-02-09 2018-02-20         2018-02-27       
5      5 D        2018-02-18 2018-04-02         2018-04-02

答案 1 :(得分:2)

使用 <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css"> <link rel="stylesheet" type="text/css" href="css/style.css"> <script src="https://code.jquery.com/jquery-2.1.3.min.js"></script> <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script> <script src="js/jquery.min.js"></script> <script src="js/bootstrap.min.js"></script> <title></title> </head> <body> <div class="container "> <nav class="navbar navbar-expand-sm navbar-dark bg-dark"> <a href="#" class="navbar-brand"><img src="logo.png">The building co.</a> <button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#myMenu"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="myMenu"> <ul class="navbar-nav"> <li class="nav-item"> <a href="#" class="navbar-link">Home </a> </li> <li class="nav-item"> <a href="#" class="navbar-link">contact us </a> </li> <li class="nav-item"> <a href="#" class="navbar-link">policy </a> </li> <li class="nav-item"> <a href="#" class="navbar-link">terms </a> </li> <li class="nav-item"> <a href="#" class="navbar-link">About us </a> </li> </ul> </div> </nav> </div> </body> </html> ,借用@divibisan的示例数据:

tidyverse

如果数据未与示例数据中的排序相同,请添加{{ 1}}作为第一步。

答案 2 :(得分:1)

我将从以下内容开始:

data %>%
  group_by(Supplier, Trans_Type) %>%
  summarise(min_date = min(Date),
    max_date = max(Date)
)  %>%
  ungroup()

然后,您可以使用gatherspread来检索所需的列。

答案 3 :(得分:0)

这是另一个基于tidyverse的解决方案,它避免了left_join。我不知道哪种方法在大型数据集上会更快,但是拥有更多选项总是很好:

df <- structure(list(Ord_ID = c(1L, 1L, 2L, 2L, 3L, 3L, 3L, 3L, 4L, 
4L, 4L, 5L, 5L), Supplier = structure(c(1L, 1L, 2L, 2L, 3L, 3L, 
3L, 3L, 2L, 2L, 2L, 4L, 4L), .Label = c("A", "B", "C", "D"), class = "factor"), 
    Trans_Type = c("PO", "Receipt", "PO", "Receipt", "PO", "Receipt", 
    "Receipt", "Receipt", "PO", "Receipt", "Receipt", "PO", "Receipt"
    ), Date = structure(c(17565, 17577, 17566, 17603, 17569, 
    17591, 17595, 17619, 17571, 17582, 17589, 17580, 17623), class = "Date")), row.names = c(NA, 
-13L), class = "data.frame")



df %>%
    group_by(Ord_ID, Supplier, Trans_Type) %>%
    # Keep only min and max date values
    filter(Date == min(Date) | Date == max(Date) | Trans_Type != 'Receipt') %>%
    # Rename 2nd Receipt value Receipt_2 so there are no duplicated values
    mutate(Trans_Type2 = if_else(Trans_Type == 'Receipt' & row_number() == 2,
                                 'Receipt_2', Trans_Type)) %>%
    # Drop Trans_Type variable (we can't replace in mutate since it's a grouping var)
    ungroup(Trans_Type) %>%
    select(-Trans_Type) %>%
    # Spread the now unduplicated Trans_Type values
    spread(Trans_Type2, Date) %>%
    # Fill in Receipt_2 values where they're missing
    mutate(Receipt_2 = if_else(is.na(Receipt_2), Receipt, Receipt_2))

# A tibble: 5 x 5
  Ord_ID Supplier PO         Receipt    Receipt_2 
   <int> <fct>    <date>     <date>     <date>    
1      1 A        2018-02-03 2018-02-15 2018-02-15
2      2 B        2018-02-04 2018-03-13 2018-03-13
3      3 C        2018-02-07 2018-03-01 2018-03-29
4      4 B        2018-02-09 2018-02-20 2018-02-27
5      5 D        2018-02-18 2018-04-02 2018-04-02

答案 4 :(得分:0)

您可以仅使用dplyr更改采购订单日期以及第一个和最后一个收货日期的新列:

test1<-test %>%
  mutate(Date = mdy(Date)) %>%
  group_by(Ord_ID) %>%
  mutate(PO_Date = ifelse(Trans_Type == "PO", Date, NA),
         Receipt_Date_First = min(Date[Trans_Type=="Receipt"]),
         Receipt_Date_Last = max(Date[Trans_Type=="Receipt"])) %>%
  filter(!is.na(PO_Date)) %>%
  mutate(PO_Date = as.Date(as.numeric(PO_Date)))

明细:

test1<-test %>%

  #convert format of "Date" column to as.Date to identify min and max dates
  mutate(Date = mdy(Date)) %>%

  #group by the Order ID
  group_by(Ord_ID) %>%

  #PO_Date will be where the "Trans_Type" is "PO" --> since the column is in date format,
  #dplyr will convert this to numeric, but can be fixed later
  mutate(PO_Date = ifelse(Trans_Type == "PO", Date, NA),

     #first receipt date is the minimum date of a receipt transaction
     Receipt_Date_First = min(Date[Trans_Type=="Receipt"]),

     #last receipt date is the maximum date of a receipt transaction
     Receipt_Date_Last = max(Date[Trans_Type=="Receipt"])) %>%

  #to remove duplicates
  filter(!is.na(PO_Date)) %>%

  #convert "PO_Date" column back to as.Date from numeric
  mutate(PO_Date = as.Date(as.numeric(PO_Date)))