【问题标题】:calculation of 90 percentile and replacement it by median by groups in R using 14 and 7 days intervals使用 14 天和 7 天的间隔计算 90 个百分位数并用 R 组中的中位数替换它
【发布时间】:2019-01-27 10:23:11
【问题描述】:

此帖子与我的帖子相关 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 个零,但是必须对所有零类动作进行中位数替换,并为每个组代码+项目执行

这里是部分数据。

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 个组变量代码+项目。这里有两组:

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 个零,然后在一个零之后计算 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 是所有 obs 的中位数。

【问题讨论】:

  • 请通过添加具有预期输出的示例数据使问题自成一体。
  • @RalfStubner,我编辑了帖子,请检查
  • 为什么第30行和第77行的41的值没有被替换?
  • @RalfStubner,我编辑了帖子。它并没有被我的疏忽所取代。
  • 我知道 90% 的分位数是根据动作阶段之前的 14 个零动作行和动作阶段之后的 7 个零动作行来计算的。中位数是根据每组中的所有个操作行计算还是从所有零个操作行计算?

标签: r dplyr data.table


【解决方案1】:

我对你的问题的理解:

  • 根据codeitem,您有一系列带有action == 1 的行。
  • 您想在该范围之前取 10 行,在该范围之后取 7 行。
  • 对于这 17 行,action == 0 成立,您将获得 90% 的分位数。
  • 比您将带有action == 0所有 行与此分位数进行比较。如果该值大于或等于,则将其替换为所有行的平均值独立于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 列,该列确定是否将特定行包含在分位数计算中。

【讨论】:

  • 请告诉我。为什么当我不在测试数据中使用 ths 脚本时,但对于所有数据,我得到错误 mutate_impl(.data, dots) 中的错误:列mask 的长度必须为 61(组大小)或 1,而不是 62。怎么能我修复它。谢谢
  • 我编辑了帖子,怀疑错误的原因。有没有可能。
  • @D.Joe 请查看更新后的代码。除了修复“因一个错误而关闭”之外,我还检查在一个块之前/之后是否有少于 10/7 个零。
  • 在你的代码中,一切都很好,除了一件事。它必须在一类动作之前找到 10 个零,在一类动作之后找到 7 个零,然后它必须通过这 17 个零计算中位数。检查真实数据,我看到它计算了所有观察值的中位数。我编辑了帖子,请以真实数据为例。
  • @D.Joe 这就是我在第四个要点中所写的内容。计算所有元素的平均值。否则,在您的示例数据中,该男子不是 14 岁!但是,修复很简单:只需使用 mean(mask * return, na.rm = TRUE)
【解决方案2】:

如果我理解正确,每个codeitem 组的action 列由一系列零组成,后跟一个连续的零,最后由另一个零序列完成。每组只有一个。

OP 想要

  1. 计算最后 14 个“零操作行”(即带有action == 0 的行)的 90% 分位数和中位数之前带有@987654325 的第一行@andfirst 7 行 after 最后一行带有action == 1,分别用于每个codeitem 组。
  2. 来自 OP 的编辑:如果 action 中的一连串之前的零少于 14 个或之后的零少于 7 个,则将为可用的零操作行计算统计信息。
  3. return 的值复制到output 中,用于所有带有action == 0 的行。
  4. 如果output 值大于或等于 中的第一个action == 1 行之前的所有 个零操作行中的中位数,则将其替换为中位数每个组。
    请注意,OP 正在讨论 查找超过 90 个百分位数的值,这意味着 更大 关系,但预期结果也替换了返回 等于 的值> 90% 的分位数。

这可以通过在非等值连接中更新并进行一些准备来解决。关键部分是识别一连串之前的零操作行和之后的零操作行。这是由cummax(action) 对第一个action == 1 行之前的零操作行完成的,而对于第一个action == 1 之后的零操作行则由一个双重反转的rev(cummax(rev(action))) 完成,该行从反向运行。

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

现在我们可以将所有零操作行的return 复制到output,并在更新非等值连接中替换大于90% 分位数的output 值:

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 包含 94 行,我们将仅显示 returnoutput 不同的行:

    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

编辑:第二个用例

OP 提供了第二个用例:

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")

在连续一连串之后只有 3 个零操作行。 对于这个用例,我们得到

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

mydat[return != output]
    item return code action output
1: 11202     19  137      0     11
2: 11202     20  137      0     11
3: 11202     19  137      0     11
4: 11202     21  137      0     11
5: 11202     25  137      0     11
6: 11202     21  137      0     11

【讨论】:

    猜你喜欢
    • 2019-01-26
    • 2019-02-04
    • 2021-10-23
    • 1970-01-01
    • 2012-11-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-01
    • 1970-01-01
    相关资源
    最近更新 更多