Ответ 1
Почему не просто что-то вроде df[rep(1:nrow(df),times = 3),]
для расширения кадра данных, а затем добавьте дополнительный столбец, как и вы, с помощью df$Time <- rep(1:lengthTime, each=nrRow)
?
У меня есть data.frame df
, и я хочу, чтобы каждая строка в этом df
дублировалась lengthTime
раза и добавлялся новый столбец, который насчитывает от 1 до lengthTime
для каждой строки в df
> .
Я знаю, это звучит довольно сложно, но в основном я хочу применить expand.grid
к df
. Вот уродливое обходное решение, и у меня есть ощущение, что наиболее простое решение (возможно, даже функция base-R?):
df <- data.frame(ID = rep(letters[1:3], each=3),
CatA = rep(1:3, times = 3),
CatB = letters[1:9])
lengthTime <- 3
nrRow <- nrow(df)
intDF <- df
for (i in 1:(lengthTime - 1)) {
df <- rbind(df, intDF)
}
df$Time <- rep(1:lengthTime, each=nrRow)
Я думал, что могу просто использовать expand.grid(df, 1:lengthTime)
, но это не работает. outer
тоже не повезло. Так кто-нибудь знает хорошее решение?
Почему не просто что-то вроде df[rep(1:nrow(df),times = 3),]
для расширения кадра данных, а затем добавьте дополнительный столбец, как и вы, с помощью df$Time <- rep(1:lengthTime, each=nrRow)
?
Прошло некоторое время, так как этот вопрос был опубликован, но я недавно наткнулся на него, ища только что в названии, а именно expand.grid
, который работает для фреймов данных. Опубликованные ответы касаются более конкретного вопроса OP, поэтому, если кто-то ищет более общее решение для фреймов данных, здесь немного более общий подход:
expand.grid.df <- function(...) Reduce(function(...) merge(..., by=NULL), list(...))
# For the example in the OP
expand.grid.df(df, data.frame(1:lengthTime))
# More generally
df1 <- data.frame(A=1:3, B=11:13)
df2 <- data.frame(C=51:52, D=c("Y", "N"))
df3 <- data.frame(E=c("+", "-"))
expand.grid.df(df1, df2, df3)
Вы также можете просто сделать простой merge
с помощью NULL
в качестве столбца слияния (что приведет к тому, что merge
сделает простую комбинаторную репликацию данных):
data.frame(time=1:lengthTime) %>% merge(iris, by=NULL)
Оператор трубопровода %>%
поступает из пакета magrittr
(dplyr
также автоматически присоединяет его) и просто использовался для улучшения удобочитаемости. Вы также можете просто сделать merge(iris, data.frame(...), by=NULL)
Быстрое обновление
Теперь есть функция cross() в пакете tidyr, которая может использоваться вместо слияния, несколько быстрее и возвращает tbl_df/tibble.
data.frame(time=1:10) %>% merge(iris, by=NULL)
data.frame(time=1:10) %>% tidyr::crossing(iris)
Это работает:
REP <- rep(1:nrow(df), 3)
df2 <- data.frame(df[REP, ], Time = rep(1:3, each = 9))
rownames(df2) <- NULL
df2
A data.table
решение:
> library(data.table)
> ( df <- data.frame(ID = rep(letters[1:3], each=3),
+ CatA = rep(1:3, times = 3),
+ CatB = letters[1:9]) )
ID CatA CatB
1 a 1 a
2 a 2 b
3 a 3 c
4 b 1 d
5 b 2 e
6 b 3 f
7 c 1 g
8 c 2 h
9 c 3 i
> ( DT <- data.table(df)[, lapply(.SD, function(x) rep(x,3))][, Time:=rep(1:3, each=nrow(df0))] )
ID CatA CatB Time
1: a 1 a 1
2: a 2 b 1
3: a 3 c 1
4: b 1 d 1
5: b 2 e 1
6: b 3 f 1
7: c 1 g 1
8: c 2 h 1
9: c 3 i 1
10: a 1 a 2
11: a 2 b 2
12: a 3 c 2
13: b 1 d 2
14: b 2 e 2
15: b 3 f 2
16: c 1 g 2
17: c 2 h 2
18: c 3 i 2
19: a 1 a 3
20: a 2 b 3
21: a 3 c 3
22: b 1 d 3
23: b 2 e 3
24: b 3 f 3
25: c 1 g 3
26: c 2 h 3
27: c 3 i 3
Другой:
> library(data.table)
> ( df <- data.frame(ID = rep(letters[1:3], each=3),
+ CatA = rep(1:3, times = 3),
+ CatB = letters[1:9]) )
> DT <- data.table(df)
> rbindlist(lapply(1:3, function(i) cbind(DT, Time=i)))
ID CatA CatB Time
1: a 1 a 1
2: a 2 b 1
3: a 3 c 1
4: b 1 d 1
5: b 2 e 1
6: b 3 f 1
7: c 1 g 1
8: c 2 h 1
9: c 3 i 1
10: a 1 a 2
11: a 2 b 2
12: a 3 c 2
13: b 1 d 2
14: b 2 e 2
15: b 3 f 2
16: c 1 g 2
17: c 2 h 2
18: c 3 i 2
19: a 1 a 3
20: a 2 b 3
21: a 3 c 3
22: b 1 d 3
23: b 2 e 3
24: b 3 f 3
25: c 1 g 3
26: c 2 h 3
27: c 3 i 3