【问题标题】:Compare rows in groups in the same data frame比较同一数据框中的组中的行
【发布时间】:2018-10-05 22:53:55
【问题描述】:

我的数据如下所示:

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 循环(甚至不确定它是否能解决问题),因为数据集很大而且需要很长时间。而且我总体上真的缺乏想法。因此,我们将不胜感激。

谢谢!



插件:

我偶然发现了与此案有关的另一个问题。我只想在下一个后续订单中将已在另一个 size 中订购的商品标记为已更改,而不是在相同尺寸的同一商品再次订购时。所以变量改变的标准是:

订单 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

抱歉,我在示例中实际上犯了一个错误,错误地填充了更改的变量。如果您仍然在帮助我,我将不胜感激。

谢谢!

【问题讨论】:

  • 也许不按订单号分组?
  • 是的,但是她会遇到问题,因为同一个订单可能有多件同种不同尺寸的物品,如果其中一个被退回,第二个将被标记为已交换,这不是真的。
  • 您能解释一下为什么第 5 行中的changed1 应该在那里吗?那不应该在第 4 行吗?
  • @Jaap:我在问题中添加了另一部分,我试图更准确地说明问题。在原始版本中,我实际上在示例结果中犯了一个错误。在原始示例中,第 4 行中的 changed == 1 实际上不应该存在,因为相同尺寸的同一篇文章已按顺序 1 订购。如果它是相同的文章,但在下一个订单中尺寸不同。由于在第二行中 JeansA 是 42 号的订购者,因此它再次出现在第二个订单中,因此不会更换商品。希望能把事情弄清楚吗?
  • 查看更新的答案,HTH

标签: r dplyr data.table lag


【解决方案1】:

新答案:

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

【讨论】:

  • 在示例中的作用就像一个魅力,谢谢!不幸的是,我遇到了一个特定的组合,它似乎不起作用: df1
  • @Ditzgewizzle 没错。所有这些都被返回,因此对于这些订单中的任何一个,条件returned == 0 都不成立。因此,它们都不能被视为后续订单。
  • @Ditzgewizzle 很高兴我能帮上忙
【解决方案2】:

您正在处理多个滞后条件,因此我们需要多个 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 

【讨论】:

  • 你很好地回答了我的问题!谢谢你。将您的代码应用于真实数据,我遇到了一个问题。如果相同尺寸的相同文章出现在下一个订单中,则实际更改的文章具有不同的尺寸。我会相应地更新问题!
  • @Ditzgewizzle 看起来您的标准与最初的问题不同。如果您有新问题,请提出新问题。请不要修改您的旧问题,因为它使我的答案看起来“错误”。如果这为您的原始问题生成了所需的输出,我没有时间或义务更新我的答案,但如果您有一个具有良好可重复示例和清晰解释的新问题,我可能有时间稍后再研究。
  • 是的,你是完全正确的,我在我给你的例子中犯了错误。我将它改回旧版本并添加了另一个示例,我试图更精确。如果您仍然可以查看它,那就太好了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多