将数据从长格式转换为具有多个度量列的宽格式

我有困难找出最优雅和灵活的方式来切换数据从长格式到宽格式,当我有多个度量variables我想带。

例如,这是一个长格式的简单数据框。 ID是主题,TIME是时间variables,X和Y是在TIME进行的ID测量:

> my.df <- data.frame(ID=rep(c("A","B","C"), 5), TIME=rep(1:5, each=3), X=1:15, Y=16:30) > my.df ID TIME XY 1 A 1 1 16 2 B 1 2 17 3 C 1 3 18 4 A 2 4 19 5 B 2 5 20 6 C 2 6 21 7 A 3 7 22 8 B 3 8 23 9 C 3 9 24 10 A 4 10 25 11 B 4 11 26 12 C 4 12 27 13 A 5 13 28 14 B 5 14 29 15 C 5 15 30 

如果我只想将TIME的值转换为包含include X的列标题,我知道我可以使用重塑包(或reshape2中的dcast)进行强制转换:

 > cast(my.df, ID ~ TIME, value="X") ID 1 2 3 4 5 1 A 1 4 7 10 13 2 B 2 5 8 11 14 3 C 3 6 9 12 15 

但是我真正想要做的就是将Y作为另一个度量variables,并使列名同时反映度量variables名称和时间值:

  ID X_1 X_2 X_3 X_4 X_5 Y_1 Y_2 Y_3 Y_4 Y_5 1 A 1 4 7 10 13 16 19 22 25 28 2 B 2 5 8 11 14 17 20 23 26 29 3 C 3 6 9 12 15 18 21 24 27 30 

(FWIW,我并不在乎是否所有的X都先跟随Y,或者它们是交错的,如X_1,Y_1,X_2,Y_2等)

我可以通过两次投入长数据并合并结果来得到这个结果,尽pipe列名需要一些工作,如果我需要添加第三或第四个variables,除了X和Y之外,还需要调整它:

 merge( cast(my.df, ID ~ TIME, value="X"), cast(my.df, ID ~ TIME, value="Y"), by="ID", suffixes=c("_X","_Y") ) 

看起来像reshape2和/或plyr中的函数的一些组合应该能够更优雅地做到这一点,我的尝试,以及更干净地处理多个度量variables。 像cast(my.df,ID〜TIME,value = c(“X”,“Y”)),这是无效的。 但我一直无法弄清楚。

任何R向导都可以帮我吗? 谢谢。

为了像你想要的那样处理多个variables,你需要在投射之前melt你所拥有的数据。

 library("reshape2") dcast(melt(my.df, id.vars=c("ID", "TIME")), ID~variable+TIME) 

这使

  ID X_1 X_2 X_3 X_4 X_5 Y_1 Y_2 Y_3 Y_4 Y_5 1 A 1 4 7 10 13 16 19 22 25 28 2 B 2 5 8 11 14 17 20 23 26 29 3 C 3 6 9 12 15 18 21 24 27 30 

编辑根据评论:

dataframe

 num.id = 10 num.time=10 my.df <- data.frame(ID=rep(LETTERS[1:num.id], num.time), TIME=rep(1:num.time, each=num.id), X=1:(num.id*num.time), Y=(num.id*num.time)+1:(2*length(1:(num.id*num.time)))) 

给出不同的结果(所有条目都是2),因为ID / TIME组合不表示唯一的行。 实际上,每个ID / TIME组合有两行。 reshape2为每个可能的variables组合假定一个单一的值,并将应用一个汇总函数来创build一个variables是有多个条目。 这就是为什么有警告

 Aggregation function missing: defaulting to length 

你可以得到一些工作,如果你添加另一个variables,打破冗余。

 my.df$cycle <- rep(1:2, each=num.id*num.time) dcast(melt(my.df, id.vars=c("cycle", "ID", "TIME")), cycle+ID~variable+TIME) 

这是因为cycle / ID / time现在在my.df唯一地定义了一行。

  reshape(my.df, idvar = "ID", timevar = "TIME", direction = "wide") 

  ID X.1 Y.1 X.2 Y.2 X.3 Y.3 X.4 Y.4 X.5 Y.5 1 A 1 16 4 19 7 22 10 25 13 28 2 B 2 17 5 20 8 23 11 26 14 29 3 C 3 18 6 21 9 24 12 27 15 30 

使用data.table_1.9.5 ,这可以在没有melt情况下完成,因为它可以处理多个value.var列。 你可以从here安装它

  library(data.table) dcast(setDT(my.df), ID~TIME, value.var=c('X', 'Y')) # ID 1_X 2_X 3_X 4_X 5_X 1_Y 2_Y 3_Y 4_Y 5_Y #1: A 1 4 7 10 13 16 19 22 25 28 #2: B 2 5 8 11 14 17 20 23 26 29 #3: C 3 6 9 12 15 18 21 24 27 30 

这是一个tidyr软件包的解决scheme,它已经基本上取代了reshape和reshape2。 与这两个软件包一样,数据集首先采用的策略又比较宽泛。

 library(magrittr); requireNamespace("tidyr"); requireNamespace("dplyr") my.df %>% tidyr::gather_(key="variable", value="value", c("X", "Y")) %>% # Make it even longer. dplyr::mutate( # Create the spread key. time_by_variable = paste0(variable, "_", TIME) ) %>% dplyr::select(ID, time_by_variable, value) %>% # Retain these three. tidyr::spread(key=time_by_variable, value=value) # Spread/widen. 

tidyr::gather()调用之后,中间数据集是:

 ID TIME variable value 1 A 1 X 1 2 B 1 X 2 3 C 1 X 3 ... 28 A 5 Y 28 29 B 5 Y 29 30 C 5 Y 30 

最终的结果是:

  ID X_1 X_2 X_3 X_4 X_5 Y_1 Y_2 Y_3 Y_4 Y_5 1 A 1 4 7 10 13 16 19 22 25 28 2 B 2 5 8 11 14 17 20 23 26 29 3 C 3 6 9 12 15 18 21 24 27 30