【问题标题】:Separate string after last underscore最后一个下划线后的分隔字符串
【发布时间】:2018-09-28 17:34:15
【问题描述】:

这确实是这个问题的重复 r-split-string-using-tidyrseparate,但我不能将 MWE 用于我的目的,因为我不知道如何调整正则表达式。 我基本上想要同样的东西,但在最后一个下划线之后拆分变量。

原因:我的数据中某些列针对相同的因子/类型多次显示。我想我可以将数据融化在类型字符串之前将值变量分开,然后将其再次展开为具有较少列的宽格式。我的问题是我的变量名有几个不同的下划线,我想学习如何在我预先添加的最后一个下划线之后进行分隔。

MWE

library(tidyr)
library(data.table)
dt<-data.table(Name=c("A","B","C"),Var_1_EVU=c(2,NA,NA),Var_1_BdS=c(NA,3,4),Var_2_BdS=c(NA,3,4))
dt.long<-melt(dt, id.vars=c("Name"))
dt.long<-separate(dt.long,variable, c("test","type"), sep='/[^_]*$/')
dt.wide<-spread(dt.long,key=Name,value=value) 

我想要类似的东西

   Name type Var1 Var2
1:    A  BdS   NA   NA
2:    A  EVU    2   NA
3:    B  BdS    3    3
4:    B  EVU   NA   NA
5:    C  BdS    4    4
6:    C  EVU   NA   NA

【问题讨论】:

  • 现在,我使用“愚蠢”的解决方案,并使用“___”将类型添加到我的变量中,我确信它在我的 data.names 中不存在。仍然渴望更好地理解正则表达式......

标签: r data.table tidyr tidyverse melt


【解决方案1】:
library(tidyr)

df <- data.frame(Name = c("A","B","C"),
                 Var_1_EVU = c(2,NA,NA),
                 Var_1_BdS = c(NA,3,4),
                 Var_2_BdS = c(NA,3,4))

df %>% 
  gather("type", "value", -Name) %>% 
  separate(type, into = c("type", "type_num", "var")) %>% 
  unite(type, type, type_num, sep = "") %>% 
  spread(type, value)

#   Name var Var1 Var2
# 1    A BdS   NA   NA
# 2    A EVU    2   NA
# 3    B BdS    3    3
# 4    B EVU   NA   NA
# 5    C BdS    4    4
# 6    C EVU   NA   NA

使用tidyr::extract 处理具有任意数量下划线的变量名的示例...

library(dplyr)
library(tidyr)

df <- data.frame(Name = c("A","B","C"),
                 Var_x_1_EVU = c(2,NA,NA),
                 Var_x_1_BdS = c(NA,3,4),
                 Var_x_y_2_BdS = c(NA,3,4))

df %>% 
  gather("col_name", "value", -Name) %>% 
  extract(col_name, c("var", "type"), "(.*)_(.*)") %>% 
  spread(var, value)

#   Name type Var_x_1 Var_x_y_2
# 1    A  BdS      NA        NA
# 2    A  EVU       2        NA
# 3    B  BdS       3         3
# 4    B  EVU      NA        NA
# 5    C  BdS       4         4
# 6    C  EVU      NA        NA

您可以通过首先使用mutate(n = row_number()) 添加行号列/变量来避免重复观察的潜在问题,以使每个观察都独一无二,并且您可以通过使用@ 显式调用它来避免tidyr::extractmagrittr 掩盖987654327@...

library(dplyr)
library(tidyr)
library(data.table)
library(magrittr)

dt <- data.table(Name = c("A", "A", "B", "C"),
                 Var_1_EVU = c(1, 2, NA, NA),
                 Var_1_BdS = c(1, NA, 3, 4),
                 Var_x_2_BdS = c(1, NA, 3, 4))

dt %>% 
  mutate(n = row_number()) %>% 
  gather("col_name", "value", -n, -Name) %>% 
  tidyr::extract(col_name, c("var", "type"), "(.*)_(.*)") %>% 
  spread(var, value)

#   Name n type Var_1 Var_x_2
# 1    A 1  BdS     1       1
# 2    A 1  EVU     1      NA
# 3    A 2  BdS    NA      NA
# 4    A 2  EVU     2      NA
# 5    B 3  BdS     3       3
# 6    B 3  EVU    NA      NA
# 7    C 4  BdS     4       4
# 8    C 4  EVU    NA      NA

【讨论】:

  • 这只适用于我的 MWE。我的真实数据有不同的名称,带有数字和下划线等。这就是我想使用正则表达式的原因,因为它可以确保我在最后一个下划线之后分开,我事先添加了自己。
  • 我添加了另一个使用tidyr::extract 的示例,它可以处理具有任意数量下划线的变量名
  • 谢谢,我会在示例中将Var_x_2_BdS 调整为Var_x_1_BdS,因为我的观点是只为Var_x_1 获取一个变量。老实说,我不明白正则表达式是如何工作的,但我想我必须努力解决这个问题。
  • 完成。第一个(.*) 捕获导致_ 的任何内容(包括其他_s)。第二个(.*) 捕获之后的任何内容。
【解决方案2】:

这是使用 tstrsplit/melt/dcast 的替代 data.table 解决方案 在这种情况下,我个人会坚持使用data.table,因为spread 没有fun 参数,因此,如果您在再次传播时遇到欺骗,您会收到错误。

library(magrittr) # people like pipes these days
dt %>%
  # convert ot long format like you did
  melt(., id = "Name") %>% 
  # split by the last underscore
  .[, c("variable", "grp") := tstrsplit(variable, "_(?!.*_)", perl = TRUE)] %>% 
  # convert back to wide format
  dcast(., Name + grp ~ variable) 

#    Name grp Var_1 Var_2
# 1:    A BdS    NA    NA
# 2:    A EVU     2    NA
# 3:    B BdS     3     3
# 4:    B EVU    NA    NA
# 5:    C BdS     4     4
# 6:    C EVU    NA    NA

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-02
    • 1970-01-01
    • 2017-04-23
    • 2016-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多