让x
是数字非负数据(主要是<10)和qx <- quantile(x, probs = pq)
的向量,其中length(pq)
通常> length(x) * (3/4)
。
我需要一个qx
的索引向量,称为q_i
,其中x[i]
属于分位数qx[q_i[i]]
。
顾名思义,要注意的是qx
中可能存在非唯一值,例如如果x
为零,则返回多个0值分位数,并可能有其他重复值。我想通过(a)回收这些等效分位数的索引序列,或(b)随机分配等效分位数的索引来处理这些情况。我想我更喜欢选项(a),但是对任何一个解决方案都会有用。
我在想有一种有效的方法-我本质上是使用for循环来完成此操作的,但是我正在寻找矢量化方法。
我开始尝试使用cut(),这当然不允许非唯一中断。我发现this question here有什么帮助,因为我发现了.bincode()
函数,该函数确实允许非唯一中断。但是,它没有“分配”索引的规则-它只会使用每个重复的分位数的第一个的索引。
此问题的一些示例代码:
x <- c(5.8, 0.0, 16.1, 5.8, 3.5, 13.8, 6.9, 5.8, 11.5, 9.2, 11.5,
3.5, 0.0, 8.1, 0.0, 4.6, 5.8, 3.5, 0.0, 10.3, 0.0, 0.0,
3.5, 6.9, 3.5)
pq <- seq(0, 1, length.out = 20)
qx <- quantile(x, pq)
# quantiles for reference, rounded for readability
round(as.numeric(qx), 2)
[1] 0.00 0.00 0.00 0.00 0.18 3.50 3.50 3.50 3.62 5.04 5.80 5.80 5.97
[14] 6.90 7.72 9.14 10.55 11.50 13.19 16.10
q_i <- .bincode(x, qx, include.lowest = TRUE)
q_i
[1] 10 1 19 10 5 19 13 10 17 16 17 5 1 15 1 9 10 5 1 16 1 1 5 13 5
如果.bincode()
很神奇,这就是我想要的结果,我可以说服它做我需要做的事情:
在上述情况(a)下:
q_i
[1] 10 1 19 11 5 19 13 10 17 16 17 6 2 15 3 9 11 7 1 16 2 3 5 13 6
在情况(b)下,它看起来与上面正好一样的可能性很小。或类似的东西:
q_i
[1] 10 1 19 10 6 19 13 11 17 16 17 5 3 15 2 9 11 6 2 16 1 3 5 13 7
谢谢!
答案 0 :(得分:0)
好的,我有一些代码可以在场景a(回收)下从您的代码继续到最后的q_i。我希望它更漂亮,但还是希望能有所帮助。
注意:
-假设length(x)
> length(qx)
> length(x)/2
。
-在代码下面的解释中,q_i
指问题的结尾处的值,在发生任何值的回收或替换之前。
## Start off with the code provided in the question...
# 1. For each distinct q_i, calculate the number of occurrances, and how far we can recycle it
df <- data.frame(lower=sort(unique(q_i)), freq=as.integer(table(q_i)))
df$upper <- c(df$lower[-1] - df$lower[-nrow(df)], 1) + df$lower - 1
df$upper <- df$upper - as.numeric(df$upper > df$lower & qx[df$upper] < qx[df$upper + 1])
# 2. Identify when there's a (single) number we can't recycle, and identify which position it's in
# e.g. is it the third time q_i == 10?
df$special_case <- rep(NA, nrow(df))
df$special_case[df$lower < df$upper] <- sapply(df$lower[df$lower < df$upper], function(low) {
bin <- x[q_i==low]
if(length(unique(bin)) > 1) {
return(match(min(bin), bin))}
else return(NA)})
# 3. For each row of df, get a vector of (possibly recycled) numbers
recycled <- apply(df, 1, function(x) {
out <- rep(x["lower"]:x["upper"], length.out=x["freq"])
# This part modifies the vector created to handle the 'special case'
if(!is.na(x["special_case"])) {
out[x["special_case"]] <- x["lower"]
if(x["special_case"] < x["freq"]) {
out[(x["special_case"]+1):x["freq"]] <- out[x["special_case"]:(x["freq"]-1)]
}
}
return(out)
})
# 3b. Make this follow the same order as q_i
q_i_final <- unlist(recycled)[order(order(q_i))]
q_i_final
[1] 10 1 19 11 5 19 13 10 17 16 17 6 2 15 3 9 11 7 1 16 2 3 5 13 6
基本概念是什么?
对于q_i
的每个值,我们可以很容易地计算出应该回收的数量(如果我们要回收的话)。通常,我们最多可以回收比下一个最大值q_i
小一个。然后,我们可以使用rep
创建一个回收向量来替换q_i
中的内容,例如用10
替换四个10 11 10 11
。
还有什么要考虑的?
这个基本思想假设,对于q_i
的每个值,x
的对应值可以全部回收,也可以全部不回收。通常是这种情况,但是您也可以使用q_i
的值,其中所有小节一个可以回收,即一个k使得x[k]
<{qx[q_i[k]+1]
,但一个或多个j,其中q_i[j]
= q_i[k]
以及x[j]
= qx[q_i[j]+1]
。
应该识别这种“特殊”情况(尽管问题数据中不存在),并且必须注意不要将此值也回收。
x[5]
> x[12]
,但是q_i[5]
= q_i[12]
= 4
。现在,在上述“基本概念”下,q_i
= 4
的所有值都将被回收,因此我们将拥有q_i_final[12]
= 5
。这是一个问题,因为我们希望x[12]
在qx[q_i_final[12]]
和qx[q_i_final[12]+1]
之间,但事实并非如此,因为它严格都小于两者。事实证明,我们可以回收q_i
= 4的所有值,x[12]
除外。新代码:
# Code copied from question, changes as follows:
# x[12] changed from 3.5 to 3.4
# x[13] and x[21] changed from 0.0 to 10.0
x <- c(5.8, 0.0, 16.1, 5.8, 3.5, 13.8, 6.9, 5.8, 11.5, 9.2, 11.5,
3.4, 10.0, 8.1, 0.0, 4.6, 5.8, 3.5, 0.0, 10.3, 10.0, 0.0,
3.5, 6.9, 3.5)
pq <- seq(0, 1, length.out = 20)
qx <- quantile(x, pq)
q_i <- .bincode(x, qx, include.lowest = T, right=T)
q_i
[1] 8 1 19 8 4 19 12 8 17 14 17 4 15 13 1 8 8 4 1 16 15 1 4 12 4
答案 1 :(得分:0)
此代码基于@hodgenovice的答案,但未考虑特殊情况。
它还有一个附加条件,可以正确回收第一个重复分位数序列的值。这是我这个问题的错误,我最初从期望的答案中省略了q_i
中的4
,但它应该是为分配了q_i
的数据值回收的索引之一由1
的{{1}}中获得。
.bincode()