r-按百分比分割向量



我需要将R中已排序的未知长度向量拆分为"顶部10%,…,底部10%"例如,如果我有vector <- order(c(1:98928)),我想把它分成10个不同的向量,每个向量大约占总长度的10%。

我试过使用split <- split(vector, 1:10),但由于我不知道矢量的长度,如果不是多重,我会得到这个错误

数据长度不是拆分变量的倍数

即使它的倍数和函数有效,split()也不能保持我的原始向量的顺序。这就是拆分的结果:

split(c(1:10) , 1:2)
$`1`
[1] 1 3 5 7 9
$`2`
[1]  2  4  6  8 10

这就是我想要的:

$`1`
[1] 1 2 3 4 5
$`2`
[1]  6  7  8  9 10

我是R的新手,我尝试了很多事情都没有成功,有人知道怎么做吗?

问题陈述

将已排序的向量x每隔10%分解为10个块。

注意,对此有两种解释:

  1. 按矢量索引切割

    split(x, floor(10 * seq.int(0, length(x) - 1) / length(x)))
    
  2. 按矢量值(如分位数)切割

    split(x, cut(x, quantile(x, prob = 0:10 / 10, names = FALSE), include = TRUE))
    

在下面,我将使用数据进行演示:

set.seed(0); x <- sort(round(rnorm(23),1))

特别是,我们的示例数据是正态分布的,而不是均匀分布的,因此按指数切割和按值切割有很大不同。

结果

按指数切割

#$`0`
#[1] -1.5 -1.2 -1.1
#
#$`1`
#[1] -0.9 -0.9
#
#$`2`
#[1] -0.8 -0.4
#
#$`3`
#[1] -0.3 -0.3 -0.3
#
#$`4`
#[1] -0.3 -0.2
#
#$`5`
#[1] 0.0 0.1
#
#$`6`
#[1] 0.3 0.4 0.4
#
#$`7`
#[1] 0.4 0.8
#
#$`8`
#[1] 1.3 1.3
#
#$`9`
#[1] 1.3 2.4

按分位数切割

#$`[-1.5,-1.06]`
#[1] -1.5 -1.2 -1.1
#
#$`(-1.06,-0.86]`
#[1] -0.9 -0.9
#
#$`(-0.86,-0.34]`
#[1] -0.8 -0.4
#
#$`(-0.34,-0.3]`
#[1] -0.3 -0.3 -0.3 -0.3
#
#$`(-0.3,-0.2]`
#[1] -0.2
#
#$`(-0.2,0.14]`
#[1] 0.0 0.1
#
#$`(0.14,0.4]`
#[1] 0.3 0.4 0.4 0.4
#
#$`(0.4,0.64]`
#numeric(0)
#
#$`(0.64,1.3]`
#[1] 0.8 1.3 1.3 1.3
#
#$`(1.3,2.4]`
#[1] 2.4

如果您将向量作为数据帧中的列(名为vec),您可以简单地执行以下操作:

df$new_vec <- cut(df$vec , breaks = quantile(df$vec, c(0, .1,.., 1)), 
                labels=1:10, include.lowest=TRUE)
x <- 1:98
y <- split(x, ((seq(length(x))-1)*10)%/%length(x)+1)

说明:

seq(length(x)) = 1..98
seq(length(x))-1 = 0..97
(seq(length(x))-1)*10 = (0, 10, ..., 970)
# each number about 10% of values, totally 98
((seq(length(x))-1)*10)%/%length(x) = (0, ..., 0, 1, ..., 1, ..., 9, ..., 9) 
# each number about 10% of values, totally 98
seq(length(x))-1)*10)%/%length(x)+1 = (1, ..., 1, 2, ..., 2, ..., 10, ..., 10)  
# splits first ~10% of numbers to 1, next ~10% of numbers to 2 etc.
split(x, ((seq(length(x))-1)*10)%/%length(x)+1) 

如果对向量进行排序,那么您只需创建一个具有相同向量长度的组变量并在其上进行拆分。在实际情况下,这将需要更多的努力,因为向量的长度可能不是10的倍数,但对于您的玩具示例,您可以执行:

n = 2
split(x, rep(1:n, each = length(x)/n))
# $`1`
# [1] 1 2 3 4 5
# $`2`
# [1]  6  7  8  9 10

一个真实的例子,矢量的长度不是组数量的倍数:

vec = 1:13
n = 3
split(vec, sort(seq_along(vec)%%n))
# $`0`
# [1] 1 2 3 4
# $`1`
# [1] 5 6 7 8 9
# $`2`
# [1] 10 11 12 13

您可以使用sum()函数来确定提取向量部分的位置。使用大于(>)或小于(<)所指示的百分位数的逻辑运算符。由于sum()在TRUE时赋值为1,在FALSE时赋值为0。首先对向量的元素进行排序是很重要的。

# A vector with numbers from 1 to 100
data <- seq(1,100)
# 25th percentile value and 75th percentile value
ps1 <- quantile(data,probs=c(0.25))
ps2 <- quantile(data,probs=c(0.75))
# Positions to split
position1 <- sum(data<=ps1)
position2 <- sum(data<=ps2)
# Split with positions in a sorted data
sort(data)[position1:position2]

结果是

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75

以同样的方式,您可以按照以下方式将有序向量划分为10个相等的部分,指定百分位数

# A vector with numbers from 1 to 100
data <- seq(1,100)
# sub vectors based on percentiles
subvectors <- quantile(data,probs=c(0.10,0.20,0.30,0.40,0.50,0.60,0.70,0.80,0.90,1))
for (i in 1:length(subvectors)-1){
  
  # Percentiles values
  ps1 <- subvectors[i]
  ps2 <- subvectors[i+1]
  
  # Positions to split
  position1 <- sum(data<=ps1)
  position2 <- sum(data<=ps2)
  
  # Split with positions in a sorted data
  print(sort(data)[position1:position2])
}

最新更新