将矢量拆分为R中的块

Seb*_*ian 208 r vector

我必须在R中将一个向量分成n个大小相等的块.我找不到任何基本函数来做到这一点.谷歌也没有把我带到任何地方.所以这就是我想出来的,希望它可以帮助某些人.

x <- 1:10
n <- 3
chunk <- function(x,n) split(x, factor(sort(rank(x)%%n)))
chunk(x,n)
$`0`
[1] 1 2 3

$`1`
[1] 4 5 6 7

$`2`
[1]  8  9 10
Run Code Online (Sandbox Code Playgroud)

任何评论,建议或改进都非常受欢迎和赞赏.

干杯,塞巴斯蒂安

Har*_*lan 294

将单行分割为大小为20的块:

split(d, ceiling(seq_along(d)/20))
Run Code Online (Sandbox Code Playgroud)

更多细节:我认为您需要的只是seq_along():split()ceiling():

> d <- rpois(73,5)
> d
 [1]  3  1 11  4  1  2  3  2  4 10 10  2  7  4  6  6  2  1  1  2  3  8  3 10  7  4
[27]  3  4  4  1  1  7  2  4  6  0  5  7  4  6  8  4  7 12  4  6  8  4  2  7  6  5
[53]  4  5  4  5  5  8  7  7  7  6  2  4  3  3  8 11  6  6  1  8  4
> max <- 20
> x <- seq_along(d)
> d1 <- split(d, ceiling(x/max))
> d1
$`1`
 [1]  3  1 11  4  1  2  3  2  4 10 10  2  7  4  6  6  2  1  1  2

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

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

$`4`
 [1]  7  6  2  4  3  3  8 11  6  6  1  8  4
Run Code Online (Sandbox Code Playgroud)

  • 这个问题要求大小相等的"n"块.这会得到一个未知数量的大小为'n`的块.我遇到了同样的问题并使用了@mathheadinclouds的解决方案. (30认同)
  • @rrs:split(d,ceiling(seq_along(d)/(length(d)/ n))) (8认同)
  • 从d1的输出可以看出,这个答案不会将d分成相同大小的组(4显然更短).因此它没有回答这个问题. (2认同)

mat*_*uds 65

chunk2 <- function(x,n) split(x, cut(seq_along(x), n, labels = FALSE)) 
Run Code Online (Sandbox Code Playgroud)


小智 31

simplified version...
n = 3
split(x, sort(x%%n))
Run Code Online (Sandbox Code Playgroud)

  • 这很有用,但是请记住,这仅适用于数值向量。 (2认同)
  • @drmariod 还可以通过执行 `split(x, sort(1:length(x) %% n))` 来扩展 (2认同)

Sco*_*and 19

试试ggplot2函数,cut_number:

library(ggplot2)
x <- 1:10
n <- 3
cut_number(x, n) # labels = FALSE if you just want an integer result
#>  [1] [1,4]  [1,4]  [1,4]  [1,4]  (4,7]  (4,7]  (4,7]  (7,10] (7,10] (7,10]
#> Levels: [1,4] (4,7] (7,10]

# if you want it split into a list:
split(x, cut_number(x, n))
#> $`[1,4]`
#> [1] 1 2 3 4
#> 
#> $`(4,7]`
#> [1] 5 6 7
#> 
#> $`(7,10]`
#> [1]  8  9 10
Run Code Online (Sandbox Code Playgroud)

  • 这不适用于拆分 [此评论] 中定义的 `x`、`y` 或 `z`(/sf/ask/232283341/ -r#comment84830680_3318333)。尤其是,它会对结果进行排序,结果可能好也可能不好,具体取决于应用程序。 (2认同)

Ton*_*yal 18

这会将它与你所拥有的不同,但我认为仍然是一个很好的列表结构:

chunk.2 <- function(x, n, force.number.of.groups = TRUE, len = length(x), groups = trunc(len/n), overflow = len%%n) { 
  if(force.number.of.groups) {
    f1 <- as.character(sort(rep(1:n, groups)))
    f <- as.character(c(f1, rep(n, overflow)))
  } else {
    f1 <- as.character(sort(rep(1:groups, n)))
    f <- as.character(c(f1, rep("overflow", overflow)))
  }

  g <- split(x, f)

  if(force.number.of.groups) {
    g.names <- names(g)
    g.names.ordered <- as.character(sort(as.numeric(g.names)))
  } else {
    g.names <- names(g[-length(g)])
    g.names.ordered <- as.character(sort(as.numeric(g.names)))
    g.names.ordered <- c(g.names.ordered, "overflow")
  }

  return(g[g.names.ordered])
}
Run Code Online (Sandbox Code Playgroud)

根据您希望如何格式化,它将为您提供以下内容:

> x <- 1:10; n <- 3
> chunk.2(x, n, force.number.of.groups = FALSE)
$`1`
[1] 1 2 3

$`2`
[1] 4 5 6

$`3`
[1] 7 8 9

$overflow
[1] 10

> chunk.2(x, n, force.number.of.groups = TRUE)
$`1`
[1] 1 2 3

$`2`
[1] 4 5 6

$`3`
[1]  7  8  9 10
Run Code Online (Sandbox Code Playgroud)

使用以下设置运行几个计时:

set.seed(42)
x <- rnorm(1:1e7)
n <- 3
Run Code Online (Sandbox Code Playgroud)

然后我们得到以下结果:

> system.time(chunk(x, n)) # your function 
   user  system elapsed 
 29.500   0.620  30.125 

> system.time(chunk.2(x, n, force.number.of.groups = TRUE))
   user  system elapsed 
  5.360   0.300   5.663 
Run Code Online (Sandbox Code Playgroud)

编辑:在我的函数中从as.factor()更改为as.character()使它快两倍.


Ric*_*ron 13

还有一些变种......

> x <- 1:10
> n <- 3
Run Code Online (Sandbox Code Playgroud)

注意,你不需要在factor这里使用这个函数,但你仍然希望sort你的第一个向量是o/w 1 2 3 10:

> chunk <- function(x, n) split(x, sort(rank(x) %% n))
> chunk(x,n)
$`0`
[1] 1 2 3
$`1`
[1] 4 5 6 7
$`2`
[1]  8  9 10
Run Code Online (Sandbox Code Playgroud)

或者您可以分配字符索引,上面左上方的数字代码:

> my.chunk <- function(x, n) split(x, sort(rep(letters[1:n], each=n, len=length(x))))
> my.chunk(x, n)
$a
[1] 1 2 3 4
$b
[1] 5 6 7
$c
[1]  8  9 10
Run Code Online (Sandbox Code Playgroud)

或者您可以使用存储在向量中的明文名称.请注意,使用sortx字母顺序排列标签时获取连续值:

> my.other.chunk <- function(x, n) split(x, sort(rep(c("tom", "dick", "harry"), each=n, len=length(x))))
> my.other.chunk(x, n)
$dick
[1] 1 2 3
$harry
[1] 4 5 6
$tom
[1]  7  8  9 10
Run Code Online (Sandbox Code Playgroud)


Mat*_*fou 9

另一种可能性是splitIndices包中的函数parallel

library(parallel)
splitIndices(20, 3)
Run Code Online (Sandbox Code Playgroud)

给出:

[[1]]
[1] 1 2 3 4 5 6 7

[[2]]
[1]  8  9 10 11 12 13

[[3]]
[1] 14 15 16 17 18 19 20
Run Code Online (Sandbox Code Playgroud)


Sig*_*gyF 8

您可以将mdsummer建议的分割/剪切与分位数组合以创建偶数组:

split(x,cut(x,quantile(x,(0:n)/n), include.lowest=TRUE, labels=FALSE))
Run Code Online (Sandbox Code Playgroud)

这为您的示例提供了相同的结果,但对于偏斜变量则没有.


fra*_*nkc 7

split(x,matrix(1:n,n,length(x))[1:length(x)])

或许这更清楚,但同样的想法:
split(x,rep(1:n, ceiling(length(x)/n),length.out = length(x)))

如果你想要它的订购,请在它周围进行排序


ver*_*our 7

如果你不喜欢split() 你不喜欢matrix()(与它的悬挂NAS),有这样的:

chunk <- function(x, n) (mapply(function(a, b) (x[a:b]), seq.int(from=1, to=length(x), by=n), pmin(seq.int(from=1, to=length(x), by=n)+(n-1), length(x)), SIMPLIFY=FALSE))
Run Code Online (Sandbox Code Playgroud)

就像split(),它返回一个列表,但它不会浪费时间或空间与标签,因此它可能更高效。


小智 6

我需要相同的功能并阅读以前的解决方案,但是我还需要将不平衡的块放在最后,即如果我有10个元素将它们分成3个向量,那么我的结果应该有3个向量,分别为3,4个元素.所以我使用了以下内容(为了便于阅读,我保留了未优化的代码,否则不需要很多变量):

chunk <- function(x,n){
  numOfVectors <- floor(length(x)/n)
  elementsPerVector <- c(rep(n,numOfVectors-1),n+length(x) %% n)
  elemDistPerVector <- rep(1:numOfVectors,elementsPerVector)
  split(x,factor(elemDistPerVector))
}
set.seed(1)
x <- rnorm(10)
n <- 3
chunk(x,n)
$`1`
[1] -0.6264538  0.1836433 -0.8356286

$`2`
[1]  1.5952808  0.3295078 -0.8204684

$`3`
[1]  0.4874291  0.7383247  0.5757814 -0.3053884
Run Code Online (Sandbox Code Playgroud)


eAn*_*ndy 6

这是另一种变体.

注意:使用此示例,您将在第二个参数中指定CHUNK SIZE

  1. 所有的块都是统一的,除了最后一块;
  2. 最后一个最差的是小块,从不大于块大小.

chunk <- function(x,n)
{
    f <- sort(rep(1:(trunc(length(x)/n)+1),n))[1:length(x)]
    return(split(x,f))
}

#Test
n<-c(1,2,3,4,5,6,7,8,9,10,11)

c<-chunk(n,5)

q<-lapply(c, function(r) cat(r,sep=",",collapse="|") )
#output
1,2,3,4,5,|6,7,8,9,10,|11,|
Run Code Online (Sandbox Code Playgroud)


FXQ*_*der 6

使用基数R rep_len

x <- 1:10
n <- 3

split(x, rep_len(1:n, length(x)))
# $`1`
# [1]  1  4  7 10
# 
# $`2`
# [1] 2 5 8
# 
# $`3`
# [1] 3 6 9
Run Code Online (Sandbox Code Playgroud)

如前所述,如果要排序索引,只需:

split(x, sort(rep_len(1:n, length(x))))
# $`1`
# [1] 1 2 3 4
# 
# $`2`
# [1] 5 6 7
# 
# $`3`
# [1]  8  9 10
Run Code Online (Sandbox Code Playgroud)


小智 5

通过简单地使用索引来分割向量的简单函数 - 无需过度复杂化

vsplit <- function(v, n) {
    l = length(v)
    r = l/n
    return(lapply(1:n, function(i) {
        s = max(1, round(r*(i-1))+1)
        e = min(l, round(r*i))
        return(v[s:e])
    }))
}
Run Code Online (Sandbox Code Playgroud)