【问题标题】:create new variable based on a regular expression基于正则表达式创建新变量
【发布时间】:2015-04-21 12:29:35
【问题描述】:

我的问题涉及如何根据正则表达式的结果在 R 中的数据框中创建一个新变量。 以下是数据的最小示例:

df <- data.frame(model=c("Legacy 2.0  BG5 B4 AUTO","Legacy 2.0 BH5 AT","Legacy 2.0i CVT Non Leather","Legacy 2.0i CVT","Legacy 2.0 BL5 AUTO B4",
                 "Legacy 2.0 BP5 AUTO","Legacy 2.0 BM5 AUTO CVT"), CRSP=c(3450000,3365000,4950000,5250000,4787526,3550000,5235000))

df
                        model    CRSP
1     Legacy 2.0  BG5 B4 AUTO 3450000
2           Legacy 2.0 BH5 AT 3365000
3 Legacy 2.0i CVT Non Leather 4950000
4             Legacy 2.0i CVT 5250000
5      Legacy 2.0 BL5 AUTO B4 4787526
6         Legacy 2.0 BP5 AUTO 3550000
7     Legacy 2.0 BM5 AUTO CVT 5235000

我想创建一个新变量'chassis',它的值是相应的'model'变量字符串的第三个元素,因此以:

df
                        model    CRSP chassis
1     Legacy 2.0  BG5 B4 AUTO 3450000     BG5
2           Legacy 2.0 BH5 AT 3365000     BH5
3 Legacy 2.0i CVT Non Leather 4950000     CVT
4             Legacy 2.0i CVT 5250000     CVT
5      Legacy 2.0 BL5 AUTO B4 4787526     BL5
6         Legacy 2.0 BP5 AUTO 3550000     BP5
7     Legacy 2.0 BM5 AUTO CVT 5235000     BM5

我需要找到一种方法来提取每一行中的适当元素并将它们放入新变量中。 任何帮助将不胜感激。

【问题讨论】:

    标签: regex r


    【解决方案1】:

    这是使用stringi的可能解决方案

    library(stringi)
    df$chassis <- stri_extract_all_words(df$model, simplify = TRUE)[, 3]
    df
    #                         model    CRSP chassis
    # 1     Legacy 2.0  BG5 B4 AUTO 3450000     BG5
    # 2           Legacy 2.0 BH5 AT 3365000     BH5
    # 3 Legacy 2.0i CVT Non Leather 4950000     CVT
    # 4             Legacy 2.0i CVT 5250000     CVT
    # 5      Legacy 2.0 BL5 AUTO B4 4787526     BL5
    # 6         Legacy 2.0 BP5 AUTO 3550000     BP5
    # 7     Legacy 2.0 BM5 AUTO CVT 5235000     BM5
    

    或者类似

    df$chassis <- sapply(stri_extract_all_words(df$model), `[`, 3)
    

    【讨论】:

      【解决方案2】:

      我是 tidyr 的忠实粉丝,我非常喜欢这种任务并将所有部分提取到单独的列中:

      if (!require("pacman")) install.packages("pacman")
      pacman::p_load(dplyr, tidyr)
      
      regx <- "(^[A-Za-z]+\\s+[0-9.a-z]+)\\s+([A-Z0-9]+)\\s*(.*)"
      
      df %>%
          extract(model, c("a", "chassis", "b"), regx, remove=FALSE)
      
      ##                         model           a chassis           b    CRSP
      ## 1     Legacy 2.0  BG5 B4 AUTO  Legacy 2.0     BG5     B4 AUTO 3450000
      ## 2           Legacy 2.0 BH5 AT  Legacy 2.0     BH5          AT 3365000
      ## 3 Legacy 2.0i CVT Non Leather Legacy 2.0i     CVT Non Leather 4950000
      ## 4             Legacy 2.0i CVT Legacy 2.0i     CVT             5250000
      ## 5      Legacy 2.0 BL5 AUTO B4  Legacy 2.0     BL5     AUTO B4 4787526
      ## 6         Legacy 2.0 BP5 AUTO  Legacy 2.0     BP5        AUTO 3550000
      ## 7     Legacy 2.0 BM5 AUTO CVT  Legacy 2.0     BM5    AUTO CVT 5235000
      

      您可以使用这个正则表达式更通用:

      regx <- "(^[^ ]+\\s+[^ ]+)\\s+([^ ]+)\\s*(.*)"
      

      还请注意,您可以使用extract 来获取您所关注的列,方法是在第一组和最后一组中删除分组括号,如下所示:

      regx <- "^[A-Za-z]+\\s+[0-9.a-z]+\\s+([A-Z0-9]+)\\s*.*"
      
      df %>% 
          extract(model, "chassis", regx, remove=FALSE)
      

      【讨论】:

      • 我在 dplyr 管道%&gt;% 内的同一数据帧上还有其他前面和后面的数据操作步骤,所以这个解决方案更方便,因为我可以将它直接插入循环。谢谢@TylerRinker
      【解决方案3】:

      使用strsplit 的替代解决方案

      # Split each of the models using space (the + accounts for multiple spaces)
      # Note that model is a factor in your data frame, so it must be cast to char
      model.split <- strsplit(as.character(df$model), " +")
      # Now go through each element of the splitted list and get the 3rd word
      df$chassis <- sapply(model.split, function(x){x[3]})
      

      【讨论】:

      • 或使用data.table 的类似方法。 setDT(df)[, chassis:=tstrsplit(model, ' +')[[3]]][]
      【解决方案4】:

      我们可以匹配字符直到包含i和空格的数字部分,使用sub将其替换为'',然后使用word提取第一个单词。

      library(stringr)
       word(sub('^\\D*[0-9.i ]*', '', df$model),1)
      #[1] "BG5" "BH5" "CVT" "CVT" "BL5" "BP5" "BM5"
      

      或匹配空格,替换为单个空格并使用word

       word(gsub(' +', ' ', df$model),3)
       #[1] "BG5" "BH5" "CVT" "CVT" "BL5" "BP5" "BM5"
      

      注意:不确定 'model' 的第一个元素中的多余空格是否是拼写错误。如果原始数据集的单词之间没有超过一个空格,则word(df$model, 3) 可以工作。

      【讨论】:

        【解决方案5】:

        这可以在基础 R 中轻松完成:

        transform(df, chassis=sub("^(\\S+\\s+){2}(\\S+).*", "\\2", model))
        

        产生:

                                model    CRSP chassis
        1     Legacy 2.0  BG5 B4 AUTO 3450000     BG5
        2           Legacy 2.0 BH5 AT 3365000     BH5
        3 Legacy 2.0i CVT Non Leather 4950000     CVT
        4             Legacy 2.0i CVT 5250000     CVT
        5      Legacy 2.0 BL5 AUTO B4 4787526     BL5
        6         Legacy 2.0 BP5 AUTO 3550000     BP5
        7     Legacy 2.0 BM5 AUTO CVT 5235000     BM5     
        

        【讨论】:

          【解决方案6】:

          您可以使用splitstackshape 包中的cSplit 拆分空格字符:

          library(splitstackshape)
          df$chassis <- cSplit(df, "model", sep = " ", "wide")$model_3
          

          这避免了对正则表达式或apply 函数的需要。

          【讨论】:

          • cSplit 有一个选项drop=FALSE,它返回一个data.table。所以,也许这也可以工作cSplit(df, "model", sep = " ", "wide", drop=FALSE)[, c(1,5), with=FALSE]
          【解决方案7】:

          使用 脱胶 我们可以做到:

          # install.packages("unglue")
          library(unglue)
          
          unglue_unnest(df, model, "{=.*?} {=.*?} {chassis=[^ ]+}{=.*?}", remove = FALSE)
          #>                         model    CRSP chassis
          #> 1     Legacy 2.0  BG5 B4 AUTO 3450000     BG5
          #> 2           Legacy 2.0 BH5 AT 3365000     BH5
          #> 3 Legacy 2.0i CVT Non Leather 4950000     CVT
          #> 4             Legacy 2.0i CVT 5250000     CVT
          #> 5      Legacy 2.0 BL5 AUTO B4 4787526     BL5
          #> 6         Legacy 2.0 BP5 AUTO 3550000     BP5
          #> 7     Legacy 2.0 BM5 AUTO CVT 5235000     BM5
          

          【讨论】:

            猜你喜欢
            • 2016-01-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-05-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多