我正在尝试转动一张看起来像这样的桌子:
记录_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)列。
由于多种原因,您的初始数据格式很尴尬......
...所以有很多步骤可以到达您想去的地方。
这是一种方法。还会有其他人。我在每个步骤的开始添加了注释来说明我正在做什么。如果您想详细调查每一步发生的情况,只需打破管道即可。
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
数据框示例:
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)