【问题标题】:How to find a pattern in a string and extract it as a new column of data frame如何在字符串中查找模式并将其提取为数据框的新列
【发布时间】:2020-11-11 03:36:11
【问题描述】:

我有一个如下图的数据框:

c("3.2% 1ST $100000 AND 1.1% BALANCE", "3.3% 1ST $100000 AND 1.2% BALANCE AND $3000 BONUS FULL PRICE ONLY", 
"$4000", "3.3% 1ST $100000 AND 1.2% BALANCE", "3.3% 1ST $100000 AND 1.2% BALANCE", 
"3.2% 1ST $100000 1.1% BALANCE")

[1] "3.2% 1ST $100000 AND 1.1% BALANCE"                                
[2] "3.3% 1ST $100000 AND 1.2% BALANCE AND $3000 BONUS FULL PRICE ONLY"
[3] "$4000"                                                            
[4] "3.3% 1ST $100000 AND 1.2% BALANCE"                                
[5] "3.3% 1ST $100000 AND 1.2% BALANCE"                                
[6] "3.2% 1ST $100000 1.1% BALANCE"   

一般来说,我可以说所有的 cmets 都是这种形式: x.y% 1ST abcdef AND a.b% BALANCE (它可以有第四个数字作为奖励。这个数据框有 52000 行,所以绝对不可能捕获各种 cmets,但总的来说,我上面提到的格式是一个很好的起始格式)。 我想知道如何提取这些 cmets 中的每个数字并将它们保存为数据框格式。例如,我想要一个这样的数据框:

    First%   cut-off second%  Bonus 
1    3.2     100000    1.1      NA
2    3.3     100000    1.2      3000
3    NA        NA      NA       NA
4    3.3     100000    1.2      NA
5    3.3     100000    1.2      NA
6    3.2     100000    1.1      NA

我大概可以使用str_subset 和这样的模式:

str_subset(data$comment, "(\\d\\.\\d)% 1ST \\$(\\d{3,8}) AND (\\d\\.\\d)% BALANCE \\w+")

但是str_subset 完全返回字符串,我不确定如何单独保存每个部分。我也查了这个链接Extract a regular expression match,看来str_extract是个不错的选择;但是,仅用于检查一种模式。就我而言,如果我提取\\d\\.\\d%,则不清楚是提取第一个数字还是提取第二个数字。

谢谢

【问题讨论】:

    标签: r regex dataframe


    【解决方案1】:

    您可以尝试以下方法:

    library(tidyverse)
    
    df %>%
      extract(col, c('First', 'cut-off', 'Second'), 
                   '(\\d+.*?)% 1ST\\s*\\$(\\d+).*?(\\d+.*?)%.*?', remove = FALSE) %>%
      mutate(Bonus = str_extract(col, '\\d+(?=\\sBONUS)')) %>%
      select(-col)
    
    #   First cut-off Second Bonus
    #1   3.2  100000    1.1  <NA>
    #2   3.3  100000    1.2  3000
    #3  <NA>    <NA>   <NA>  <NA>
    #4   3.3  100000    1.2  <NA>
    #5   3.3  100000    1.2  <NA>
    #6   3.2  100000    1.1  <NA>
    

    数据

    df <- data.frame(col = c("3.2% 1ST $100000 AND 1.1% BALANCE", "3.3% 1ST $100000 AND 1.2% BALANCE AND $3000 BONUS FULL PRICE ONLY", 
                             "$4000", "3.3% 1ST $100000 AND 1.2% BALANCE", "3.3% 1ST $100000 AND 1.2% BALANCE", 
                             "3.2% 1ST $100000 1.1% BALANCE"))
    

    【讨论】:

    • 感谢@Ronak Shah。你能解释一下这行代码是如何工作的吗?所以,我猜提取函数的工作方式是自动提取() 中的部分模式,对吗?我很好奇的是,您如何将第一个找到的匹配项分配给第一列,将第二个匹配项分配给截止列?为什么你使用str_extract 作为奖励部分?
    • 是的,没错。所以要提取的所有值都在捕获组() 中。第一个捕获组分配给第一列,即First,第二个分配给cut-off,依此类推。由于 BONUS 部分并不存在于所有值中,因此我使用 str_extract 来获取它。
    【解决方案2】:

    这行得通吗:

    st <- c("3.2% 1ST $100000 AND 1.1% BALANCE", "3.3% 1ST $100000 AND 1.2% BALANCE AND $3000 BONUS FULL PRICE ONLY", 
            "$4000", "3.3% 1ST $100000 AND 1.2% BALANCE", "3.3% 1ST $100000 AND 1.2% BALANCE", 
            "3.2% 1ST $100000 1.1% BALANCE")
    dat <- plyr::ldply(str_extract_all(st, '[0-9]\\.[0-9]|[0-9]{4,6}'), rbind)
    names(dat) <- c('First%', 'cut-off', 'second%',  'Bonus')
    dat <- dat %>% type.convert(as.is = T)
    dat$`First%`[dat$`First%`>10] <- NA
    dat
      First% cut-off second% Bonus
    1    3.2  100000     1.1    NA
    2    3.3  100000     1.2  3000
    3     NA      NA      NA    NA
    4    3.3  100000     1.2    NA
    5    3.3  100000     1.2    NA
    6    3.2  100000     1.1    NA
    

    【讨论】:

    • 谢谢@Karthik。出于某种原因,这对我不起作用。我传递了为它创建的数据框@Ronak Shah,但它没有返回预期的结果。您的代码中的st 是什么?是单个字符串吗?
    • @Roozbeh_you,对不起,我忘了添加“st”部分,它只是有问题的字符串。已编辑答案。
    【解决方案3】:

    我选择了 dplyr 管道。结果并不完美,但它是一种更流畅的方式来逐个处理正则表达式匹配而不是长字符串。

    library(tidyverse)
    
    data_ <- data.frame(dat = c("3.2% 1ST $100000 AND 1.1% BALANCE", "3.3% 1ST $100000 AND 1.2% BALANCE AND $3000 BONUS FULL PRICE ONLY", 
                "$4000", "3.3% 1ST $100000 AND 1.2% BALANCE", "3.3% 1ST $100000 AND 1.2% BALANCE", 
                "3.2% 1ST $100000 1.1% BALANCE"))
    
    data_ %>%
      mutate(first_perc = str_extract(dat, "\\d+\\.\\d%?"),
             cut_off = str_extract(dat, "[^\\d+\\.\\d% 1ST.]\\d+"),
             second_perc = str_extract(dat, "[^\\d+\\.\\d% 1ST?\\d+]?\\d+\\.\\d%"),
             bonus = str_extract(dat, "[^\\d+\\.\\d% 1ST?\\d+\\d+\\.\\d%\\D+]?\\d\\d+"))
    

    我可能会建议使用条件返回不完整的行,例如 case_when 参数,具体取决于各种变异行捕获或未捕获的内容。

    【讨论】:

    • 感谢@Kenr Orr。这个解决方案也是有效的,更重要的是简单。感谢您的努力
    猜你喜欢
    • 1970-01-01
    • 2022-10-07
    • 2021-10-20
    • 1970-01-01
    • 2021-10-07
    • 1970-01-01
    • 2020-11-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多