Повторяющиеся элементы в векторе с циклом for
Я хочу сделать вектор из 3:50 в R, глядя, как
3 4 4 5 6 6 7 8 8 .. 50 50
Я хочу использовать цикл for В цикле for, но он не делает wat, который я хочу.
f <- c()
for (i in 3:50) {
for(j in 1:2) {
f = c(f, i)
}
}
что с ним не так?
8 ответов
использовать rep
функция, наряду с возможностью использования рециркуляции логического индексирования ...[c(TRUE, FALSE, TRUE, TRUE)]
rep(3:50, each = 2)[c(TRUE, FALSE, TRUE, TRUE)]
## [1] 3 4 4 5 6 6 7 8 8 9 10 10 11 12 12 13 14 14 15 16 16 17 18 18 19
## [26] 20 20 21 22 22 23 24 24 25 26 26 27 28 28 29 30 30 31 32 32 33 34 34 35 36
## [51] 36 37 38 38 39 40 40 41 42 42 43 44 44 45 46 46 47 48 48 49 50 50
если вы используете логический вектор (TRUE
/FALSE
) как индекс (внутри [
]
), a TRUE
приводит к выбору соответствующего элемента и FALSE
ведет к бездействию. Если вектор логического индекса (c(TRUE, FALSE, TRUE, TRUE)
) короче индексированного вектора (rep(3:50, each = 2)
в вашем случае), вектор индекса recyled.
также боковое Примечание: всякий раз, когда вы используйте код R, например
x = c(x, something)
или
x = rbind(x, something)
или аналогично, вы принимаете C-подобный стиль программирования в R. Это делает ваш код unnessecarily сложным и может привести к низкой производительности и проблемам с памятью, если вы работаете с большими (скажем, 200 МБ+) наборами данных. R предназначен, чтобы избавить вас от этих низкоуровневых возиться со структурами данных.
Читайте для получения дополнительной информации о обжорах и их наказании в R Inferno, круг 2: Растущие Объекты.
другой вариант-использовать встроенный rep
:
rep(3:50, rep(1:2, 24))
что дает:
[1] 3 4 4 5 6 6 7 8 8 9 10 10 11 12 12 13 14 14 15 16 16 17 18 18 19 20 20 [28] 21 22 22 23 24 24 25 26 26 27 28 28 29 30 30 31 32 32 33 34 34 35 36 36 37 38 38 [55] 39 40 40 41 42 42 43 44 44 45 46 46 47 48 48 49 50 50
это использует тот факт, что times
-аргумент rep
также может быть числом, вектором, который равен длине х-аргумент.
вы можете обобщить это на:
s <- 3
e <- 50
v <- 1:2
rep(s:e, rep(v, (e-s+1)/2))
еще один вариант, используя сочетание rep
и rep_len
:
v <- 3:50
rep(v, rep_len(1:2, length(v)))
решение на основе sapply
.
as.vector(sapply(0:23 * 2 + 2, function(x) x + c(1, 2, 2)))
# [1] 3 4 4 5 6 6 7 8 8 9 10 10 11 12 12 13 14 14 15 16 16 17 18 18 19 20 20 21 22 22 23 24 24 25 26 26
# [37] 27 28 28 29 30 30 31 32 32 33 34 34 35 36 36 37 38 38 39 40 40 41 42 42 43 44 44 45 46 46 47 48 48 49 50 50
бенчмаркинг
вот сравнение производительности для всех текущих ответов. Результат показывает, что cumsum(rep(c(1, 1, 0), 24)) + 2L
(m8
) является самым быстрым, в то время как rep(3:50, rep(1:2, 24))
(m1
) это почти так же быстро, как m8
.
library(microbenchmark)
library(ggplot2)
perf <- microbenchmark(
m1 = {rep(3:50, rep(1:2, 24))},
m2 = {rep(3:50, each = 2)[c(TRUE, FALSE, TRUE, TRUE)]},
m3 = {v <- 3:50; sort(c(v,v[v %% 2 == 0]))},
m4 = {as.vector(t(cbind(seq(3,49,2),seq(4,50,2),seq(4,50,2))))},
m5 = {as.vector(sapply(0:23 * 2 + 2, function(x) x + c(1, 2, 2)))},
m6 = {sort(c(3:50, seq(4, 50, 2)))},
m7 = {rep(seq(3, 50, 2), each=3) + c(0, 1, 1)},
m8 = {cumsum(rep(c(1, 1, 0), 24)) + 2L},
times = 10000L
)
perf
# Unit: nanoseconds
# expr min lq mean median uq max neval
# m1 514 1028 1344.980 1029 1542 190200 10000
# m2 1542 2570 3083.716 3084 3085 191229 10000
# m3 26217 30329 35593.596 31871 34442 5843267 10000
# m4 43180 48321 56988.386 50891 55518 6626173 10000
# m5 30843 35984 42077.543 37526 40611 6557289 10000
# m6 40611 44209 50092.131 46779 50891 446714 10000
# m7 13879 16449 19314.547 17478 19020 6309001 10000
# m8 0 1028 1256.715 1028 1542 71454 10000
самый простой способ, который я могу найти, - это создать другой, содержащий только even
значения (на основе намерения OP), а затем просто объединяют два вектора. Примером может быть:
v <- 3:50
sort(c(v,v[v %% 2 == 0]))
# [1] 3 4 4 5 6 6 7 8 8 9 10 10 11 12 12 13 14 14 15 16 16
# 17 18 18 19 20 20 21 22 22 23 24 24 25 26 26 27 28 28
#[40] 29 30 30 31 32 32 33 34 34 35 36 36 37 38 38 39 40 40 41 42 42
# 43 44 44 45 46 46 47 48 48 49 50 50
вот решение без петли 1 линия:
> as.vector(t(cbind(seq(3,49,2),seq(4,50,2),seq(4,50,2))))
[1] 3 4 4 5 6 6 7 8 8 9 10 10 11 12 12 13 14 14 15 16 16 17
[23] 18 18 19 20 20 21 22 22 23 24 24 25 26 26 27 28 28 29 30 30 31 32
[45] 32 33 34 34 35 36 36 37 38 38 39 40 40 41 42 42 43 44 44 45 46 46
[67] 47 48 48 49 50 50
он формирует матрицу, первый столбец которой является нечетными числами в диапазоне 3: 50 и чьи второй и третий столбцы являются четными числами в этом диапазоне, а затем (взяв транспонирование) считывает его строка за строкой.
проблема с вашим вложенным циклом заключается в том, что фундаментальный шаблон имеет длину 3, повторяемую 24 раза (вместо шаблона длины 2, повторяемого 50 раз). Если вы хотите использовать вложенный цикл, внешний цикл может повторяться 24 раза, а внутренний-3. Первый проход через внешнюю петлю мог построить 3,4,4. Второй проход мог бы построить 5,6,6. Так далее. Поскольку есть 24*3 = 72 элемента, вы можете предварительно выделить вектор (используя f <- vector("numeric",74)
) Так что вы не растете его по 1 элементу за раз. Идиома f <- c(f,i)
что вы используете на каждом этапе копирует все старые элементы только для создания нового вектора, который только на 1 элемент длиннее. Здесь слишком мало элементов для того, чтобы действительно сделайте разницу, но если вы попытаетесь создать большие векторы таким образом, производительность может быть потрясающе плохой.
вот метод, который объединяет части нескольких других ответов.
rep(seq(3, 50, 2), each=3) + c(0, 1, 1)
[1] 3 4 4 5 6 6 7 8 8 9 10 10 11 12 12 13 14 14 15 16
[21] 16 17 18 18 19 20 20 21 22 22 23 24 24 25 26 26 27 28 28 29
[41] 30 30 31 32 32 33 34 34 35 36 36 37 38 38 39 40 40 41 42 42
[61] 43 44 44 45 46 46 47 48 48 49 50 50
вот второй метод с использованием cumsum
cumsum(rep(c(1, 1, 0), 24)) + 2L
Это должно быть очень быстро.
еще одна идея, хотя и не конкурирующая в скорости с самыми быстрыми решениями:
mat <- matrix(3:50,nrow=2)
c(rbind(mat,mat[2,]))
# [1] 3 4 4 5 6 6 7 8 8 9 10 10 11 12 12 13 14 14 15 16 16 17 18 18 19 20 20 21 22 22
# [31] 23 24 24 25 26 26 27 28 28 29 30 30 31 32 32 33 34 34 35 36 36 37 38 38 39 40 40 41 42 42
# [61] 43 44 44 45 46 46 47 48 48 49 50 50