问题描述
我已经尝试了多个线程和多次尝试,但我还没有能够破解它,如果这是重复的,请原谅我。
我有一个看起来像这样的数据框,但有更多的列(所以希望解决方案可以自动化):
clear
我希望我的输出看起来像这样:
| id | Q1_wave1 | Q1_wave2 | Q1_wave3 | Q1_wave4 | Q2_wave1 | Q2_wave3 | Q3_wave1 | Q3_wave2 | Q3_wave3 |
|----|----------|----------|----------|----------|----------|----------|----------|----------|----------|
| 1 | 50 | 30 | 40 | 60 | Yes | Yes | 20 | 40 | 60 |
| 2 | 10 | 20 | 30 | 40 | No | Yes | 10 | 5 | 70 |
| 3 | 20 | 40 | 60 | 80 | Yes | No | 5 | 10 | 15 |
我尝试用这种方式重塑:
| id | wave | Q1 | Q2 | Q3 |
|----|------|----|-----|----|
| 1 | 1 | 50 | Yes | 20 |
| 1 | 2 | 30 | | 40 |
| 1 | 3 | 40 | Yes | 60 |
| 1 | 4 | 60 | | |
| 2 | 1 | 10 | No | 10 |
| 2 | 2 | 20 | | 5 |
| 2 | 3 | 30 | Yes | 70 |
| 2 | 4 | 40 | | |
| 3 | 1 | 20 | Yes | 5 |
| 3 | 2 | 40 | | 10 |
| 3 | 3 | 60 | No | 15 |
| 3 | 4 | 80 | | |
并得到错误:
df_long<-reshape(df_wide,direction="long",varying=2:ncol(df_wide),idvar='id',timevar="wave",v.names=c("Q1","Q2","Q3"),sep="_")
当它是单个变量或面板是平衡的时,我所看到的所有示例似乎都运行良好,但在这种情况下我一直无法找到一些工作。 length of 'v.names' does not evenly divide length of 'varying'
也躲过了我。提前致谢!
解决方法
使用pivot_longer
:
tidyr::pivot_longer(df_wide,-id,names_to = c('.value','wave'),names_pattern = '(Q\\d+)_wave(\\d+)')
# id wave Q1 Q2 Q3
# <int> <chr> <int> <chr> <int>
# 1 1 1 50 Yes 20
# 2 1 2 30 NA 40
# 3 1 3 40 Yes 60
# 4 1 4 60 NA NA
# 5 2 1 10 No 10
# 6 2 2 20 NA 5
# 7 2 3 30 Yes 70
# 8 2 4 40 NA NA
# 9 3 1 20 Yes 5
#10 3 2 40 NA 10
#11 3 3 60 No 15
#12 3 4 80 NA NA
names_pattern
用于指定正则表达式模式以中断列名。这必须与 names_to
同步。 .value
是一个特殊关键字,表示原始列名的一部分将在最后一列中。第一部分 (Q\\d+)
指定 'Q' 后跟任意数字(此处为 Q1
、Q2
、Q3
)将是单独的列,数字后跟 'wave_'
进入 wave
列。
数据
df_wide <- structure(list(id = 1:3,Q1_wave1 = c(50L,10L,20L),Q1_wave2 = c(30L,20L,40L),Q1_wave3 = c(40L,30L,60L),Q1_wave4 = c(60L,40L,80L),Q2_wave1 = c("Yes","No","Yes"),Q2_wave3 = c("Yes","Yes","No"),Q3_wave1 = c(20L,5L),Q3_wave2 = c(40L,5L,10L),Q3_wave3 = c(60L,70L,15L)),class = "data.frame",row.names = c(NA,-3L))
,
我们可以在 names_sep
中使用 _
和 pivot_longer
并在需要时使用 parse_number
解析数值
library(tidyr)
library(dplyr)
pivot_longer(df_wide,cols = -id,names_to = c(".value","wave"),names_sep = "_") %>%
mutate(wave = readr::parse_number(wave))
-输出
# A tibble: 12 x 5
id wave Q1 Q2 Q3
<int> <dbl> <int> <chr> <int>
1 1 1 50 Yes 20
2 1 2 30 <NA> 40
3 1 3 40 Yes 60
4 1 4 60 <NA> NA
5 2 1 10 No 10
6 2 2 20 <NA> 5
7 2 3 30 Yes 70
8 2 4 40 <NA> NA
9 3 1 20 Yes 5
10 3 2 40 <NA> 10
11 3 3 60 No 15
12 3 4 80 <NA> NA
或者使用 melt
中的 data.table
library(data.table)
melt(setDT(df_wide),measure = patterns("^Q1",'^Q2','^Q3'),value.name = c("Q1","Q2","Q3"),variable.name = 'wave')
数据
df_wide <- structure(list(id = 1:3,-3L))