计算 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 中的组中位数替换它的主要内容,如果未能解决你的问题,请参考以下文章