当我想要携带多个度量变量时,我无法找出将数据从长格式转换为宽格式的最优雅和灵活的方法.
例如,这是一个长格式的简单数据框. ID是主体,TIME是时间可变的,并且X和Y是由测量X在Y:
> 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 X Y
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
Run Code Online (Sandbox Code Playgroud)
如果我只想将TIME的值转换为包含包含X的列标题,我知道我可以使用reshape包中的强制转换(或来自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
Run Code Online (Sandbox Code Playgroud)
但我真正想做的是将Y作为另一个度量变量,并使列名反映度量变量名和时间值:
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
Run Code Online (Sandbox Code Playgroud)
(FWIW,我真的不关心,如果所有X的首先遵循由Y的,或者如果它们交错为ID,TIME,TIME,X,等)
我可以通过cast()两次长数据并合并结果来接近这个,虽然列名需要一些工作,如果我需要添加除X和Y之外的第3或第4个变量,我需要调整它:
merge(
cast(my.df, ID ~ TIME, value="X"),
cast(my.df, ID ~ TIME, value="Y"),
by="ID", suffixes=c("_X","_Y")
)
Run Code Online (Sandbox Code Playgroud)
看起来像某些功能组合reshape和/或dcast()应该能够更优雅地完成我的尝试,以及更干净地处理多个测量变量.有点像reshape2,这是无效的.但我无法弄明白.
任何R-Wizards可以帮助我吗?谢谢.
Set*_*eth 20
reshape(my.df,
idvar = "ID",
timevar = "TIME",
direction = "wide")
Run Code Online (Sandbox Code Playgroud)
给
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
Run Code Online (Sandbox Code Playgroud)
Bri*_*ggs 16
为了处理您想要的多个变量,您需要melt在投射之前获得数据.
library("reshape2")
dcast(melt(my.df, id.vars=c("ID", "TIME")), ID~variable+TIME)
Run Code Online (Sandbox Code Playgroud)
这使
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
Run Code Online (Sandbox Code Playgroud)
根据评论编辑:
数据框
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))))
Run Code Online (Sandbox Code Playgroud)
给出不同的结果(所有条目都是2),因为ID/ TIME组合不表示唯一的行.实际上,每个ID/ TIME组合有两行.reshape2假定每个可能的变量组合都有一个值,并且如果有多个条目,则应用汇总函数来创建单个变量.这就是警告的原因
Aggregation function missing: defaulting to length
Run Code Online (Sandbox Code Playgroud)
如果添加另一个打破冗余的变量,您可以获得一些有用的东西.
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)
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为cycle/ ID/ time现在唯一地定义了一行my.df.
akr*_*run 14
使用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
Run Code Online (Sandbox Code Playgroud)
这是tidyr包的解决方案,它基本上取代了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.
Run Code Online (Sandbox Code Playgroud)
在之后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
Run Code Online (Sandbox Code Playgroud)
最终的结果是:
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
Run Code Online (Sandbox Code Playgroud)
spread()是@JWilliman提出的替代方案.这在功能上等同于pivot_wider()和tidyr::gather()上述组合中,当tidyr::unite()参数为true(这是默认值).
如果你不习惯这种类型的操纵,dplyr::mutate()可能是一个小障碍,因为它是你必须学习和记忆的另一个功能.但是,它的好处包括(a)更简洁的代码(即,四行替换为一行)和(b)重复变量名称的位置更少(即,您不必在dplyr::select()子句中重复/修改变量).
my.df %>%
tidyr::gather(key=variable, value=value, c(X, Y)) %>% # Make it even longer.
tidyr::unite("time_by_variable", variable, TIME, remove=T) %>% # Create the spread key `time_by_variable` while simultaneously dropping `variable` and `TIME`.
tidyr::spread(key=time_by_variable, value=value) # Spread/widen.
Run Code Online (Sandbox Code Playgroud)
该pivot_wider()函数是tidyr的第二代方法(在 tidyr 1.0.0 中发布)。
library(magrittr); requireNamespace("tidyr");
my.df %>%
tidyr::pivot_wider(
names_from = c(TIME), # Can accommodate more variables, if needed.
values_from = c(X, Y)
)
Run Code Online (Sandbox Code Playgroud)
结果:
# A tibble: 3 x 11
ID X_1 X_2 X_3 X_4 X_5 Y_1 Y_2 Y_3 Y_4 Y_5
<fct> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
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
Run Code Online (Sandbox Code Playgroud)
这可能是优选的前tidyr方法
(使用的组合gather()和spread())。
旋转小插图中描述了更多功能。这个例子是特别简洁,因为您想要的规格相匹配的默认值id_cols和names_sep。