在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,]