Организация кадра данных - разделение одного столбца на три - PullRequest
4 голосов
/ 22 марта 2019

У меня есть набор данных, который выглядит следующим образом:

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, столбец, в котором перечислены самые ранние даты поступления для каждого заказа и последняя дата поступления для каждого заказа.Поскольку некоторые заказы имеют только одну дату поступления, 2-й и 3-й столбцы должны быть одинаковыми.Я пытался использовать 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 ]

3 голосов
/ 22 марта 2019

Использование 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
2 голосов
/ 22 марта 2019

С tidyverse, заимствование данных выборки @ divibisan:

library(tidyverse)

df %>%
  group_by(Ord_ID, Supplier) %>%
  slice(c(1:2, n())) %>%
  mutate(Trans_Type = c("PO_Date","First_Receipt_Date","Last_Receipt_Date")) %>%
  spread(Trans_Type, Date) %>%
  ungroup()

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

Если данные не отсортированы, как в данных выборки, добавьте %>% arrange(Trans_Type, Date) в качестве первого шага.

1 голос
/ 22 марта 2019

Я бы начал с чего-то вроде этого:

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

Затем вы можете поиграть с gather и spread, чтобы получить нужные вам столбцы.

0 голосов
/ 22 марта 2019

Вы можете просто использовать 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)))
0 голосов
/ 22 марта 2019

Вот еще одно решение на основе 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
...