【问题标题】:how to separate leading words before first number in list in R如何在R中列表中的第一个数字之前分隔前导词
【发布时间】:2018-09-11 15:08:25
【问题描述】:

我的清单是:

   A      B
1 Alex    but            
2 likes   lala 54 hi     
3 a lot   number and 33 hello
4 of      face soap 34 hello  
5 food    35 hello      

我想提取B列中第一个数字之前的字符串并将其放入新列C列。我想要的输出是:

   A        B                        C 
1 Alex      but                   
2 likes     lala 54 hi               lala
3 a lot     number and 33 hello      number and
4 of        face soap 34 hello       face soap
5 food      35 hello             

【问题讨论】:

  • 仅供参考,第一行和最后一行都产生空字符串的期望使得这作为正则表达式相当困难。也就是说,说“给我一个数字之前的所有字符”很容易,这将产生最后一行,但是对于第一行,你说的是“在数字之前给我一些东西,除非没有数字,然后给我一个空string",这是一个重要的特殊情况。在那种情况下,我认为@A.Suliman 制作NA(第一行)并没有不妥。
  • Ramsha,你的问题有几个很好的答案。请accept其中一个,如果你选择,那么你可以投票给你喜欢的任何其他人(但你只能接受一个)。

标签: r extract tidyr stringr


【解决方案1】:

使用正向预测,我们可以查找后跟空格和数字的文本,然后使用 stringr::str_extract 返回此文本

library(stringr)
libary(dplyr)
df %>% mutate(C= str_extract(B,'\\D+(?= \\d+)'))


     A                   B          C
1  Alex                 but       <NA>
2 likes          lala 54 hi       lala
3 a lot number and 33 hello number and
4    of  face soap 34 hello  face soap
5  food            35 hello       <NA>

有关 stringr 和正向前瞻的更多详细信息,您可以查看here

【讨论】:

  • 这将产生 NA 而不是空字符串。这很容易解决,但最好扩展此答案以包含有关您为什么认为NA 可以的文本,以及(如果 OP 希望)获得所需输出中实际显示的内容的方式(即, 空字符串)。
  • 添加到您的mutate 呼叫:C = if_else(is.na(C), "", C) 以获得所需的输出。
  • 我更喜欢空字符串,因为这是一个更大项目的一部分,但是将 NA 替换为空字符串并不难。这是一个非常好的答案,我将把这个问题留一会儿,看看是否有人有另一种独特的方式。
  • @RamshaPerwez 是的,如果您更喜欢空字符串,那么您可以为 r2evans 提供建议。
【解决方案2】:

解决此问题的最佳方法是使用 dplyrstringr 函数,它们随附于 tidyverse 包中。这是解决您问题的代码:

# install.packages('tidyverse')
library(tidyverse)

d <- tibble(A = c('Alex', 'likes', 'a lot', 'of', 'food'),
             B = c('but', 'lala 54 hi', 'number and 33 hello', 'face soap 34 hello', '35 hello'))

d %>% 
  mutate(C = str_extract(B, '\\D*(?=\\d)'))

以下是您需要了解的有关其工作原理的信息:

dplyr::mutate 创建一个新列 C。它放入此列的数据是通过从列 B 中提取(使用 stringr::str_extract)字符创建的。它提取的数据是使用正则表达式提取的。

这里使用的正则表达式是\\D*(?=\\d)。这看起来既复杂又粗俗,但它的意思是“查找在数字之前的任何长度的任何非数字字符。给我那些字符,而不是数字”。

希望有帮助!

【讨论】:

    【解决方案3】:

    我希望这会有所帮助。使用 sapply,您可以通过 B 列中的值以矢量化方式应用 gsub 函数并输出过滤后的矢量。

    new_column = sapply(df$B, function(x){gsub("^(.*?)[0-9].*", "\\1", x)})
    

    这将为您提供一个向量,其中包含 B 列中的过滤值。 然后,您只需将此新向量添加为数据框中的新列:

    df$C= new_column
    

    【讨论】:

    • 不用sapplysubgsub都是自然矢量化的。试试gsub("^(.*?)[0-9].*", "\\1", df$B)。 (不幸的是,您的代码没有产生所需的输出。)
    • 嗨,这是一个很好的答案!除第一行外,此方法有效。 B1 没有编号,因此它不应该复制到 C1 上。有没有办法解决这个问题?
    • @r2evans 您的修改显示与上述代码相同的结果。 :(
    • 我知道,这就是我说“不幸”的原因。我的评论是关于sapply 的不必要使用,而不是关于gsub 的正确操作。也许我应该说“不幸的是,该模式没有产生所需的输出”。
    • 感谢@r2evans,我确实错过了。
    【解决方案4】:

    另一种选择,在基础 R 中。

    df <- data.frame(A=c("Alex", "likes", "a lot", "of", "food"), B=c("but", "lala 54 hi", "number and 33 hello", "face soap 34 hello", "35 hello"))
    regmatches(df$B, gregexpr("^\\D*(?=\\d)", df$B, perl=TRUE))
    # [[1]]
    # character(0)
    # [[2]]
    # [1] "lala "
    # [[3]]
    # [1] "number and "
    # [[4]]
    # [1] "face soap "
    # [[5]]
    # [1] ""
    

    如果您不熟悉正则表达式:

    • ^: 字符串开头
    • \\D* 零个或多个非数字,类似于 [^0-9]*
    • (?=\\d) 表示“向前看一个数字,但不包括在返回的模式中”(向前看的一个很好的参考:https://www.regular-expressions.info/lookaround.html);这是正则表达式的 perl 扩展,因此 perl=TRUE

    这会为第一个生成一个长度为 0 的向量。这很容易处理,也许可以使用快速帮助函数:

    replace_len0 <- function(x, replace=NA) `[<-`(x, lengths(x) < 1, replace)
    unlist(replace_len0(regmatches(df$B, gregexpr("^\\D*(?=\\d)", df$B, perl=TRUE)), ""))
    # [1] ""            "lala "       "number and " "face soap "  ""           
    

    (我将默认替换设置为NA,因为在我看来这是“在第一个数字之前有一个空字符串""“有区别没有号码”。交给你了。)

    可以根据需要轻松分配给df$C

    【讨论】:

      【解决方案5】:

      tidyr 使用extract 的另一种方法:

      library(dplyr)
      library(tidyr)
      
      df %>%
        extract(B, "C", "^([a-z\\s]+)\\d", remove = FALSE) %>%
        mutate(C = replace(C, is.na(C), ""))
      

      输出:

            A                   B           C
      1  Alex                 but            
      2 likes          lala 54 hi       lala 
      3 a lot number and 33 hello number and 
      4    of  face soap 34 hello  face soap 
      5  food            35 hello            
      

      【讨论】:

        猜你喜欢
        • 2019-03-22
        • 1970-01-01
        • 2012-02-06
        • 1970-01-01
        • 2015-11-06
        • 1970-01-01
        • 2019-06-11
        • 2021-04-14
        • 2017-06-02
        相关资源
        最近更新 更多