2012-07-27 29 views
22

Tôi có một data.frame df và tôi muốn rằng tất cả các hàng trong df này được nhân đôi lengthTime lần và rằng một cột mới được thêm vào mà đếm 1-lengthTime cho mỗi hàng trong df .Thay thế cho expand.grid cho data.frames

Tôi biết, nghe có vẻ khá phức tạp, nhưng điều tôi muốn là áp dụng expand.grid đến df. Dưới đây là một workaround xấu xí và tôi có cảm giác rằng có nhất là một giải pháp dễ dàng hơn (thậm chí có một chức năng cơ bản-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) 

Tôi nghĩ rằng tôi chỉ có thể sử dụng expand.grid(df, 1:lengthTime), nhưng điều đó không làm việc. outer cũng không mang lại bất kỳ may mắn nào. Vì vậy, không ai biết một giải pháp tốt?

Trả lời

13

Tại sao không chỉ một cái gì đó như df[rep(1:nrow(df),times = 3),] để mở rộng khung dữ liệu và sau đó thêm cột bổ sung giống như bạn đã nêu ở trên, với df$Time <- rep(1:lengthTime, each=nrRow)?

2

này hoạt động:

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

Mỏ thực sự không khác gì joran's đã đánh bại tôi 40 giây nhưng tôi sẽ để nó càng rõ ràng hơn. –

+0

Đầu tiên đến, lần đầu tiên phục vụ, vì vậy tôi chấp nhận câu trả lời của mình ;-) Nhưng +1 cho cả hai bạn. Đó là một giải pháp rất gọn gàng! –

36

Nó được một lúc kể từ khi câu hỏi này đã được đăng, nhưng gần đây tôi đi qua nó tìm kiếm chỉ là những điều trong tiêu đề, cụ thể là, một expand.grid mà làm việc cho khung dữ liệu. Những câu trả lời posted giải quyết câu hỏi cụ thể hơn của OP, vì vậy trong trường hợp bất cứ ai đang tìm kiếm một giải pháp tổng quát hơn cho khung dữ liệu, đây là một cách tiếp cận hơi tổng quát hơn:

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

Giải pháp đẹp. – Ariel

+1

Chà. Đây là công việc tuyệt vời. – jknowles

9

Bạn cũng có thể chỉ cần làm một đơn giản merge sử dụng NULL như merge cột (mà sẽ gây merge để làm đơn giản sao chép dữ liệu tổ hợp):

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

các đường ống điều hành %>% xuất phát từ gói magrittr (dplyr cũng sẽ đính kèm nó tự động) và chỉ sử dụng để Impro có thể đọc được. Bạn cũng có thể đơn giản làm merge(iris, data.frame(...), by=NULL)

+0

Tôi nghĩ bạn có thể muốn đề cập đến nơi bạn đã lấy '%>%' từ ... –

+0

@DavidArenburg cảm ơn cho gợi ý. –

1

Một giải pháp 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 

Một số khác:

> 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

Cập nhật nhanh chóng

Hiện nay, cũng là crossing() chức năng trong gói tidyr mà có thể được sử dụng thay vì hợp nhất, nhanh hơn một chút và trả về một tbl_df/tibble.

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

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