如何解决如何在 R 中将宽嵌套数据重塑为长格式?
我有一个看起来像这样的数据集,其中每个教室(ID)有不同的团队(A,B),每个团队有 3 个分数(例如,team1_1 team1_2 team1_3)和每个团队的平均分数.换句话说,Classroom (ID) 1 有两个团队(A,B),Classroom 2 有两个团队(A,B),依此类推。
df <- data.frame(ID=1:5,Team1=c("A","A","A"),Team1_1=c(2,3,1,4),Team1_2=c(4,2,2),Team1_3=c(5,4,5,Team1_Mean=c(3.67,2.67,2.33,3.67,3.33),Team2=c("B","B","B"),Team2_1=c(4,Team2_2=c(4,Team2_3=c(4,3),Team2_Mean=c(4,3))
ID Team1 Team1_1 Team1_2 Team1_3 Team1_Mean Team2 Team2_1 Team2_2 Team2_3 Team2_Mean
1 A 2 4 5 3.67 B 4 4 4 4
2 A 3 2 3 2.67 B 3 2 4 3
3 A 1 2 4 2.33 B 3 2 4 3
4 A 3 3 5 3.67 B 5 5 5 5
5 A 4 2 4 3.33 B 4 2 3 3
我想重新整理数据,以便以长格式列出每个团队,如下所示:
df2 <- data.frame(ID=c(1,5),Team=c("A",score1=c(2,score2=c(4,score3=c(5,Mean=c(3.67,3.33,3))
ID Team score1 score2 score3 Mean
1 A 2 4 5 3.67
1 B 4 4 4 4.00
2 A 3 2 3 2.67
2 B 3 2 4 3.00
3 A 1 2 4 2.33
3 B 3 2 4 3.00
4 A 3 3 5 3.67
4 B 5 5 5 5.00
5 A 4 2 4 3.33
5 B 5 2 3 3.00
在我看来,我认为将每个团队的数据放在一个列表中,重新整理成长格式,然后取消嵌套数据就行了,但这并不容易。我的第一步是这样的:
df <- df %>% nest(items = c("Team1","Team1_1","Team1_2","Team1_3","Team1_Mean"))
names(df)[names(df) == "items"] <- "Team1"
df <- df %>% nest(items = c("Team2","Team2_1","Team2_2","Team2_3","Team2_Mean"))
names(df)[names(df) == "items"] <- "Team2"
# A tibble: 5 x 3
ID Team1 Team2
<int> <list> <list>
1 1 <tibble [1 × 5]> <tibble [1 × 5]>
2 2 <tibble [1 × 5]> <tibble [1 × 5]>
3 3 <tibble [1 × 5]> <tibble [1 × 5]>
4 4 <tibble [1 × 5]> <tibble [1 × 5]>
5 5 <tibble [1 × 5]> <tibble [1 × 5]>
从那里我尝试了我常用的 reshape2 (melt) 函数,但 R 说这已被弃用,所以我尝试了 tidyr 的“收集”方法,但这些努力似乎不适用于列表。
我的问题是:
- 如何实现我想要的结果?
- 我的数据集包含数百个 ID 和团队,所以我不想像上面那样输入每个变量;我该如何简化它以减少硬编码的使用?
非常感谢!
解决方法
一个选项是 pivot_longer
。我们可以 rename
列 'Team1','Team2' 添加定界符 (_
) 以及后缀 'Team',然后使用 pivot_longer
指定cols
作为除 'ID' (-ID
) 之外的所有内容,将 names_sep
指定为 _
,然后 rename
以数字开头并附加 '分数'作为前缀
library(dplyr)
library(tidyr)
library(stringr)
df %>%
rename_at(vars(matches("^Team\\d+$")),~ str_c(.,"_Team")) %>%
pivot_longer(cols = -ID,names_to = c("grp",".value"),names_sep="_")%>%
rename_at(vars(matches('^\\d+')),~ str_c("Score",.)) %>%
select(-grp)
-输出
# A tibble: 10 x 6
# ID Team Score1 Score2 Score3 Mean
# <int> <chr> <dbl> <dbl> <dbl> <dbl>
# 1 1 A 2 4 5 3.67
# 2 1 B 4 4 4 4
# 3 2 A 3 2 3 2.67
# 4 2 B 3 2 4 3
# 5 3 A 1 2 4 2.33
# 6 3 B 3 2 4 3
# 7 4 A 3 3 5 3.67
# 8 4 B 5 5 5 5
# 9 5 A 4 2 4 3.33
#10 5 B 4 2 3 3
,
这是一个使用 stack
+ gsub
+ unstack
q <- unstack(
transform(
stack(df),ind = gsub("(?<=Team)\\d+","",ind,perl = TRUE)
)
)
q$ID <- rep(q$ID,max(lengths(q)) / length(q$ID))
q <- type.convert(q,as.is = TRUE)
dfout <- data.frame(q)[order(q$ID),]
给出
> dfout
ID Team Team_1 Team_2 Team_3 Team_Mean
1 1 A 2 4 5 3.67
6 1 B 4 4 4 4.00
2 2 A 3 2 3 2.67
7 2 B 3 2 4 3.00
3 3 A 1 2 4 2.33
8 3 B 3 2 4 3.00
4 4 A 3 3 5 3.67
9 4 B 5 5 5 5.00
5 5 A 4 2 4 3.33
10 5 B 4 2 3 3.00
,
您可以使用 melt 中的 data.table 并传递一个 patterns 列表以及新的列名:
result <- melt(setDT(df),id=c("ID"),measure = patterns(Team = "Team\\d$",Score1 = "Team\\d_1$",Score2 = "Team\\d_2$",Score3 = "Team\\d_3$",Mean = ".+Mean$"))
result[order(ID),!c("variable")]
ID Team Score1 Score2 Score3 Mean
1: 1 A 2 4 5 3.67
2: 1 B 4 4 4 4.00
3: 2 A 3 2 3 2.67
4: 2 B 3 2 4 3.00
5: 3 A 1 2 4 2.33
6: 3 B 3 2 4 3.00
7: 4 A 3 3 5 3.67
8: 4 B 5 5 5 5.00
9: 5 A 4 2 4 3.33
10: 5 B 4 2 3 3.00
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。