dplyr 枢轴从宽到长的正则表达式,

regular expressions with dplyr pivot wide to long,

我有一个连接管道数据库,其中流入(字母)和流出为数字。

df=data.frame(id=c(1,2,3,4,5), A-Y=c(0,1,0,1,0), B-Z=c(1,1,1,0,0), C-W=c(1,1,0,0,0))
df
df
  id A.Y B.Z C.W
1  1   0   1   1
2  2   1   1   1
3  3   0   1   0
4  4   1   0   0
5  5   0   0   0

我想把它转换成长格式如下

df.out<-data.frame(id=c(1,1,2,2,2,3,4,5), inflow=c("B", "C", "A", "B", "C", "B", "A",""), outflow=c("Z", "W", "Y", "Z", "W", "Z","Y",""))
 df.out
  id inflow outflow
  1      B       Z
  1      C       W
  2      A       Y
  2      B       Z
  2      C       W
  3      B       Z
  4      A       Y
  5               

我想我应该使用 pivot_longer 但我不确定如何定义拆分。

df %>% pivot_longer(cols=A.Y:C.W, names_to=c("Inflow", "Outflow"), names_pattern = ".-.", values_to = status)

Error: `regex` should define 2 groups;  found.

好像不行

有什么想法吗?

您需要提供捕获组:

df <- tibble(
  id = c(1, 2, 3, 4, 5),
  A_Y = c(0, 1, 0, 1, 0),
  B_Z = c(1, 1, 1, 0, 0),
  C_W = c(1, 1, 0, 0, 0)
)
df

df %>%
  pivot_longer(
    cols = -id,
    names_to = c("Inflow", "Outflow"),
    names_pattern = "(.)_(.)",
    values_to = "status"
  ) %>%
  filter(status == 1) %>%
  select(-status)

编辑: 作为对评论的回答——目前,正则表达式 "(.)_(.)" 正在寻找任何单个字符 (.) 后跟一个下划线,然后是另一个单个字符。为了使其更具体,将 . 替换为另一个正则表达式,例如([A-Z])_([A-Z]) 只会找到大写字母 A-Z(因此仍然适用于该示例)。对于较长的词,例如 (.+)_(.+),其中 + 表示一个或多个。尽可能使正则表达式具体化,前提是它仍然可读!

@Ronak 建议 names_sep = '\.' 而不是 names_pattern 这是一个更简单的解决方案,前提是分隔符是一致的(names_sep = "_" 以适合我的示例!)

您可以使用 names_sep.

tidyr::pivot_longer(df, cols = -id, 
                    names_to = c('inflow', 'outflow'), 
                    names_sep = '\.') %>%
  filter(value == 1) %>%
  select(-value)

#     id inflow outflow
#  <dbl> <chr>  <chr>  
#1     1 B      Z      
#2     1 C      W      
#3     2 A      Y      
#4     2 B      Z      
#5     2 C      W      
#6     3 B      Z      
#7     4 A      Y   

数据

df=data.frame(id=c(1,2,3,4,5), A.Y=c(0,1,0,1,0), 
              B.Z=c(1,1,1,0,0), C.W=c(1,1,0,0,0))