根据其在R中的场景选择组

时间:2018-08-17 15:58:48

标签: r dataframe dplyr data.table

这里的数据

mydat=structure(list(code = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L), .Label = "52382МСК", class = "factor"), 
    item = c(11709L, 11709L, 11709L, 11709L, 11708L, 11708L, 
    11708L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 
    11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 
    11710L, 11710L, 11710L, 11710L, 11710L, 11710L), sales = c(30L, 
    10L, 20L, 15L, 2L, 10L, 3L, 30L, 10L, 20L, 15L, 2L, 10L, 
    3L, 30L, 10L, 20L, 15L, 2L, 10L, 3L, 30L, 10L, 20L, 15L, 
    2L, 10L, 3L), action = c(0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 
    0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 
    0L, 1L, 0L, 0L, 0L)), .Names = c("code", "item", "sales", 
"action"), class = "data.frame", row.names = c(NA, -28L))

我有3组vars代码和项目。这里有3组:

code    item
52382МСК    11709
52382МСК    11708
52382МСК    11710

我也有行动专栏。它只能有两个值零(0)或一(1)。

每个小组代表3个场景

52382МСК    11709

这是当我们有1个零类别的动作col时的情况。在动作col的第一类别之前,以及在动作col的第一类别之后的两个零。 注意:当我们有2个零类别的动作col时,可能是这种情况。在动作col的第一类别之前,并且在动作col的第一类别之后为1。

52382МСК    11708

这是当我们有1个零类别的动作col时的情况。在第一类动作列之后添加1个零。

52382МСК    11710

这是当我们有3个(或更多)零类别的动作col时的场景。并且在第一类动作列之后添加3(或更多)个零。

如何选择具有每种情况的组? 即Mydat1是具有第一种情况的组, Mydat2是具有第二种情况的小组,  Mydat3是具有第三种情况的小组

输出很简单

mydat1

code    item    sales   action
52382МСК    11709   30  0
52382МСК    11709   10  1
52382МСК    11709   20  0
52382МСК    11709   15  0



mydat2
code    item    sales   action
52382МСК    11708   2   0
52382МСК    11708   10  1
52382МСК    11708   3   0

mydat3
code    item    sales   action
52382МСК    11710   30  0
52382МСК    11710   10  0
52382МСК    11710   20  0
52382МСК    11710   15  1
52382МСК    11710   2   0
52382МСК    11710   10  0
52382МСК    11710   3   0
52382МСК    11710   30  0
52382МСК    11710   10  0
52382МСК    11710   20  0
52382МСК    11710   15  1
52382МСК    11710   2   0
52382МСК    11710   10  0
52382МСК    11710   3   0
52382МСК    11710   30  0
52382МСК    11710   10  0
52382МСК    11710   20  0
52382МСК    11710   15  1
52382МСК    11710   2   0
52382МСК    11710   10  0
52382МСК    11710   3   0

编辑

我忘了,当我们有1个零类别的动作col时,可能是场景。在动作col的第一类别之前,以及在动作col的第一类别之后的三个零。 或当我们有3个零类别的动作栏时的场景。在动作col的第一类别之前,并且在动作col的第一类别之后为1。

(mydat4)

也可以 我们有2个零类别的动作col的场景。在动作col的第一类别之前,以及在动作col的第一类别之后的三个零。 或当我们有3个零类别的动作栏时的场景。在动作col的第一类之前,并且在动作col的第一类之后为2。

(mydat5)

I.E。它只能在这些情况下工作。

edit2

我找到了下一组,它只有一行

code    item    sales   action
52499МСК    11202   2   0

如果数据只有一行,那将是6种情况怎么办?

也可以这样

code    item    sales   action
52499МСК    11202   2   0
 52499МСК   11202   2   1

code    item    sales   action
52499МСК    11202   2   0
 52499МСК   11202   2   0

code    item    sales   action
52499МСК    11202   2   1
 52499МСК   11202   2   1

如果组中只有两行,则有7种情况

2 个答案:

答案 0 :(得分:1)

如果我对您的理解正确,那么情况如下:

s1:0100
s2:010
s3:000 ... 1000 ...
s4:01000或00010
s5:001000或000100
s6:0或1
s7:01或00或10或11

如果是这样,那么方便地,这些方案中的每一个都有唯一的行数。 s1是4行,s2是3,s3是7 +,s4是5,s5是6,s6是1,s7是2。

利用这个事实,我们可以执行以下操作:

这将添加一个“方案”列,以指示是方案1、2、3、4还是5。我强烈建议您不要将数据帧分解为多个数据帧。我愿意猜测dplyr的library(dplyr) mydat = structure(list(code = c("52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK", "52382MCK" ), item = c(11709L, 11709L, 11709L, 11709L, 11708L, 11708L, 11708L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L), sales = c(30L, 10L, 20L, 15L, 2L, 10L, 3L, 30L, 10L, 20L, 15L, 2L, 10L, 3L, 30L, 10L, 20L, 15L, 2L, 10L, 3L, 30L, 10L, 20L, 15L, 2L, 10L, 3L), action = c(0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L)), class = "data.frame", row.names = c(NA, -28L), .Names = c("code", "item", "sales", "action")) mydat = mydat %>% group_by(code, item) %>% mutate(groups_item_count = n(), scenario = case_when(groups_item_count == 4 ~ 1, groups_item_count == 3 ~ 2, groups_item_count >= 7 ~ 3, groups_item_count == 5 ~ 4, groups_item_count == 6 ~ 5, groups_item_count == 1 ~ 6, groups_item_count == 2 ~ 7)) filter()函数对于完成接下来要完成的任务会更有效。但是,如果您坚持要针对每种情况将其分解为单独的数据帧,则可以执行以下操作:

group_by()

答案 1 :(得分:1)

如果我理解正确,OP将按action列中的零和一的模式对数据集中的不同组进行分类。在这个问题中,他描述了他希望在数据中找到的几种模式(称为“方案”)。

到目前为止,该问题已被编辑两次以添加更多方案。这表明OP的方案列表可能不完整。因此,我建议采用另一种方法来定义一组完整的方案(或01的模式),然后尝试在数据集中找到这些模式。

定义可能的情况

IIUC,不同的场景取决于0的每个序列或条纹之前和之后连续1的数量。 (此问题中的样本数据集只有一个1,但是OP发布了相关问题,其中数据包含最多三个1的条纹。)

根据OP的描述,在0连胜之前或之后,可能没有0或最多三个连续1的序列。另外,一个组只能包含0个。

以此,可以创建所有可能的模式/场景的表:

library(data.table)
library(magrittr)

max_zeros <- 3
zeros <- sapply(0:max_zeros, stringr::str_dup, string = "0")
names(zeros) <- as.character(nchar(zeros))
sc <- CJ(zeros.before = zeros, zeros.after = zeros)[
  , scenario.name := paste(nchar(zeros.before), nchar(zeros.after), sep = "-")][
    , action.pattern := sprintf("%s1+(?=%s)", zeros.before, zeros.after)][]
# special case: all zero
sc0 <- data.table(
  zeros.before = NA,
  zeros.after = NA, 
  scenario.name = "no1", 
  action.pattern = "^0+$")
sc <- rbind(sc0, sc)
sc
    zeros.before zeros.after scenario.name action.pattern
 1:         <NA>        <NA>           no1           ^0+$
 2:                                    0-0         1+(?=)
 3:                        0           0-1        1+(?=0)
 4:                       00           0-2       1+(?=00)
 5:                      000           0-3      1+(?=000)
 6:            0                       1-0        01+(?=)
 7:            0           0           1-1       01+(?=0)
 8:            0          00           1-2      01+(?=00)
 9:            0         000           1-3     01+(?=000)
10:           00                       2-0       001+(?=)
11:           00           0           2-1      001+(?=0)
12:           00          00           2-2     001+(?=00)
13:           00         000           2-3    001+(?=000)
14:          000                       3-0      0001+(?=)
15:          000           0           3-1     0001+(?=0)
16:          000          00           3-2    0001+(?=00)
17:          000         000           3-3   0001+(?=000)

action.pattern正则表达式,用于查找通过折叠每个组的action列而创建的字符串中的模式。它使用lookahead查找重叠的图案。

scenario.name是模式的简短描述。例如,第17行中的场景名称3-3表示一种模式,该模式由三个0,一个或多个1的条纹,后跟三个0组成,例如,00010000001100000011111000。第2行中的方案名称0-0表示另一个特殊情况,其中模式仅由1个组成。

按组查找数据集中的模式

现在,我们可以尝试在给定数据中查找模式。要搜索不同的模式,我们

  • action列折叠为一个字符串,分别针对每个codeitem组,
  • 计算字符串中每个action.pattern的出现次数,并且
  • 以宽格式格式化结果(每组一行)。

请注意,mydat已被修改为包括OP修改中的其他用例(请参见下面的数据部分)。

mydat[, paste(action, collapse = "") %>% 
        stringr::str_count(sc$action.pattern) %>%
        t() %>% 
        as.data.table() %>% 
        setnames(sc$scenario.name),
      by = .(code, item)]

       code  item no1 0-0 0-1 0-2 0-3 1-0 1-1 1-2 1-3 2-0 2-1 2-2 2-3 3-0 3-1 3-2 3-3
1: 52382MCK 11709   0   1   1   1   0   1   1   1   0   0   0   0   0   0   0   0   0
2: 52382MCK 11708   0   1   1   0   0   1   1   0   0   0   0   0   0   0   0   0   0
3: 52382MCK 11710   0   3   3   3   3   3   3   3   3   3   3   3   3   3   3   3   3
4: 52499MCK 11202   1   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
5: 52499MCK 11203   0   1   0   0   0   1   0   0   0   0   0   0   0   0   0   0   0
6: 52499MCK 11204   1   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
7: 52499MCK 11205   0   1   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

此表显示了每个组中“隐藏”了哪些可能的模式/场景以及发现了多少次事件/场景。

例如,第2行显示相应组中的模式0-0"1"),0-1"10"),1-0({{ 1}})和"01"1-1)已被发现一次。在所有找到的模式中,"0101-1)最长,因此我们将其作为该组的分类。

第3行显示在相应的组中几乎所有模式都被发现了3次。但是,模式"0103-3)最长,将被用作该组的分类。

组的自动分类

我们可以自动选择最右边的模式作为组的分类:

"0001000"
class <- mydat[, .(scenario.name = sc$scenario.name[
  paste(action, collapse = "") %>% 
    stringr::str_count(sc$action.pattern) %>%
    is_greater_than(0) %>% 
    which() %>% 
    max()
  ]),
  by = .(code, item)][]

class

也可以将分类加入 code item scenario.name 1: 52382MCK 11709 1-2 2: 52382MCK 11708 1-1 3: 52382MCK 11710 3-3 4: 52499MCK 11202 no1 5: 52499MCK 11203 1-0 6: 52499MCK 11204 no1 7: 52499MCK 11205 0-0 的每一行:

mydat
mydat[class, on = .(code, item)]

注意事项

答案是基于我对OP的要求的理解,包括对OP生产数据集的大量推测和隐含假设。

数据

code item sales action scenario.name 1: 52382MCK 11709 30 0 1-2 2: 52382MCK 11709 10 1 1-2 3: 52382MCK 11709 20 0 1-2 4: 52382MCK 11709 15 0 1-2 5: 52382MCK 11708 2 0 1-1 6: 52382MCK 11708 10 1 1-1 7: 52382MCK 11708 3 0 1-1 8: 52382MCK 11710 30 0 3-3 9: 52382MCK 11710 10 0 3-3 10: 52382MCK 11710 20 0 3-3 11: 52382MCK 11710 15 1 3-3 12: 52382MCK 11710 2 0 3-3 13: 52382MCK 11710 10 0 3-3 14: 52382MCK 11710 3 0 3-3 15: 52382MCK 11710 30 0 3-3 16: 52382MCK 11710 10 0 3-3 17: 52382MCK 11710 20 0 3-3 18: 52382MCK 11710 15 1 3-3 19: 52382MCK 11710 2 0 3-3 20: 52382MCK 11710 10 0 3-3 21: 52382MCK 11710 3 0 3-3 22: 52382MCK 11710 30 0 3-3 23: 52382MCK 11710 10 0 3-3 24: 52382MCK 11710 20 0 3-3 25: 52382MCK 11710 15 1 3-3 26: 52382MCK 11710 2 0 3-3 27: 52382MCK 11710 10 0 3-3 28: 52382MCK 11710 3 0 3-3 29: 52499MCK 11202 2 0 no1 30: 52499MCK 11203 2 0 1-0 31: 52499MCK 11203 2 1 1-0 32: 52499MCK 11204 2 0 no1 33: 52499MCK 11204 2 0 no1 34: 52499MCK 11205 2 1 0-0 35: 52499MCK 11205 2 1 0-0 code item sales action scenario.name 的增强版

mydat

编辑:按方案划分

OP有requested可以为17个场景中的每个场景创建一个单独的数据集。

通常,除非有充分的理由,附加要求或外部约束,否则我不建议您采用这种方法。想象一下,您是数据库管理员。您是否要在数据库中创建17个结构相同的独立表,而不是通过选择子集来控制处理的一个表?

但是,可以按场景mydat <- structure(list(code = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("52382MCK", "52499MCK"), class = "factor"), item = c(11709L, 11709L, 11709L, 11709L, 11708L, 11708L, 11708L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11710L, 11202L, 11203L, 11203L, 11204L, 11204L, 11205L, 11205L ), sales = c(30L, 10L, 20L, 15L, 2L, 10L, 3L, 30L, 10L, 20L, 15L, 2L, 10L, 3L, 30L, 10L, 20L, 15L, 2L, 10L, 3L, 30L, 10L, 20L, 15L, 2L, 10L, 3L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), action = c(0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 1L)), row.names = c(NA, -35L), class = "data.frame") # coerce to data.table setDT(mydat) 进行数据集

split()
split(mydat[class, on = .(code, item)], by = "scenario.name")

结果是一个列表data.tables。

可以从列表中选择单个元素,

$`1-2`
       code  item sales action scenario.name
1: 52382MCK 11709    30      0           1-2
2: 52382MCK 11709    10      1           1-2
3: 52382MCK 11709    20      0           1-2
4: 52382MCK 11709    15      0           1-2

$`1-1`
       code  item sales action scenario.name
1: 52382MCK 11708     2      0           1-1
2: 52382MCK 11708    10      1           1-1
3: 52382MCK 11708     3      0           1-1

$`3-3`
        code  item sales action scenario.name
 1: 52382MCK 11710    30      0           3-3
 2: 52382MCK 11710    10      0           3-3
 3: 52382MCK 11710    20      0           3-3
 4: 52382MCK 11710    15      1           3-3
 5: 52382MCK 11710     2      0           3-3
 6: 52382MCK 11710    10      0           3-3
 7: 52382MCK 11710     3      0           3-3
 8: 52382MCK 11710    30      0           3-3
 9: 52382MCK 11710    10      0           3-3
10: 52382MCK 11710    20      0           3-3
11: 52382MCK 11710    15      1           3-3
12: 52382MCK 11710     2      0           3-3
13: 52382MCK 11710    10      0           3-3
14: 52382MCK 11710     3      0           3-3
15: 52382MCK 11710    30      0           3-3
16: 52382MCK 11710    10      0           3-3
17: 52382MCK 11710    20      0           3-3
18: 52382MCK 11710    15      1           3-3
19: 52382MCK 11710     2      0           3-3
20: 52382MCK 11710    10      0           3-3
21: 52382MCK 11710     3      0           3-3
        code  item sales action scenario.name

$no1
       code  item sales action scenario.name
1: 52499MCK 11202     2      0           no1
2: 52499MCK 11204     2      0           no1
3: 52499MCK 11204     2      0           no1

$`1-0`
       code  item sales action scenario.name
1: 52499MCK 11203     2      0           1-0
2: 52499MCK 11203     2      1           1-0

$`0-0`
       code  item sales action scenario.name
1: 52499MCK 11205     2      1           0-0
2: 52499MCK 11205     2      1           0-0
split(mydat[class, on = .(code, item)], by = "scenario.name")[["1-2"]]

如果出于某些原因仍需要使用许多单个数据对象来使工作区变得混乱,可以按以下步骤进行操作(不推荐

       code  item sales action scenario.name
1: 52382MCK 11709    30      0           1-2
2: 52382MCK 11709    10      1           1-2
3: 52382MCK 11709    20      0           1-2
4: 52382MCK 11709    15      0           1-2
# workspace before
ls()
[1] "class"     "max_zeros" "mydat"     "sc"        "sc0"       "zeros"  
# create separate datasets
mydat[class, on = .(code, item)] %>% 
  split(by = "scenario.name") %>% 
  set_names(names(.) %>% make.names()) %>%   # make syntactically valid names 
  list2env(.GlobalEnv)
<environment: R_GlobalEnv>
#workspace after
ls()