此帖子与此我的帖子相关 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%以上的值,然后必须用计算出的中位数来代替这些值。 但必须对所有零类别的操作以及每个组的代码+项目
执行中位数替换在执行一类动作之后,再次将零类别用于返回列。为此,我也必须找到上面计算出的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是所有肥胖的中位数。
答案 0 :(得分:1)
我对您的问题的理解:
code
和item
,您都有一系列带有action == 1
的行。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)
如果我理解正确,每个action
,code
组的item
列由一个零序列组成,之后是一个连续的零,最后由另一个零序列构成。每组只有一个连胜。
OP想要
action == 0
的行)的90%分位数和中位数,在第一行之前action == 1
和分别为第一 7行 后最后一行,action == 1
,每个{{1} },code
组。 item
中出现1个连号之前,少于14个零或少于7个零,则将计算可用零动作行的统计信息。action
的行的return
值复制到output
。action == 0
值大于或等于90%分位数的{em> ,则替换第一个{{1 }}每行。这可以通过使用一些准备工作通过联接更新来解决。关键部分是确定连胜之前的零动作行和之后的零动作行。对于第一行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