Сравнить строки в группах в одном фрейме данных - PullRequest
0 голосов
/ 25 апреля 2018

Мои данные выглядят так:

library(dplyr)
library(data.table)

df <- data.frame(
  customernumber = c("111", "111", "111",  "111", "111","222", "222", "222", "222", "222", "222", "222"), 
  ordernumber = c("1", "1", "1", "2", "2", "1", "1", "1", "1", "2", "2", "3"), 
  article = c("JeansA", "JeansA", "ShirtA", "JeansA", "JeansB", "ShirtA", "ShirtB", "ShirtB", "JeansA", "JeansB", "ShirtA", "JeansB"), 
  size = c("40", "42", "40", "42", "44", "36", "36", "40", "40", "38", "44", "36"), 
  returned = c("1", "1", "0", "0", "1", "1", "1", "0", "0", "0", "0", "0")
)

Вывод:

   customernumber ordernumber article size returned
1             111           1  JeansA   40        1
2             111           1  JeansA   42        1
3             111           1  ShirtA   40        0
4             111           2  JeansA   42        0
5             111           2  JeansB   44        1
6             222           1  ShirtA   36        1
7             222           1  ShirtB   36        1
8             222           1  ShirtB   40        0
9             222           1  JeansA   40        0
10            222           2  JeansB   38        0
11            222           2  ShirtA   44        0
12            222           3  JeansB   36        0

Теперь я хочу отметить все заказы на клиента, для которых статья была возвращена, но заказана сновав следующем порядке в другом размере.Таким образом, все статьи, которые только обмениваются и поэтому не могут рассматриваться как новый порядок.Таким образом, конечные результаты должны выглядеть следующим образом:

Результат:

   customernumber ordernumber article size returned changed
1             111           1  JeansA   40        1       0
2             111           1  JeansA   42        1       0
3             111           1  ShirtA   40        0       0
4             111           2  JeansA   42        0       1
5             111           2  JeansB   44        1       0
6             222           1  ShirtA   36        1       0
7             222           1  ShirtB   36        1       0
8             222           1  ShirtB   40        0       0
9             222           1  JeansA   40        0       0
10            222           2  JeansB   38        0       0
11            222           2  ShirtA   44        0       1
12            222           3  JeansB   36        0       0

Я думал, что смогу решить проблему, введя переменную запаздывания, используя dyplr (или data.table), ноМне удается отложить переменную только в пределах одной группы, но мне не удается отнести ее к следующей группе.Это:

df %>% 
  group_by(customernumber, ordernumber, article) %>% 
  mutate(lag_size = lag(size, order_by = article))

или:

df <- data.table(df)
setorder(df, customernumber, ordernumber, article)
df[,lag_size := shift(size), by = .(customernumber, ordernumber, article)]

Я не хочу думать о цикле for (даже не уверен, решит ли это проблему), так как набор данныхдовольно большой, и это займет целую вечность. И мне в целом действительно не хватает идей.Поэтому любая помощь приветствуется.

Спасибо!



AddOn:

Я наткнулся на еще одну проблему, связанную с этим делом.Я хочу пометить только те товары, которые были заказаны в другом размере в следующем порядке следования, как измененные, а не в том случае, если тот же товар того же размера был заказчиком снова.Таким образом, критерий для измененной переменной будет:

Порядок n: возвращено == 1 Порядок n + 1: та же статья, другой размер -> изменено == 1 (в противном случае изменено == 0)

Вот обновленный пример:

df <- data.frame(
 customernumber = c("111", "111", "111",  "111", "111", "111","222", "222", "222", "222", "222", "222", "222"), 
 ordernumber = c("1", "1", "1", "2", "2", "2", "1", "1", "1", "1", "2", "2", "3"), 
 article = c("JeansA", "JeansA", "ShirtA", "JeansA", "JeansA", "JeansB", "ShirtA", "ShirtB", "ShirtB", "JeansA", "JeansB", "ShirtA", "JeansB"), 
 size = c("40", "42", "40", "40", "44", "44", "36", "36", "40", "40", "38", "44", "36"), 
 returned = c("1", "1", "0", "0", "1", "1", "1", "1", "0", "0", "0", "0", "0")
)

Вывод:

   customernumber ordernumber article size returned
1             111           1  JeansA   40        1
2             111           1  JeansA   42        1
3             111           1  ShirtA   40        0
4             111           2  JeansA   40        0
5             111           2  JeansA   44        1
6             111           2  JeansB   44        1
7             222           1  ShirtA   36        1
8             222           1  ShirtB   36        1
9             222           1  ShirtB   40        0
10            222           1  JeansA   40        0
11            222           2  JeansB   38        0
11            222           2  ShirtA   44        0
12            222           3  JeansB   36        0

Результат:

   customernumber ordernumber article size returned changed
1             111           1  JeansA   40        1       0
2             111           1  JeansA   42        1       0
3             111           1  ShirtA   40        0       0
4             111           2  JeansA   40        0       0
5             111           2  JeansA   44        1       1
6             111           2  JeansB   44        1       0   
7             222           1  ShirtA   36        1       0
8             222           1  ShirtB   36        1       0
9             222           1  ShirtB   40        0       0
10            222           1  JeansA   40        0       0
11            222           2  JeansB   38        0       0
11            222           2  ShirtA   44        0       1
12            222           3  JeansB   36        0       0

Извините за путаницу, я действительно допустил ошибкув моем примере и измененную переменную заполняли некорректно.Если вы все еще помогаете мне, я был бы очень признателен.

Спасибо!

Ответы [ 2 ]

0 голосов
/ 25 апреля 2018

Новый ответ:

Возможное решение с data.table:

library(data.table)
setDT(df)

df[, changed := 0
   ][df[df, on = .(customernumber, ordernumber < ordernumber, article), nomatch = 0
        ][size != i.size & returned == 1, .SD[!i.size %in% size], by = .(customernumber, ordernumber, article)
          ][, .(customernumber, ordernumber, article, size = i.size)][, unique(.SD)]
     , on = .(customernumber, ordernumber, article, size), changed := 1][]

, что дает:

    customernumber ordernumber article size returned changed
 1:            111           1  JeansA   40        1       0
 2:            111           1  JeansA   42        1       0
 3:            111           1  ShirtA   40        0       0
 4:            111           2  JeansA   40        0       0
 5:            111           2  JeansA   44        1       1
 6:            111           2  JeansB   44        1       0
 7:            222           1  ShirtA   36        1       0
 8:            222           1  ShirtB   36        1       0
 9:            222           1  ShirtB   40        0       0
10:            222           1  JeansA   40        0       0
11:            222           2  JeansB   38        0       0
12:            222           2  ShirtA   44        0       1
13:            222           3  JeansB   36        0       0

Старый ответ:

library(data.table)
setDT(df)

df[df[returned == 0][df[returned == 1]
                     , on = .(customernumber, article)
                     ][ordernumber != i.ordernumber]
   , on = .(customernumber, article, returned)
   , changed := i.returned
   ][, changed := replace(changed, is.na(changed), 0)][]

, что дает:

    customernumber ordernumber article size returned changed
 1:            111           1  JeansA   40        1       0
 2:            111           1  JeansA   42        1       0
 3:            111           1  ShirtA   40        0       0
 4:            111           2  JeansA   42        0       1
 5:            111           2  JeansB   44        1       0
 6:            222           1  ShirtA   36        1       0
 7:            222           1  ShirtB   36        1       0
 8:            222           1  ShirtB   40        0       0
 9:            222           1  JeansA   40        0       0
10:            222           2  JeansB   38        0       0
11:            222           2  ShirtA   44        0       1
12:            222           3  JeansB   36        0       0
0 голосов
/ 25 апреля 2018

Вы работаете над более чем одним условием задержки, поэтому нам нужно более одной команды lag для создания этого условия.Затем мы можем использовать case_when для создания столбца changed.

df2 <- df %>%
  group_by(customernumber, article) %>%
  mutate(lag_returned = lag(returned),
         lag_ordernumber = lag(ordernumber)) %>%
  ungroup() %>%
  mutate(changed = case_when(
    returned %in% "0" & 
      duplicated(article) & 
        lag_returned %in% "1" &
          ordernumber != lag_ordernumber ~ "1",
    TRUE                                 ~ "0"
  )) %>%
  select(-starts_with("lag"))

df2
# # A tibble: 12 x 6
#    customernumber ordernumber article size  returned changed
#    <fct>          <fct>       <fct>   <fct> <fct>    <chr>  
#  1 111            1           JeansA  40    1        0      
#  2 111            1           JeansA  42    1        0      
#  3 111            1           ShirtA  40    0        0      
#  4 111            2           JeansA  42    0        1      
#  5 111            2           JeansB  44    1        0      
#  6 222            1           ShirtA  36    1        0      
#  7 222            1           ShirtB  36    1        0      
#  8 222            1           ShirtB  40    0        0      
#  9 222            1           JeansA  40    0        0      
# 10 222            2           JeansB  38    0        0      
# 11 222            2           ShirtA  44    0        1      
# 12 222            3           JeansB  36    0        0 
...