Подтвердить что ты не робот

Альтернатива expand.grid для data.frames

У меня есть 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 тоже не повезло. Так кто-нибудь знает хорошее решение?

4b9b3361

Ответ 1

Почему не просто что-то вроде df[rep(1:nrow(df),times = 3),] для расширения кадра данных, а затем добавьте дополнительный столбец, как и вы, с помощью df$Time <- rep(1:lengthTime, each=nrRow)?

Ответ 2

Прошло некоторое время, так как этот вопрос был опубликован, но я недавно наткнулся на него, ища только что в названии, а именно 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)

Ответ 3

Вы также можете просто сделать простой merge с помощью NULL в качестве столбца слияния (что приведет к тому, что merge сделает простую комбинаторную репликацию данных):

data.frame(time=1:lengthTime) %>% merge(iris, by=NULL) 

Оператор трубопровода %>% поступает из пакета magrittr (dplyr также автоматически присоединяет его) и просто использовался для улучшения удобочитаемости. Вы также можете просто сделать merge(iris, data.frame(...), by=NULL)

Ответ 4

Быстрое обновление

Теперь есть функция cross() в пакете tidyr, которая может использоваться вместо слияния, несколько быстрее и возвращает tbl_df/tibble.

data.frame(time=1:10) %>% merge(iris, by=NULL) 

data.frame(time=1:10) %>% tidyr::crossing(iris) 

Ответ 5

Это работает:

REP <- rep(1:nrow(df), 3)
df2 <- data.frame(df[REP, ], Time = rep(1:3, each = 9))
rownames(df2) <- NULL
df2

Ответ 6

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