按百分位数将向量拆分

6
我需要将一个未知长度的有序向量在R中拆分为“前10%,...,后10%”。
例如,如果我有vector <- order(c(1:98928)),我想将其拆分为10个不同的向量,每个向量大约表示总长度的10%。
我尝试使用split <- split(vector, 1:10),但由于我不知道向量的长度,如果它不是多个,则会出现以下错误:

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

即使它是多个并且函数有效,split()也不会保留原始向量的顺序。这是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语言的新手,尝试了很多方法都没有成功,有人知道如何做吗?

5个回答

8

问题陈述

将一个已排序的向量x每10%打成10个块。

请注意,这有两种解释:

  1. Cutting by vector index:

    split(x, floor(10 * seq.int(0, length(x) - 1) / length(x)))
    
  2. Cutting by vector values (say, quantiles):

    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

5
如果您的向量以列形式(命名为vec)存在于数据帧中,您可以简单地执行以下操作:
df$new_vec <- cut(df$vec , breaks = quantile(df$vec, c(0, .1,.., 1)), 
                labels=1:10, include.lowest=TRUE)

我知道仅仅为了说谢谢而留言并不好(因此点赞),但我花了几个小时的时间寻找这个解决方案,它非常有效。谢谢! - Phil

4
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) 

2
如果向量已排序,那么您只需创建一个与向量相同长度的组变量并在其上拆分即可。在实际情况下,这将需要更多的努力,因为向量的长度可能不是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

0

您可以使用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])
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接