Повторить data.frame N раз
У меня есть следующий фрейм данных
data.frame(a = c(1,2,3),b = c(1,2,3)) ab 1 1 1 2 2 2 3 3 3
и я хочу превратить его в
ab 1 1 1 2 2 2 3 3 3 4 1 1 5 2 2 6 3 3 7 1 1 8 2 2 9 3 3
или повторить N раз. Есть ли простая функция для этого в R? Благодаря!
- Упорядочить базовые графики и таблицы grid.tables на одной странице
- Обозначения осевых меток форматирования на грань в ggplot / R
- Создать zip-файл: команда выполнения ошибок "" имеет статус 127
- Поиск процента в подгруппе с использованием group_by и суммирование
- Невозможно выполнить цикл с пакетом листов R для создания нескольких карт
- Исключить группы, которые имеют разные значения
- R grep: есть ли оператор AND?
- Проблемы с установкой пакета devtools
- Условное слияние / замена в R
- Разделить строку строки фрейма данных на несколько столбцов
- Форматирование дат с помощью scale_x_date в ggplot2
- Ошибка преобразования длинного списка data.frames (~ 1 миллион) в единый файл data.frame с использованием do.call и ldply
- Участок с условными цветами на основе значений в R
EDIT: обновлен до лучшего современного R-ответа.
Вы можете использовать replicate()
, а затем rbind
результат. Имена ростов автоматически изменяются для запуска от 1: ноль.
d <- data.frame(a = c(1,2,3),b = c(1,2,3)) n <- 3 do.call("rbind", replicate(n, d, simplify = FALSE))
Более традиционный способ - использовать индексирование, но здесь изменение розового имени не совсем так аккуратно (но более информативно):
d[rep(seq_len(nrow(d)), n), ]
Ниже приведены усовершенствования, описанные выше, первые два с использованием функционального программирования purrr, идиоматический purrr:
purrr::map_df(seq_len(3), ~d)
и менее идиоматический purrr (идентичный результат, хотя и более неудобный):
purrr::map_df(seq_len(3), function(x) d)
и, наконец, с помощью индексации, а не списка, используйте dplyr
:
d %>% slice(rep(row_number(), 3))
Для объектов data.frame
это решение в несколько раз быстрее, чем @ mdsummer и @ wojciech-sobala’s.
d[rep(seq_len(nrow(d)), n), ]
Для объектов data.table
@ mdsummer немного быстрее, чем применение выше, после преобразования в data.frame
. Для больших n это может переворачиваться. ,
Полный код:
packages <- c("data.table", "ggplot2", "RUnit", "microbenchmark") lapply(packages, require, character.only=T) Repeat1 <- function(d, n) { return(do.call("rbind", replicate(n, d, simplify = FALSE))) } Repeat2 <- function(d, n) { return(Reduce(rbind, list(d)[rep(1L, times=n)])) } Repeat3 <- function(d, n) { if ("data.table" %in% class(d)) return(d[rep(seq_len(nrow(d)), n)]) return(d[rep(seq_len(nrow(d)), n), ]) } Repeat3.dt.convert <- function(d, n) { if ("data.table" %in% class(d)) d <- as.data.frame(d) return(d[rep(seq_len(nrow(d)), n), ]) } # Try with data.frames mtcars1 <- Repeat1(mtcars, 3) mtcars2 <- Repeat2(mtcars, 3) mtcars3 <- Repeat3(mtcars, 3) checkEquals(mtcars1, mtcars2) # Only difference is row.names having ".k" suffix instead of "k" from 1 & 2 checkEquals(mtcars1, mtcars3) # Works with data.tables too mtcars.dt <- data.table(mtcars) mtcars.dt1 <- Repeat1(mtcars.dt, 3) mtcars.dt2 <- Repeat2(mtcars.dt, 3) mtcars.dt3 <- Repeat3(mtcars.dt, 3) # No row.names mismatch since data.tables don't have row.names checkEquals(mtcars.dt1, mtcars.dt2) checkEquals(mtcars.dt1, mtcars.dt3) # Time test res <- microbenchmark(Repeat1(mtcars, 10), Repeat2(mtcars, 10), Repeat3(mtcars, 10), Repeat1(mtcars.dt, 10), Repeat2(mtcars.dt, 10), Repeat3(mtcars.dt, 10), Repeat3.dt.convert(mtcars.dt, 10)) print(res) ggsave("repeat_microbenchmark.png", autoplot(res))
Пакет dplyr
содержит функцию bind_rows()
которая напрямую объединяет все кадры данных в списке, так что нет необходимости использовать do.call()
вместе с rbind()
:
df <- data.frame(a = c(1, 2, 3), b = c(1, 2, 3)) library(dplyr) bind_rows(replicate(3, df, simplify = FALSE))
Для большого количества bind_rows()
также намного быстрее, чем rbind()
:
library(microbenchmark) microbenchmark(rbind = do.call("rbind", replicate(1000, df, simplify = FALSE)), bind_rows = bind_rows(replicate(1000, df, simplify = FALSE)), times = 20) ## Unit: milliseconds ## expr min lq mean median uq max neval cld ## rbind 31.796100 33.017077 35.436753 34.32861 36.773017 43.556112 20 b ## bind_rows 1.765956 1.818087 1.881697 1.86207 1.898839 2.321621 20 a
d <- data.frame(a = c(1,2,3),b = c(1,2,3)) r <- Reduce(rbind, list(d)[rep(1L, times=3L)])
Просто используйте простую индексацию с функцией повтора.
mydata<-data.frame(a = c(1,2,3),b = c(1,2,3)) #creating your data frame n<-10 #defining no. of time you want repetition of the rows of your dataframe mydata<-mydata[rep(rownames(mydata),n),] #use rep function while doing indexing rownames(mydata)<-1:NROW(mydata) #rename rows just to get cleaner look of data