【问题标题】:Splitting a dataframe string column into multiple different columns [duplicate]将数据框字符串列拆分为多个不同的列[重复]
【发布时间】:2023-04-05 00:09:03
【问题描述】:

我想要完成的是将一列拆分为多列。我希望第一列包含“F”,第二列包含“US”,第三列“CA6”或“DL”,第四列包含“Z13”或“U13”等。我的整个df遵循相同的模式X.XX.XXXX.XXX 或 X.XX.XXX.XXX 或 X.XX.XX.XXX 我知道第三列是我的问题所在,因为长度不同。我过去只使用过 substr ,我可以在这里使用一些 if 语句,但想学习如何使用 stringr 包和 POSIX 来做到这一点(除非有更好的选择)。提前谢谢你。

这是我的 df:

c("F.US.CLE.V13", "F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", 
"F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", 
"F.US.DL.U13", "F.US.DL.U13", "F.US.DL.U13", "F.US.DL.Z13", "F.US.DL.Z13"
)

【问题讨论】:

    标签: r split dataframe stringr


    【解决方案1】:

    一个非常直接的方法是在你的字符向量上使用read.table

    > read.table(text = text, sep = ".", colClasses = "character")
       V1 V2  V3  V4
    1   F US CLE V13
    2   F US CA6 U13
    3   F US CA6 U13
    4   F US CA6 U13
    5   F US CA6 U13
    6   F US CA6 U13
    7   F US CA6 U13
    8   F US CA6 U13
    9   F US  DL U13
    10  F US  DL U13
    11  F US  DL U13
    12  F US  DL Z13
    13  F US  DL Z13
    

    需要指定colClasses,否则F 将转换为FALSE(这是我需要在“splitstackshape”中修复的问题,否则我会建议:))


    更新(> 一年后)...

    或者,您可以使用my cSplit function,如下所示:

    cSplit(as.data.table(text), "text", ".")
    #     text_1 text_2 text_3 text_4
    #  1:      F     US    CLE    V13
    #  2:      F     US    CA6    U13
    #  3:      F     US    CA6    U13
    #  4:      F     US    CA6    U13
    #  5:      F     US    CA6    U13
    #  6:      F     US    CA6    U13
    #  7:      F     US    CA6    U13
    #  8:      F     US    CA6    U13
    #  9:      F     US     DL    U13
    # 10:      F     US     DL    U13
    # 11:      F     US     DL    U13
    # 12:      F     US     DL    Z13
    # 13:      F     US     DL    Z13
    

    或者,来自“tidyr”的separate,像这样:

    library(dplyr)
    library(tidyr)
    
    as.data.frame(text) %>% separate(text, into = paste("V", 1:4, sep = "_"))
    #    V_1 V_2 V_3 V_4
    # 1    F  US CLE V13
    # 2    F  US CA6 U13
    # 3    F  US CA6 U13
    # 4    F  US CA6 U13
    # 5    F  US CA6 U13
    # 6    F  US CA6 U13
    # 7    F  US CA6 U13
    # 8    F  US CA6 U13
    # 9    F  US  DL U13
    # 10   F  US  DL U13
    # 11   F  US  DL U13
    # 12   F  US  DL Z13
    # 13   F  US  DL Z13
    

    【讨论】:

    • +1 该死的阿南达。让我觉得你做的很愚蠢。 :-)
    • 还有splitstackshape,你不是说shapeshifter吗?
    • 哇。这太简单了。
    • shapeshiftershapeshiftR 更酷。
    • 现在复选标记是你的了!
    【解决方案2】:

    这是你想要做的吗?

    # Our data
    text <- c("F.US.CLE.V13", "F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", 
    "F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", 
    "F.US.DL.U13", "F.US.DL.U13", "F.US.DL.U13", "F.US.DL.Z13", "F.US.DL.Z13"
    )
    
    #  Split into individual elements by the '.' character
    #  Remember to escape it, because '.' by itself matches any single character
    elems <- unlist( strsplit( text , "\\." ) )
    
    #  We know the dataframe should have 4 columns, so make a matrix
    m <- matrix( elems , ncol = 4 , byrow = TRUE )
    
    #  Coerce to data.frame - head() is just to illustrate the top portion
    head( as.data.frame( m ) )
    #  V1 V2  V3  V4
    #1  F US CLE V13
    #2  F US CA6 U13
    #3  F US CA6 U13
    #4  F US CA6 U13
    #5  F US CA6 U13
    #6  F US CA6 U13
    

    【讨论】:

    • 这就是我要找的!和 R 一样,有很多方法可以到达那里。谢谢您的帮助。只需使用合并命令将新的 df 合并回我的主 df 吗?
    • @Tim 没有看到你的data.frame的结构有点难说,但你可以试一试,看看它是否有效?否则,编辑您的问题并粘贴到dput( head( df ) ) 的输出中以获得更可靠的答案! :-)
    • 我只需要unlist()。谢谢
    • 感谢您评论您的代码。评论“记住要逃避它,因为'。'本身匹配任何单个字符”帮助我解决了我的问题。非常感谢:)
    【解决方案3】:

    通过unlistmatrix 的方式似乎有点复杂,需要你硬编码元素的数量(这实际上是一个很大的禁忌。当然你可以绕过硬编码这个数字并在运行时确定)

    我会走一条不同的路线,直接从strsplit 返回的列表中构造一个数据框。对我来说,这在概念上更简单。基本上有两种方法可以做到这一点:

    1. as.data.frame——但由于列表完全是错误的(我们有一个行列表而不是列列表),我们必须转置结果。我们还清除了rownames,因为默认情况下它们很难看(但这完全没有必要!):

      `rownames<-`(t(as.data.frame(strsplit(text, '\\.'))), NULL)
      
    2. 或者,使用rbind 从行列表构造数据框。我们使用do.call 调用rbind,并将所有行作为单独的参数:

      do.call(rbind, strsplit(text, '\\.'))
      

    两种方式产生相同的结果:

         [,1] [,2] [,3]  [,4]
    [1,] "F"  "US" "CLE" "V13"
    [2,] "F"  "US" "CA6" "U13"
    [3,] "F"  "US" "CA6" "U13"
    [4,] "F"  "US" "CA6" "U13"
    [5,] "F"  "US" "CA6" "U13"
    [6,] "F"  "US" "CA6" "U13"
    …
    

    显然,第二种方法比第一种简单得多。

    【讨论】:

    • 并要求您硬编码元素的数量(这实际上是一个非常大的禁忌。但是在 OP 中给出并指定了列数,所以我真的没有问题。不过还有不错的选择。+1
    • 其实我真的喜欢do.call(rbind, strsplit(text, '\\.'))
    【解决方案4】:

    我们可以使用tidyr::extract()

    x <- c("F.US.CLE.V13", "F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", 
      "F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", 
      "F.US.DL.U13", "F.US.DL.U13", "F.US.DL.U13", "F.US.DL.Z13", "F.US.DL.Z13"
    )
    
    
    library(tidyr)
    extract(tibble(data=x),"data", regex = "^(.*?)\\.(.*?)\\.(.*?)\\.(.*?)$",into = LETTERS[1:4])
    #> # A tibble: 13 x 4
    #>    A     B     C     D    
    #>    <chr> <chr> <chr> <chr>
    #>  1 F     US    CLE   V13  
    #>  2 F     US    CA6   U13  
    #>  3 F     US    CA6   U13  
    #>  4 F     US    CA6   U13  
    #>  5 F     US    CA6   U13  
    #>  6 F     US    CA6   U13  
    #>  7 F     US    CA6   U13  
    #>  8 F     US    CA6   U13  
    #>  9 F     US    DL    U13  
    #> 10 F     US    DL    U13  
    #> 11 F     US    DL    U13  
    #> 12 F     US    DL    Z13  
    #> 13 F     US    DL    Z13
    

    另一种选择是使用unglue::unglue_data()

    # remotes::install_github("moodymudskipper/unglue")
    library(unglue)
    unglue_data(x,"{A}.{B}.{C}.{D}")
    #>    A  B   C   D
    #> 1  F US CLE V13
    #> 2  F US CA6 U13
    #> 3  F US CA6 U13
    #> 4  F US CA6 U13
    #> 5  F US CA6 U13
    #> 6  F US CA6 U13
    #> 7  F US CA6 U13
    #> 8  F US CA6 U13
    #> 9  F US  DL U13
    #> 10 F US  DL U13
    #> 11 F US  DL U13
    #> 12 F US  DL Z13
    #> 13 F US  DL Z13
    

    reprex package (v0.3.0) 于 2019-09-14 创建

    【讨论】:

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