Я должен разделить вектор на n блоки равного размера в R. Я не мог найти, что любая основная функция сделала это. Также Google не получил меня нигде. Таким образом, вот то, что я придумал, надо надеяться, это помогает кому-то некоторые где.
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
Любые комментарии, предложения или улучшения действительно приветствуются и ценятся.
С наилучшими пожеланиями, Sebastian
Однострочное разбиение 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
split(x,matrix(1:n,n,length(x))[1:length(x)])
возможно, это более понятно, но идея та же:
split(x,rep(1:n, ceiling(length(x)/n),length.out = length(x)))
если хотите упорядочить, накиньте sort
Это разделит его иначе, чем у вас, но Я думаю, что это все еще довольно хорошая структура списка:
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 () в моей функции сделал это в два раза быстрее.
Еще несколько вариантов кучи ...
> x <- 1:10
> n <- 3
Обратите внимание, что вам не нужно использовать здесь функцию factor
, но вы все равно хотите отсортировать
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
Или вы можете использовать имена в виде простых слов, хранящиеся в векторе. Обратите внимание, что при использовании 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
Вы можете комбинировать разделение / вырезание, как предлагает mdsummer, с квантилем для создания четных групп:
split(x,cut(x,quantile(x,(0:n)/n), include.lowest=TRUE, labels=FALSE))
Это дает тот же результат для вашего примера, но не для искаженных переменных.