在R中按组将一列中的元素转置为多列
Transpose elements in a column into multiple columns by group in R
给定数据
test_id <- c(1, 1, 1, 2, 2, 2)
test_values <- c(1, 2, 3, 4, 5, 6)
test_df <- data.frame(test_id, test_values)
test_df
test_id test_values
1 1
1 2
1 3
2 4
2 5
2 6
我想将值列转置为一行
test_df$x1 <- c(1, 1, 1, 4, 4, 4)
test_df$x2 <- c(2, 2, 2, 5, 5, 5)
test_df$x3 <- c(3, 3, 3, 6, 6, 6)
test_df
test_id test_values x1 x2 x3
1 1 1 2 3
1 2 1 2 3
1 3 1 2 3
2 4 4 5 6
2 5 4 5 6
2 6 4 5 6
我最初想到的是
test_df <- test_df %>%
group_by(test_id) %>%
mutate(X = t(test_values))%>%
ungroup()
但这不允许将列拆分为多个条目 - x1、x2、x3。任何有关如何解决此问题的建议都将不胜感激!
你可以用枢轴和连接来做到这一点:
test_id <- c(1, 1, 1, 2, 2, 2)
test_values <- c(1, 2, 3, 4, 5, 6)
test_df <- data.frame(test_id, test_values)
test_df %>%
group_by(test_id) %>%
mutate(var = seq_along(test_values)) %>%
pivot_wider(values_from="test_values", names_from="var", names_prefix="x") %>%
left_join(test_df %>% dplyr::select(test_id, test_values), .)
# Joining, by = "test_id"
# test_id test_values x1 x2 x3
# 1 1 1 1 2 3
# 2 1 2 1 2 3
# 3 1 3 1 2 3
# 4 2 4 4 5 6
# 5 2 5 4 5 6
# 6 2 6 4 5 6
或者,如果您只希望每个 test_id
一行,您可以只删除最后一行:
test_df %>%
group_by(test_id) %>%
mutate(var = seq_along(test_values)) %>%
pivot_wider(values_from="test_values", names_from="var", names_prefix="x")
# # A tibble: 2 x 4
# # Groups: test_id [2]
# test_id x1 x2 x3
# <dbl> <dbl> <dbl> <dbl>
# 1 1 1 2 3
# 2 2 4 5 6
这里有一个data.table
选项
setDT(test_df)[,c(.(test_values = test_values),data.frame(outer(rep(1,.N),test_values))),test_id]
其中 outer
用于进行转置,因此
test_id test_values X1 X2 X3
1: 1 1 1 2 3
2: 1 2 1 2 3
3: 1 3 1 2 3
4: 2 4 4 5 6
5: 2 5 4 5 6
6: 2 6 4 5 6
使用 tidyr
中的 unnest_wider
library(dplyr)
library(tidyr)
test_df %>%
group_by(test_id) %>%
transmute(col1 = list(test_values)) %>%
unnest_wider(c(col1)) %>%
rename_at(vars(starts_with("...")),
~ str_replace(., fixed("..."), "x")) %>%
ungroup
-输出
# A tibble: 6 x 4
# test_id x1 x2 x3
# <dbl> <dbl> <dbl> <dbl>
#1 1 1 2 3
#2 1 1 2 3
#3 1 1 2 3
#4 2 4 5 6
#5 2 4 5 6
#6 2 4 5 6
或使用base R
test_df[paste0('x', 1:3)] <- do.call(rbind, with(test_df,
split(test_values, test_id)))[test_df$test_id,]
给定数据
test_id <- c(1, 1, 1, 2, 2, 2)
test_values <- c(1, 2, 3, 4, 5, 6)
test_df <- data.frame(test_id, test_values)
test_df
test_id test_values
1 1
1 2
1 3
2 4
2 5
2 6
我想将值列转置为一行
test_df$x1 <- c(1, 1, 1, 4, 4, 4)
test_df$x2 <- c(2, 2, 2, 5, 5, 5)
test_df$x3 <- c(3, 3, 3, 6, 6, 6)
test_df
test_id test_values x1 x2 x3
1 1 1 2 3
1 2 1 2 3
1 3 1 2 3
2 4 4 5 6
2 5 4 5 6
2 6 4 5 6
我最初想到的是
test_df <- test_df %>%
group_by(test_id) %>%
mutate(X = t(test_values))%>%
ungroup()
但这不允许将列拆分为多个条目 - x1、x2、x3。任何有关如何解决此问题的建议都将不胜感激!
你可以用枢轴和连接来做到这一点:
test_id <- c(1, 1, 1, 2, 2, 2)
test_values <- c(1, 2, 3, 4, 5, 6)
test_df <- data.frame(test_id, test_values)
test_df %>%
group_by(test_id) %>%
mutate(var = seq_along(test_values)) %>%
pivot_wider(values_from="test_values", names_from="var", names_prefix="x") %>%
left_join(test_df %>% dplyr::select(test_id, test_values), .)
# Joining, by = "test_id"
# test_id test_values x1 x2 x3
# 1 1 1 1 2 3
# 2 1 2 1 2 3
# 3 1 3 1 2 3
# 4 2 4 4 5 6
# 5 2 5 4 5 6
# 6 2 6 4 5 6
或者,如果您只希望每个 test_id
一行,您可以只删除最后一行:
test_df %>%
group_by(test_id) %>%
mutate(var = seq_along(test_values)) %>%
pivot_wider(values_from="test_values", names_from="var", names_prefix="x")
# # A tibble: 2 x 4
# # Groups: test_id [2]
# test_id x1 x2 x3
# <dbl> <dbl> <dbl> <dbl>
# 1 1 1 2 3
# 2 2 4 5 6
这里有一个data.table
选项
setDT(test_df)[,c(.(test_values = test_values),data.frame(outer(rep(1,.N),test_values))),test_id]
其中 outer
用于进行转置,因此
test_id test_values X1 X2 X3
1: 1 1 1 2 3
2: 1 2 1 2 3
3: 1 3 1 2 3
4: 2 4 4 5 6
5: 2 5 4 5 6
6: 2 6 4 5 6
使用 tidyr
unnest_wider
library(dplyr)
library(tidyr)
test_df %>%
group_by(test_id) %>%
transmute(col1 = list(test_values)) %>%
unnest_wider(c(col1)) %>%
rename_at(vars(starts_with("...")),
~ str_replace(., fixed("..."), "x")) %>%
ungroup
-输出
# A tibble: 6 x 4
# test_id x1 x2 x3
# <dbl> <dbl> <dbl> <dbl>
#1 1 1 2 3
#2 1 1 2 3
#3 1 1 2 3
#4 2 4 5 6
#5 2 4 5 6
#6 2 4 5 6
或使用base R
test_df[paste0('x', 1:3)] <- do.call(rbind, with(test_df,
split(test_values, test_id)))[test_df$test_id,]