[英]How do I reshape wide nested data to long format in R?
我有一個看起來像這樣的數據集,其中每個教室(ID)有不同的團隊(A,B),每個團隊有 3 個分數(例如,team1_1 team1_2 team1_3)和每個團隊的平均分數。 換句話說,教室 (ID) 1 有兩個團隊(A,B),而教室 2 有兩個團隊(A,B),依此類推。
df <- data.frame(ID=1:5,
Team1=c("A","A","A","A","A"),
Team1_1=c(2,3,1,3,4),
Team1_2=c(4,2,2,3,2),
Team1_3=c(5,3,4,5,4),
Team1_Mean=c(3.67,2.67,2.33,3.67,3.33),
Team2=c("B","B","B","B","B"),
Team2_1=c(4,3,3,5,4),
Team2_2=c(4,2,2,5,2),
Team2_3=c(4,4,4,5,3),
Team2_Mean=c(4,3,3,5,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,1,2,2,3,3,4,4,5,5),
Team=c("A", "B", "A", "B", "A", "B", "A", "B", "A", "B"),
Score1=c(2,4,3,3,1,3,3,5,4,5),
Score2=c(4,4,2,2,2,2,3,5,2,2),
Score3=c(5,4,3,4,4,4,5,5,4,3),
Mean=c(3.67,4,2.67,3,2.33,3,3.67,5,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) function 但 R 說這已被棄用,所以我嘗試了 tidyr 的“收集”方法,但似乎這些努力不適用於列表。
我的問題是:
非常感謝提前!
一個選項是pivot_longer
。 我們可以rename
列重命名為“Team1”、“Team2”以添加分隔符 ( _
) 以及后綴“Team”,然后使用pivot_longer
將cols
重新調整為“long”格式,將除“ID”(- -ID
) 之外的所有列指定為,將names_sep
指定為_
,然后rename
以數字開頭的列名,並附加'Score'作為前綴
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
的基本 R 選項
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
您可以使用data.table中的melt並傳遞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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.