计算90%的百分位数,并用14天和7天的间隔用R中的组将其替换为中位数

时间:2018-08-21 09:00:45

标签: r dplyr data.table

此帖子与此我的帖子相关 calculation of 90 percentile and replacement of it by median by groups in R

jyjek的解决方案对我有所帮助,但并不完全。

 mydat%>%
  group_by(code,item)%>%
  mutate(output=ifelse(return>quantile(return,.9) & action==0,median(return),return))

存在计算中位数和90%的条件。

在OP中,我写道  请注意,计算是通过在一个动作类别之前的14个零完成的,但对于所有零类别的动作并针对每个组的代码和项目执行了中位数替换。如何计算90%百分位数是针对一类动作之前的14个零+一类动作之后的7个零,但是必须对所有零类动作以及每个组的code + item执行该操作以中位数代替

这是数据的一部分。

mydat=structure(list(code = c(123L, 123L, 123L, 123L, 123L, 123L, 123L, 
123L, 123L, 123L, 123L, 123L, 123L, 123L, 123L, 123L, 123L, 123L, 
123L, 123L, 123L, 123L, 123L, 123L, 123L, 123L, 123L, 123L, 123L, 
123L, 123L, 123L, 123L, 123L, 123L, 123L, 123L, 123L, 123L, 123L, 
123L, 123L, 123L, 123L, 123L, 123L, 123L, 222L, 222L, 222L, 222L, 
222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L, 
222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L, 
222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L, 
222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L, 222L), 
    item = c(234L, 234L, 234L, 234L, 234L, 234L, 234L, 234L, 
    234L, 234L, 234L, 234L, 234L, 234L, 234L, 234L, 234L, 234L, 
    234L, 234L, 234L, 234L, 234L, 234L, 234L, 234L, 234L, 234L, 
    234L, 234L, 234L, 234L, 234L, 234L, 234L, 234L, 234L, 234L, 
    234L, 234L, 234L, 234L, 234L, 234L, 234L, 234L, 234L, 333L, 
    333L, 333L, 333L, 333L, 333L, 333L, 333L, 333L, 333L, 333L, 
    333L, 333L, 333L, 333L, 333L, 333L, 333L, 333L, 333L, 333L, 
    333L, 333L, 333L, 333L, 333L, 333L, 333L, 333L, 333L, 333L, 
    333L, 333L, 333L, 333L, 333L, 333L, 333L, 333L, 333L, 333L, 
    333L, 333L, 333L, 333L, 333L, 333L), return = c(25L, 25L, 
    21L, 37L, 23L, 27L, 19L, 7L, 16L, 12L, 33L, 24L, 6L, 14L, 
    4L, 25L, 90L, 27L, 3L, 16L, 7L, 1L, 13L, 11L, 36L, 5L, 6L, 
    14L, 11L, 41L, 11L, 6L, 4L, 11L, 3L, 6L, 21L, 41L, 28L, 30L, 
    92L, 4L, 1L, 83L, 3L, 16L, 4L, 25L, 25L, 21L, 37L, 23L, 27L, 
    19L, 7L, 16L, 12L, 33L, 24L, 6L, 14L, 4L, 25L, 90L, 27L, 
    3L, 16L, 7L, 1L, 13L, 11L, 36L, 5L, 6L, 14L, 11L, 41L, 11L, 
    6L, 4L, 11L, 3L, 6L, 21L, 41L, 28L, 30L, 92L, 4L, 1L, 83L, 
    3L, 16L, 4L), action = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
    0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
    0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 
    0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
    0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
    0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 
    0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L)), .Names = c("code", 
"item", "return", "action"), class = "data.frame", row.names = c(NA, 
-94L))

我有2个小组vars代码和项目。这是两组:

123 234
222 333

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

我需要通过返回列的零个操作类别来计算90 percentile,该列要归一类操作。 然后,我需要按归零列的归零操作类别来计算median,该归零列要归一类操作。

如何计算90%的百分比是针对一类动作之前的14个零+一类动作之后的7个零,

然后我必须找到上面计算出的90%以上的值,然后必须用计算出的中位数来代替这些值。  但必须对所有零类别的操作以及每个组的代码+项目

执行中位数替换

在执行一类动作之后,再次将零类别用于返回列。为此,我也必须找到上面计算出的90%以上的值,然后必须用上面计算出的中位数代替该值。

请注意,calculation是由一类动作之前的14个零和一类动作之后的7个零完成的。 但对所有replacing的操作都按中位数完成zero category 并为每个组code+item

表演

结果可以在输出列中。

在此处更加清晰地显示所需的输出。

对于123+234组 90 perc = 41 中位数= 14

222+333 90 perc = 41 中位数= 14

 code item return action output
1   123  234     25      0     25
2   123  234     25      0     25
3   123  234     21      0     21
4   123  234     37      0     16
5   123  234     23      0     23
6   123  234     27      0     27
7   123  234     19      0     19
8   123  234      7      0      7
9   123  234     16      0     16
10  123  234     12      0     12
11  123  234     33      0     33
12  123  234     24      0     24
13  123  234      6      0      6
14  123  234     14      0     14
15  123  234      4      0      4
16  123  234     25      0     25
17  123  234     90      0     **14**
18  123  234     27      0     27
19  123  234      3      0      3
20  123  234     16      0     16
21  123  234      7      0      7
22  123  234      1      0      1
23  123  234     13      0     13
24  123  234     11      0     11
25  123  234     36      0     36
26  123  234      5      0      5
27  123  234      6      0      6
28  123  234     14      0     14
29  123  234     11      0     11
30  123  234     41      0     **14**
31  123  234     11      1     Na
32  123  234      6      1     Na
33  123  234      4      1     Na
34  123  234     11      1     Na
35  123  234      3      0      3
36  123  234      6      0      6
37  123  234     21      0     21
38  123  234     41      0     **14**
39  123  234     28      0     28
40  123  234     30      0     30
41  123  234     92      0     **14**
42  123  234      4      0      4
43  123  234      1      0      1
44  123  234     83      0     **14**
45  123  234      3      0      3
46  123  234     16      0     16
47  123  234      4      0      4
48  222  333     25      0     25
49  222  333     25      0     25
50  222  333     21      0     21
51  222  333     37      0     16
52  222  333     23      0     23
53  222  333     27      0     27
54  222  333     19      0     19
55  222  333      7      0      7
56  222  333     16      0     16
57  222  333     12      0     12
58  222  333     33      0     33
59  222  333     24      0     24
60  222  333      6      0      6
61  222  333     14      0     14
62  222  333      4      0      4
63  222  333     25      0     25
64  222  333     90      0     **14**
65  222  333     27      0     27
66  222  333      3      0      3
67  222  333     16      0     16
68  222  333      7      0      7
69  222  333      1      0      1
70  222  333     13      0     13
71  222  333     11      0     11
72  222  333     36      0     36
73  222  333      5      0      5
74  222  333      6      0      6
75  222  333     14      0     14
76  222  333     11      0     11
77  222  333     41      0     **14**
78  222  333     11      1     Na
79  222  333      6      1     Na
80  222  333      4      1     Na
81  222  333     11      1     Na
82  222  333      3      0      3
83  222  333      6      0      6
84  222  333     21      0     21
85  222  333     41      0     **14**
86  222  333     28      0     28
87  222  333     30      0     30
88  222  333     92      0     **14**
89  222  333      4      0      4
90  222  333      1      0      1
91  222  333     83      0     **14**
92  222  333      3      0      3
93  222  333     16      0     16
94  222  333      4      0      4

**我标记了其中值用中位数代替的行。

用于计算百分位数和中位数的数据

return  action
90  0
27  0
3   0
16  0
7   0
1   0
13  0
11  0
36  0
5   0
6   0
14  0
11  0
41  0
11  1
6   1
4   1
11  1
3   0
6   0
21  0
41  0
28  0
30  0
92  0

在一种动作类别之前的14个零+在一种动作类别之后的7个零。

重要修改

我怀疑该错误的原因

此处数据

    item return code action
1  11202      6  137      0
2  11202      3  137      0
3  11202      5  137      0
4  11202      6  137      0
5  11202      4  137      0
6  11202     10  137      0
7  11202      1  137      0
8  11202     19  137      0
9  11202     16  137      0
10 11202      6  137      0
11 11202     11  137      0
12 11202     20  137      0
13 11202     19  137      0
14 11202     13  137      0
15 11202     14  137      0
16 11202     13  137      0
17 11202     21  137      0
18 11202     10  137      0
19 11202     16  137      0
20 11202      8  137      0
21 11202     15  137      0
22 11202      8  137      0
23 11202     25  137      0
24 11202     17  137      0
25 11202     21  137      0
26 11202     14  137      0
27 11202     15  137      0
28 11202      6  137      0
29 11202      5  137      0
30 11202     11  137      0
31 11202     11  137      0
32 11202      8  137      0
33 11202     12  137      1
38 11202     17  137      1
39 11202      9  137      0
40 11202      7  137      0
41 11202      4  137      0

如您所见,在一类动作之前我们有14个零,但在一类动作之后我们只有4个零 在这种情况下,我们先计算14个零,然后计算1个后的4个零。 可能是这种情况

编辑三个

item    return  code    action  mask    output
11683   77  40  0   NA  77
11683   165 40  0   NA  68
11683   100 40  0   NA  100
11683   84  40  0   NA  84
11683   80  40  0   NA  80
11683   52  40  0   NA  52
11683   1   40  0   NA  1
11683   106 40  0   NA  106
11683   70  40  0   NA  70
11683   88  40  0   NA  88
11683   49  40  0   NA  49
11683   107 40  0   NA  107
11683   25  40  0   NA  25
11683   18  40  0   NA  18
11683   77  40  0   NA  77
11683   70  40  0   NA  70
11683   54  40  0   NA  54
11683   74  40  0   NA  74
11683   115 40  0   NA  68
11683   45  40  0   NA  45
11683   22  40  0   NA  22
11683   95  40  0   NA  95
11683   73  40  0   NA  73
11683   69  40  0   NA  69
11683   70  40  0   1   70
11683   71  40  0   1   71
11683   37  40  0   1   37
11683   20  40  0   1   20
11683   49  40  0   1   49
11683   102 40  0   1   102
11683   113 40  0   1   68
11683   110 40  0   1   110
11683   117 40  0   1   68
11683   42  40  0   1   42
11683   7   40  1   NA  7
11683   117 40  1   NA  117
11683   117 40  1   NA  117
11683   132 40  1   NA  132
11683   108 40  1   NA  108
11683   68  40  1   NA  68
11683   51  40  1   NA  51
11683   8   40  1   NA  8
11683   63  40  1   NA  63
11683   88  40  1   NA  88
11683   90  40  1   NA  90
11683   92  40  1   NA  92
11683   80  40  1   NA  80
11683   54  40  1   NA  54
11683   5   40  1   NA  5
11683   139 40  1   NA  139
11683   122 40  1   NA  122
11683   68  40  1   NA  68
11683   43  40  1   NA  43
11683   29  40  1   NA  29
11683   21  40  1   NA  21
11683   12  40  1   NA  12
11683   0   40  1   NA  0
11683   43  40  0   1   43
11683   33  40  0   1   33
11683   53  40  0   1   53
11683   101 40  0   1   101
11683   61  40  0   1   61
11683   13  40  0   1   13
11683   51  40  0   1   51
11683   83  40  0   NA  83
11683   30  40  0   NA  30
11683   59  40  0   NA  59
11683   37  40  0   NA  37
11683   20  40  0   NA  20
11683   9   40  0   NA  9
11683   125 40  0   NA  68
11683   33  40  0   NA  33

中位数和百分位数由这些数据在10之前,7之后计算

70
71
37
20
49
102
113
110
117
42
43
33
53
101
61
13
51

中位数是53,但所有超过90%的位数在68上被替换,因为68是所有肥胖的中位数。

2 个答案:

答案 0 :(得分:1)

我对您的问题的理解:

  • 对于每个codeitem,您都有一系列带有action == 1的行。
  • 您要在该范围前排10行,在该范围后排7行。
  • 对于这17行中action == 0所在的地方,您获得90%的分位数。
  • 比起将所有带有action == 0 all 行与此分位数进行比较。如果该值较大或相等,则用所有行的均值独立于 action的值代替。

如果正确,则可以使用以下内容:

library(dplyr)
get_mask <- function(action) {
  ones <- which(action == 1)
  end_before <- max(0, min(ones) - 1)
  start_before <- max(0, end_before - 9)
  start_after <- min(length(action), max(ones) + 1)
  end_after <- min(length(action), start_after + 6)
  indices <- c(seq.int(from = start_before, to = end_before), 
               seq.int(from = start_after, to = end_after))
  result <- rep(NA_real_, length(action))
  result[indices] <- 1
  result
}


mydat %>%
  group_by(code,item) %>%
  mutate(mask = get_mask(action)) %>%
  mutate(output = ifelse(return>=quantile(mask * return, .9, na.rm = TRUE) & action==0,
                         median(return), return))

主要思想是引入一个mask列,该列确定是否在分位数计算中包括特定的行。

答案 1 :(得分:1)

如果我理解正确,每个actioncode组的item列由一个零序列组成,之后是一个连续的零,最后由另一个零序列构成。每组只有一个连胜。

OP想要

  1. 计算最后 14个“零动作行”(即,带有action == 0的行)的90%分位数和中位数,第一行之前action == 1 分别为第一 7行 后最后一行,action == 1,每个{{1} },code组。
  2. 根据OP的编辑:如果在item中出现1个连号之前,少于14个零或少于7个零,则将计算可用零动作行的统计信息。
  3. 将所有带有action的行的return值复制到output
  4. 如果action == 0值大于或等于90%分位数的{em> ,则替换第一个{{1 }}每行。
    请注意,OP正在讨论寻找大于90%的值,这意味着具有更大的关系,但预期结果也替换了返回等于 90%的分位数。

这可以通过使用一些准备工作通过联接更新来解决。关键部分是确定连胜之前的零动作行和之后的零动作行。对于第一行output之前的零操作行,这是通过action == 1完成的;对于运行行的第一行cummax(action)之后的零操作行,这是通过双反转action == 1进行的从后退。

rev(cummax(rev(action)))
action == 1

现在,我们可以将所有零操作行的library(data.table) library(magrittr) # mark the zero action rows before and after the the action period setDT(mydat)[ , c("zero_before", "zero_after") := .(cummax(action), rev(cummax(rev(action)))), by = .(code, item)] # compute median and 90% quantile for the last 14 rows before and # the first 7 rows after each action period agg <- mydat[, quantile(c(tail(return[zero_before == 0], 14L), head(return[zero_after == 0], 7L)), c(0.5, 0.9)) %>% as.list() %>% set_names(c("med", "q90")) %>% c(.(action = 0)), by = .(code, item)] agg 复制到agg code item med q90 action 1: 123 234 14 41 0 2: 222 333 14 41 0 ,并在更新非等额联接中替换大于90%分位数的return值:

output

由于output由94行组成,因此我们仅显示mydat[action == 0, output := as.double(return)][ # replace output values greater q90 in an update non-equi join agg, on = .(code, item, action, return > q90), output := as.double(med)][ # remove helper column , c("zero_before", "zero_after") := NULL] mydat不同的行:

return

编辑:第二个用例

OP提供了第二个用例:

output

在连胜之后只有3个零动作行。 对于这种用例,我们得到

    code item return action output
 1:  123  234     90      0     14
 2:  123  234     41      0     14
 3:  123  234     41      0     14
 4:  123  234     92      0     14
 5:  123  234     83      0     14
 6:  222  333     90      0     14
 7:  222  333     41      0     14
 8:  222  333     41      0     14
 9:  222  333     92      0     14
10:  222  333     83      0     14
mydat <-
structure(list(item = c(11202L, 11202L, 11202L, 11202L, 11202L, 
11202L, 11202L, 11202L, 11202L, 11202L, 11202L, 11202L, 11202L, 
11202L, 11202L, 11202L, 11202L, 11202L, 11202L, 11202L, 11202L, 
11202L, 11202L, 11202L, 11202L, 11202L, 11202L, 11202L, 11202L, 
11202L, 11202L, 11202L, 11202L, 11202L, 11202L, 11202L, 11202L
), return = c(6L, 3L, 5L, 6L, 4L, 10L, 1L, 19L, 16L, 6L, 11L, 
20L, 19L, 13L, 14L, 13L, 21L, 10L, 16L, 8L, 15L, 8L, 25L, 17L, 
21L, 14L, 15L, 6L, 5L, 11L, 11L, 8L, 12L, 17L, 9L, 7L, 4L), code = c(137L, 
137L, 137L, 137L, 137L, 137L, 137L, 137L, 137L, 137L, 137L, 137L, 
137L, 137L, 137L, 137L, 137L, 137L, 137L, 137L, 137L, 137L, 137L, 
137L, 137L, 137L, 137L, 137L, 137L, 137L, 137L, 137L, 137L, 137L, 
137L, 137L, 137L), action = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L)), row.names = c(NA, 
-37L), class = "data.frame")

agg
   code  item med  q90 action
1:  137 11202  11 18.6      0