2012-07-27 51 views
22

我有data.frame df,我想,在這個df每一行復制lengthTime倍,並且將新列補充說從1計數到lengthTimedf每一行。替代expand.grid爲data.frames

我知道,這聽起來很複雜,但我基本上想要的是將expand.grid應用於df。這裏是一個醜陋的解決辦法,我有一種感覺,有大部分是一個簡單的解決方案(甚至基本-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也沒有帶來任何運氣。那麼有誰知道一個好的解決方案?

回答

13

爲什麼不像df[rep(1:nrow(df),times = 3),]那樣擴展數據框,然後像上面那樣添加額外的列,使用df$Time <- rep(1:lengthTime, each=nrRow)

2

這工作:

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

我真的沒有什麼比喬蘭打敗了我40秒,但我會離開它,因爲它稍微更明確。 – 2012-07-27 18:44:10

+0

先到先得,所以我接受了他的回答;-)但是你們倆都+1。這是一個非常好的解決方案! – 2012-07-27 19:00:57

36

這已經有一段時間,因爲這個問題被張貼,但我最近碰到它的標題尋找只是事情,即一個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) 
+1

美麗的解決方案。 – Ariel 2014-07-26 17:12:10

+1

哇。這是一項偉大的工作。 – jknowles 2017-02-28 22:15:54

9

你也可以使用NULL爲做一個簡單的merge合併列(這將導致merge做簡單的組合數據複製):

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

的管道運營商%>%來自magrittr包(dplyr也會自動將其附加),並只用於IMPRO可讀性。你也可以簡單的做merge(iris, data.frame(...), by=NULL)

+0

我想你可能想提一下你從哪裏拿到'%>%'...... – 2014-11-03 14:30:18

+0

@DavidArenburg謝謝你的提示。 – 2014-11-04 14:44:23

1

一個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 
5

快速更新

現在已經開始交叉()封裝內tidyr功能,可以用來代替合併,速度稍快,並返回一個tbl_df/tibble。

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

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