如何将多个列合并为一个列并创建另一个指示源的列?

问题描述 投票:0回答:2

我正在尝试转动一张看起来像这样的桌子:

记录_id 高度_1 高度_1_v1 高度_1_v1_v1 权重_1 weight_1_v1 weight_1_v1_v1
10 不适用 不适用 5 英尺 6 英寸 不适用 不适用 154
10 不适用 5 英尺 6 英寸 不适用 不适用 153 不适用
10 5 英尺 6 英寸 不适用 不适用 152 不适用 不适用
11 不适用 不适用 5.11 不适用 不适用 138
11 不适用 5.11 不适用 不适用 131 不适用
11 5.11 不适用 不适用 135 不适用 不适用

进入如下所示的表格:

记录_id appt_num 高度 重量
10 1 5 英尺 6 英寸 152
10 2 5 英尺 6 英寸 153
10 3 5 英尺 6 英寸 154
11 1 5.11 135
11 2 5.11 131
11 3 5.11 138

我怎样才能实现这个目标?谢谢!

到目前为止,我已经尝试过pivot_longer()和gather()但没有成功。我得到的最接近的是使用合并(),但我无法成功创建约会号码(appt_num)列。

r reshape
2个回答
0
投票

由于多种原因,您的初始数据格式很尴尬......

  • 尴尬的列名
  • 数据值以相反顺序呈现
  • 混合字符和数值

...所以有很多步骤可以到达您想去的地方。

这是一种方法。还会有其他人。我在每个步骤的开始添加了注释来说明我正在做什么。如果您想详细调查每一步发生的情况,只需打破管道即可。

d %>% 
  # Temporary, to allow combining into a single column
  mutate(across(starts_with("weight"), as.character)) %>% 
  # Pivot longer, discarding awkward column name suffixes
  pivot_longer(
    cols = c(starts_with("height"), starts_with("weight")),
    names_pattern = "(height|weight)_(.)",
    names_to = c("name", NA)
  ) %>% 
  # Discard missing values
  filter(!is.na(value)) %>% 
  # Define appointment number
  group_by(record_id, name) %>% 
  mutate(appt_num = 1 + n() - row_number()) %>% 
  arrange(record_id, name, appt_num) %>% 
  # Pivot to required format
  pivot_wider(
    names_from = name,
    values_from = value,
    id_cols = c(record_id, appt_num)
  ) %>% 
  # Convert weight back to numeric
  mutate(weight = as.numeric(weight)) %>% 
  # Remove grouping
  ungroup()
# A tibble: 6 × 4
  record_id appt_num height weight
      <dbl>    <dbl> <chr>   <dbl>
1        10        1 5ft6in    152
2        10        2 5ft6in    153
3        10        3 5ft6in    154
4        11        1 5.11      135
5        11        2 5.11      131
6        11        3 5.11      138

0
投票

数据框示例:

library(dplyr)
library(tidyr)

df <- data.frame(record_id=c(rep(10,3),rep(11,3)),
           height_1=c(NA_character_,NA_character_,"5ft6in",NA_character_,NA_character_,"5.11"),
           height_1_v1=c(NA_character_,"5ft6in",NA_character_,NA_character_,"5.11",NA_character_),
           height_1_v1_v1=c("5ft6in",NA_character_,NA_character_,"5.11",NA_character_,NA_character_),
           weight_1=c(NA_character_,NA_character_,"152",NA_character_,NA_character_,"135"),
           weight_1_v1=c(NA_character_,"153",NA_character_,NA_character_,"131",NA_character_),
           weight_1_v1_v1=c("154",NA_character_,NA_character_,"138",NA_character_,NA_character_))


  record_id height_1 height_1_v1 height_1_v1_v1 weight_1 weight_1_v1 weight_1_v1_v1
1        10     <NA>        <NA>         5ft6in     <NA>        <NA>            154
2        10     <NA>      5ft6in           <NA>     <NA>         153           <NA>
3        10   5ft6in        <NA>           <NA>      152        <NA>           <NA>
4        11     <NA>        <NA>           5.11     <NA>        <NA>            138
5        11     <NA>        5.11           <NA>     <NA>         131           <NA>
6        11     5.11        <NA>           <NA>      135        <NA>           <NA>

使用 pivot_longer 转换 data.frame,排除 record_id 列并删除所有具有 NA 值的行。使用 case_when 命令将值分配给 appt_num 列。删除 col 列中的多余文本并使用 pivot_wider 再次转换 data.frame。

df %>% pivot_longer(-c(record_id),names_to="col",values_to="text") %>% filter(!is.na(text)) %>% 
  mutate(appt_num=case_when(
    grepl("1_v1_v1",col) ~ 3,
    grepl("1_v1",col) ~ 2,
    TRUE ~ 1
  )) %>% mutate(col=gsub("_v1","",col)) %>% mutate(col=gsub("_1","",col)) %>% 
  pivot_wider(names_from = "col", values_from = "text") %>% arrange(record_id,appt_num)

# A tibble: 6 × 4
  record_id appt_num height weight
      <dbl>    <dbl> <chr>  <chr> 
1        10        1 5ft6in 152   
2        10        2 5ft6in 153   
3        10        3 5ft6in 154   
4        11        1 5.11   135   
5        11        2 5.11   131   
6        11        3 5.11   138 

更新:

版本,以防使用 stringr 库中的 str_count 有更多列遵循相同的结构。

library(stringr)

df %>% pivot_longer(-c(record_id),names_to="col",values_to="text") %>% filter(!is.na(text)) %>%
  mutate(appt_num=str_count(col,"_v1") + 1) %>%
  mutate(col=gsub("_v1","",col)) %>% mutate(col=gsub("_1","",col)) %>% 
  pivot_wider(names_from = "col", values_from = "text") %>% arrange(record_id,appt_num)
© www.soinside.com 2019 - 2024. All rights reserved.