首页 > 解决方案 > 带有 dplyr 的正则表达式从宽到长,

问题描述

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

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.

似乎不起作用

有任何想法吗?

标签: rdplyrtidyversepivot-tabletidyr

解决方案


您需要提供捕获组:

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])只会找到大写的 AZ(因此仍然适用于该示例)。对于更长的单词,例如(.+)_(.+)where+意味着一个或多个。尝试使正则表达式尽可能具体,只要它仍然可读!

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


推荐阅读