【问题标题】:R splitting a column of character separated by different number of spacesR拆分由不同数量的空格分隔的一列字符
【发布时间】:2016-07-30 00:38:26
【问题描述】:

我有一个数据框,其中有一列由不同数量的空格分隔的单词组成,例如:

head(lst)
'fff fffd ddd'
'sss dd'
'de dd'
'dds sssd eew rrr'
'dsds eed'

我想要的是 2 列: 第一列是第一个空格之前的部分 第二列是最后一个空格之后的部分 意思应该是这样的

V1       v2
'fff'   'ddd'
'sss'   'dd'
'de'    'dd'
'dds'   'rrr
'dsds'  'eed'

我能得到第一列,但第二列有问题 这是我使用的代码。

  lst <- strsplit(athletes.df$V1, "\\s+")
  v1 <- sapply(lst ,`[`, 1)
  v2 <- sapply(lst, `[`, 2)

我得到的第 v2 列是第二个词。我知道这是因为我在 sapply 中放了 2 如何告诉它只取最后一个空格之后的内容?

【问题讨论】:

    标签: r split


    【解决方案1】:

    您可以使用tail 来抓取每个向量的最后一个条目:

    lst <- strsplit(athletes.df$V1, "\\s+")
    v1 <- sapply(lst, head, 1) # example with head to grab first vector element
    v2 <- sapply(lst, tail, 1) # example with tail to grab last vector element
    

    或者可能是 vapply 版本,因为您知道返回类型应该是字符向量:

    v2 <- vapply(lst, tail, 1, FUN.VALUE = character(1))
    

    另一种方法是将您的 strsplit 拆分标准修改为类似这样的内容,您可以在一个空格上进行拆分,该空格可以选择后跟任何字符一次或多次,直到找到最终空格。

    strsplit(df$V1, "\\s(?:.+\\s)?")
    #[[1]]
    #[1] "fff" "ddd"
    #
    #[[2]]
    #[1] "sss" "dd" 
    #
    #[[3]]
    #[1] "de" "dd"
    #
    #[[4]]
    #[1] "dds" "rrr"
    #
    #[[5]]
    #[1] "dsds" "eed"
    

    正如 Sumedh 指出的,这个正则表达式可以很好地与 tidyrseparate 配合使用:

    tidyr::separate(df, V1, c("V1", "V2"), "\\s(?:.+\\s)?")
    #    V1  V2
    #1  fff ddd
    #2  sss  dd
    #3   de  dd
    #4  dds rrr
    #5 dsds eed
    


    两种基于stringi 的方法:

    library(stringi)
    v1 <- stri_extract_last_regex(df$V1, "\\S+")
    v2 <- stri_extract_first_regex(df$V1, "\\S+")
    

    或者

    stri_extract_all_regex(df$V1, "^\\S+|\\S+$", simplify = TRUE)
    # this variant explicitly checks for the spaces with lookarounds:
    stri_extract_all_regex(df$V1, "^\\S+(?=\\s)|(?<=\\s)\\S+$", simplify = TRUE)
    

    【讨论】:

    • 正则表达式太棒了!或许你可以加tidyr::separate(df, V1, c("V1", "V2"), "\\s(?:.+\\s)?")
    【解决方案2】:

    也许是这个?

    lst <- strsplit(athletes.df$V1, "\\s+")
    v1 <- sapply(lst ,`[`, 1)
    v2 <- sapply(lst, function(x) x[length(x)])
    

    或者

    data.frame(t(sapply(strsplit(athletes.df$V1, "\\s+"), 
                        function(x) c(x[1], x[length(x)]))))
    

    【讨论】:

      【解决方案3】:

      不使用任何包,这可以在使用sub 创建分隔符后使用read.table 完成。

      read.table(text=sub("^(\\S+)\\s+.*\\s+(\\S+)$", "\\1 \\2", df1$V1), 
                           header=FALSE, stringsAsFactors= FALSE)
      #     V1  V2
      #1  fff ddd
      #2  sss  dd
      #3   de  dd
      #4  dds rrr
      #5 dsds eed
      

      另一个方便的选项是word from stringr

      library(stringr)
      transform(df1, V1 = word(V1, 1), V2 = word(V1, -1))
      #   V1  V2
      #1  fff ddd
      #2  sss  dd
      #3   de  dd
      #4  dds rrr
      #5 dsds eed
      

      数据

      df1 <- structure(list(V1 = c("fff fffd ddd", "sss dd", "de dd",
      "dds sssd eew rrr", 
      "dsds eed")), .Names = "V1", class = "data.frame", row.names = c(NA, 
      -5L))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-18
        • 1970-01-01
        • 1970-01-01
        • 2017-08-11
        相关资源
        最近更新 更多