2010-07-23 153 views
157

我必须在R中将向量拆分为n个相同大小的块。我找不到任何基本函数来完成此操作。谷歌也没有让我到任何地方。所以这就是我想到的,希望它能帮助某个地方的某个人。将一个向量拆分为R块

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 

任何意见,建议或改进,真的欢迎和赞赏。

干杯, 塞巴斯蒂安

+4

是的,这是非常不清楚,你得到的是解决“大小相等的n个块”。但是,也许这也让你在那里:x < - 1:10; n < - 3; split(x,cut(x,n,labels = FALSE)) – mdsumner 2010-07-23 14:08:03

+0

问题中的解决方案和前面的注释中的解决方案都不正确,因为如果向量具有重复条目,则它们可能无法正常工作。试试这个: > foo <-c(rep(1,12),rep(2,3),rep(3,3)) [1] 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 3 3 3 >块(FOO,2) (给出错误的结果) >块(FOO,3) (也有错) – mathheadinclouds 2013-04-29 09:21:35

+0

(继续前面的评论) 为什么呢? rank(x)不需要是整数 > rank(c(1,1,2,3)) [1] 1.5 1.5 3.0 4.0 所以这就是问题中的方法失败的原因。 (x,n)分割(x,cut(seq_along(x),n,labels = FALSE)) – mathheadinclouds 2013-04-29 09:33:14

回答

7

你可以合并拆分/切割,通过mdsummer的建议,与位数来创造出组:

split(x,cut(x,quantile(x,(0:n)/n), include.lowest=TRUE, labels=FALSE)) 

这为你的例子同样的结果,但不对于偏斜变量。

12

到桩数更多的变种...

> x <- 1:10 
> n <- 3 

注意,你不需要在这里使用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 

或者你可以指定字符索引,副左侧数字的上方蜱:

> 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 

或者您可以使用存储在向量中的纯字词名称。请注意,使用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 
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]) 
} 

哪将根据你想要的格式给你以下内容:

> 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 

使用这些设置运行几个定时:

set.seed(42) 
x <- rnorm(1:1e7) 
n <- 3 

然后我们有以下结果:

> 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 

编辑:从as.factor改变()来as.character()在我的功能使得它快两倍。

5

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

也许这是更为明确的,但同样的想法:
split(x,rep(1:n, ceiling(length(x)/n),length.out = length(x)))

如果你想订购,扔掉它周围

232

一个班轮分裂d成大小20的大块:

split(d, ceiling(seq_along(d)/20)) 

更多细节:我认为所有你需要的是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 
+18

问题要求大小相同的“n”个块。这会让你获得数量未知的大小为“n”的块。我遇到了同样的问题,并使用@mathheadinclouds提供的解决方案。 – rrs 2014-04-21 18:26:59

+2

从d1的输出中可以看出,这个答案不会将d分成相等大小的组(4显然更短)。因此它不回答这个问题。 – Calimo 2015-01-23 16:39:58

+6

@rrs:split(d,ceiling(seq_along(d)/(length(d)/ n))) – gkcn 2015-06-05 11:45:13

42
chunk2 <- function(x,n) split(x, cut(seq_along(x), n, labels = FALSE)) 
5

我需要同样的功能,并已经阅读以前的解决方案,但我也需要有平衡块是在年底,即如果我有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 
6

这里的另一种变体。

注:此示例你的第二个参数

  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,| 
2

感谢@Sebastian这个function

chunk <- function(x,y){ 
     split(x, factor(sort(rank(row.names(x))%%y))) 
     } 
2

如果你不喜欢split(),你不介意的NA填充你的短尾巴:

chunk <- function(x, n) { if((length(x)%%n)==0) {return(matrix(x, nrow=n))} else {return(matrix(append(x, rep(NA, n-(length(x)%%n))), nrow=n))} } 

返回的列的ma trix([,1:ncol])是您正在寻找的机器人。

2

如果你不喜欢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)) 

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

13

尝试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 
+0

这不适用于拆分[this comment]中定义的'x','y'或'z'(https://stackoverflow.com/questions/3318333/split-a-vector-into-chunks-在-R#comment84830680_3318333)。具体来说,它根据应用对结果进行分类,结果可能会也可能不会。 – Kalin 2018-02-21 17:42:04

+0

相反,[此评论](https://stackoverflow.com/questions/3318333/split-a-vector-into-chunks-in-r#comment84830878_3318333)。 – Kalin 2018-02-21 17:48:49

15
simplified version... 
n = 3 
split(x, sort(x%%n)) 
+0

我喜欢这个,因为它给你尽可能大小的块(对于分割大任务例如适应有限的RAM或跨多个线程运行任务而言是很好的)。 – alexvpickering 2016-07-21 22:13:20

+1

这很有用,但请记住这只适用于数字向量。 – 2016-08-24 17:49:43

1

我需要一个函数,它接受一个data.table的参数(在引号),另一种说法是对的数量上限该原始data.table的子集中的行。此功能将产生data.tables的任何数量的上限允许:

library(data.table)  
split_dt <- function(x,y) 
    { 
    for(i in seq(from=1,to=nrow(get(x)),by=y)) 
     {df_ <<- get(x)[i:(i + y)]; 
      assign(paste0("df_",i),df_,inherits=TRUE)} 
    rm(df_,inherits=TRUE) 
    } 

此功能给了我一系列data.tables的名字命名的DF_ [数字]与起始行从原来的data.table 。最后的data.table可以是简短的,并填充了NAs,因此您必须将其归入任何剩余的数据。这种类型的功能很有用,因为某些GIS软件限制了您可以导入多少个地址引脚。因此,不建议将数据表分成更小的块,但可能无法避免。通过简单地使用索引拆分矢量

0

简单的功能 - 无需过度复杂化这个

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]) 
    })) 
}