计算 90% 并用 R 中的组中位数替换它

Posted

技术标签:

【中文标题】计算 90% 并用 R 中的组中位数替换它【英文标题】:calculation of 90 percentile and replacement of it by median by groups in R 【发布时间】:2019-01-26 12:51:47 【问题描述】:

这里是部分数据。

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,它先于一类动作。 (一后我们不碰零)

这些统计信息必须在一类操作之前按 14 个零计算

然后我必须找到上面计算的超过 90 个百分位数的值,然后这些值必须由计算的中位数代替。

在一个类别的动作之后再次归零类别返回列。对于它,我也必须找到上面计算的超过 90 个百分位数的值,然后必须用上面计算的中位数替换这个值(当计算 14 个零时)。

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

结果可以在输出列中。

在这里更清楚所需的输出。

对于123+234 组 90 perc=39,5 中位数=12

222+333 90 perc=39,5 中位数=12

 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     **12**
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     16
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     **12**
39  123  234     28      0     28
40  123  234     30      0     30
41  123  234     92      0     **12**
42  123  234      4      0      4
43  123  234      1      0      1
44  123  234     83      0     **12**
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     **12**
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     16
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     **12**
86  222  333     28      0     28
87  222  333     30      0     30
88  222  333     92      0     **12**
89  222  333      4      0      4
90  222  333      1      0      1
91  222  333     83      0     **12**
92  222  333      3      0      3
93  222  333     16      0     16
94  222  333      4      0      4

** 我标记了值被中位数替换的行。

【问题讨论】:

为什么第 41 行和第 77 行的 output 显示的值是 16 而不是 12?他们也应该被麦地恩取代。 【参考方案1】:

tidyverse:

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

【讨论】:

谢谢。我可以请您更正代码吗?我写了注意,计算是由一类动作之前的 14 个零完成的,但对于所有零类动作并用中位数替换,并为每个组代码+项目执行。如何做到这 90 个百分位数是针对一类动作之前的 14 个零 + 一类动作之后的 7 个零计算的,但是对于所有零类动作并为每个组代码 + 项目执行替换为中位数。 请在发布答案之前检查结果。您的答案返回的中位数为 14,而 OP 预计中位数为 12。原因是您的答案计算了每组中 all 零行的统计信息,而 OP 要求仅考虑 第一行之前的最后 14 行 action == 1【参考方案2】:

如果我理解正确,OP 想要

    计算最后 14 个“零操作行”(即带有 action == 0 的行)的 90% 分位数和中位数第一行带有 action == 1 的行之前,分别为每个 @987654325 @、item 组。 (这意味着每组只有一个action == 1 值。 将return 的值复制到output 中,用于所有带有action == 0 的行。 如果 output 值大于 90% 分位数,则将每个组中第一个 action == 1 行之前的所有个零操作行中的中位数替换为中位数。

这可以通过在非等值连接中更新并进行一些准备来解决

library(data.table)
# mark the zero acton rows before the the action period
setDT(mydat)[, zero_before := cummax(action), by = .(code, item)]
# compute median and 90% quantile for that last 14 rows before each action period 
agg <- mydat[zero_before == 0, 
             quantile(tail(return, 14L), c(0.5, 0.9)) %>% 
               as.list()  %>% 
               set_names(c("med", "q90")) %>% 
               c(.(zero_before = 0)), by = .(code, item)]
agg

   code item med  q90 zero_before
1:  123  234  12 39.5           0
2:  222  333  12 39.5           0

# append output column
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
    , zero_before := NULL]

由于mydat 有 94 行,我们将只显示更新的行:

mydat[return != output]
    code item return action output
 1:  123  234     90      0     12
 2:  123  234     41      0     12
 3:  123  234     41      0     12
 4:  123  234     92      0     12
 5:  123  234     83      0     12
 6:  222  333     90      0     12
 7:  222  333     41      0     12
 8:  222  333     41      0     12
 9:  222  333     92      0     12
10:  222  333     83      0     12

【讨论】:

我尝试在***.com/questions/52074105/… 此处应用您的代码并收到错误。你能帮我理解为什么会发生错误吗? 链接的问题完全不同。我发布了一个答案there。

以上是关于计算 90% 并用 R 中的组中位数替换它的主要内容,如果未能解决你的问题,请参考以下文章

如何计算向量中的位数? (在 R 中)

R语言 平均值,中位数和模式

在包含 is.na() 和中位数的 R 函数中传递列名

postgresql中的第n个百分位数计算

如何从 PHP 中的双精度数组中计算第 n 个百分位数?

R语言分位数计算Percentiles