【问题标题】:Efficiently reshaping data from wide to long format and combining multiple columns into new variables有效地将数据从宽格式转换为长格式,并将多列组合成新变量
【发布时间】:2020-03-09 10:09:41
【问题描述】:

我必须重塑一个由观察 (obs) 和与观察相关联的元素 (p) 组成的数据集。元素的数据(特征)在附加到观察结果的新列中。

MWE 如下所示:

set.seed(1)

data <- data.frame(obs_id = c(1:3),
                   char1 = sample(1:10, 3),
                   p1 = 1,
                   p1_char = sample(11:20, 3),
                   p2 = 2,
                   p2_char = sample(11:20, 3),
                   p3 = 3,
                   p3_char = sample(11:20, 3))

这会产生如下所示的数据:

> data
  obs_id p1 p1_char1 p2 p2_char1 p3 p3_char1
1      1  1       20  2       12  3       16
2      2  1       16  2       20  3       11
3      3  1       18  2       16  3       13

obs_id是观察结果。 pX表示各种元素,pX_charX表示特征。

现在,我必须创建带有 两个 新列的长格式数据。第一个应命名为p 并包含所有元素编号。所以,太好了。例如,这可以通过 tidyr 包中的 gather 轻松实现:

library(magrittr)
library(tidyr)

data_long1 <- gather(data, key = p_variable, value = p,
                     p1, p2, p3)

过滤掉最初的观察,一切都应该是:

> data_long1 %>% filter(obs_id == 1)
  obs_id p1_char1 p2_char1 p3_char1 p_variable p
1      1       20       12       16         p1 1
2      1       20       12       16         p2 2
3      1       20       12       16         p3 3

现在,第二个新列应该命名为char 并填充元素的特征。我也可以用gather独立堆叠它们。

data_long2 <- gather(data, key = char_variable, value = char,
                     p1_char1, p2_char1, p3_char1)

> data_long2 %>% filter(obs_id == 1)
  obs_id p1 p2 p3 char_variable char
1      1  1  2  3      p1_char1   20
2      1  1  2  3      p2_char1   12
3      1  1  2  3      p3_char1   16

现在,我可以将两者与bind_cols() 结合起来得到我想要的东西

data_long <- bind_cols(data_long1, data_long2)

> data_long %>% 
+   select(obs_id, p, char) %>% 
+   filter(obs_id == 1)
  obs_id p char
1      1 1   20
2      1 2   12
3      1 3   16

问题是我需要对我想要堆叠的元素的每个新变量执行此操作。

我的问题是这样的:当我从宽到长格式化数据时,有没有更有效的方法来创建两列或更多列?如果我想将原始数据中的 pX_char2 变量转换为最终数据中的 char2 变量怎么办?

【问题讨论】:

标签: r dplyr reshape tidyr


【解决方案1】:

正如@domaeg 在 cmets 中指出的那样,这可以通过 tidyr 1.0.0 中的新 pivot_longer 函数来完成:

library(tidyverse)

data %>% pivot_longer(-obs_id, 
                      names_to = "p", 
                      names_pattern = "p([0-9])", 
                      values_to = "char")

产生:

# A tibble: 9 x 3
  obs_id p      char
   <int> <chr> <int>
1      1 1        20
2      1 2        12
3      1 3        16
4      2 1        16
5      2 2        20
6      2 3        11
7      3 1        18
8      3 2        16
9      3 3        13

为了更好的衡量,我无法用种子复制你的数据,所以我直接这样设置,如果其他人想试一试:

txt <- "obs_id p1 p1_char1 p2 p2_char1 p3 p3_char1
1      1  1       20  2       12  3       16
2      2  1       16  2       20  3       11
3      3  1       18  2       16  3       13"

data <- read.table(text = txt, header = TRUE)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-22
    • 1970-01-01
    • 1970-01-01
    • 2023-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多