将一个矢量拆分成R中的块
我不得不在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
任何意见,建议或改进,真的欢迎和赞赏。
干杯,塞巴斯蒂安
单线划分成大小为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
chunk2 <- function(x,n) split(x, cut(seq_along(x), n, labels = FALSE))
这将以不同的方式将其拆分为您所拥有的,但我认为这仍然是一个不错的列表结构:
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()在我的函数做了两倍的速度。
尝试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
堆的几个变种…
> x <- 1:10 > n <- 3
注意,你不需要在这里使用factor
函数,但是你仍然想要sort
你的第一个向量是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
或者,您可以使用存储在向量中的纯字词名称。 请注意,使用sort
来获得x
连续值可以使标签:
> 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
simplified version... n = 3 split(x, sort(x%%n))
您可以将mdsummer建议的split / cut结合分位数来创建偶数组:
split(x,cut(x,quantile(x,(0:n)/n), include.lowest=TRUE, labels=FALSE))
这给你的例子相同的结果,但不是偏斜的变量。
这是另一个变体。
注意:在这个示例中,您正在第二个参数中指定CHUNK SIZE
- 所有的大块都是统一的,除了最后一个;
- 最后最后会变小,从不比块大小大。
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,|
split(x,matrix(1:n,n,length(x))[1:length(x)])
也许这更清楚,但是同样的想法:
split(x,rep(1:n, ceiling(length(x)/n),length.out = length(x)))
如果你想要订购的话,可以在它周围进行排序
我需要相同的功能,并已阅读以前的解决方案,但我也需要有不平衡的块在最后,即如果我有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
感谢@Sebastian这个功能
chunk <- function(x,y){ split(x, factor(sort(rank(row.names(x))%%y))) }
如果你不喜欢split()
,你不介意NAs填充你的短尾巴:
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))} }
返回矩阵([,1:ncol])的列是你正在寻找的机器人。
如果你不喜欢split()
并且你不喜欢matrix()
(它有悬而未决的NA),那就是:
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()
一样,它会返回一个列表,但是它不会浪费时间或者带有标签的空间,因此可能会更高效。
我需要一个函数,它接受data.table(在引号中)的参数,而另一个参数是原始data.table的子集中行数的上限。 这个函数可以产生任意数量的数据。表上限允许:
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) }
这个函数为我提供了一系列名为df_ [number]的data.tables,其名称中的原始data.table起始行。 最后一个data.table可以是简短的,并填充了NAs,所以你必须将它分回到剩下的任何数据。 这种类型的功能很有用,因为某些GIS软件限制了您可以导入多少个地址引脚。 因此,将data.tables切片成较小的块可能不被推荐,但可能无法避免。