【问题标题】:Strsplit split string at every characterStrsplit 在每个字符处拆分字符串
【发布时间】:2019-11-15 10:42:14
【问题描述】:

我有一个像这样的庞大数据集:

customer_id     customer_math
  15251           10001010
  10101           11111111
  84787           10101010

我想在每个字符处拆分 customer_math 以获得这样的 df:

customer_id     2012   2013   2014   2015  2016  2017 2018 2019
  15251           1      0     0       0    1     0     1    0
  10101           1      1     1       1    1     1     1    1   
  84787           1      0     1       0    1     0     1    0

我尝试过但失败了。

你能帮我解决这个问题吗?

非常感谢您的支持!

【问题讨论】:

    标签: r strsplit


    【解决方案1】:

    这是一种可能的解决方案,它对正前瞻 (?=.) 进行正则表达式拆分,以在每个字符之前生成拆分。

    out <- strsplit(as.character(df$customer_math), "(?=.)", perl=TRUE)
    data.frame(df, do.call(rbind, out))
    
        customer_id customer_math X1 X2 X3 X4 X5 X6 X7 X8
    1   15251       10001010      1  0  0  0  1  0  1  0
    2   10101       11111111      1  1  1  1  1  1  1  1
    3   84787       10101010      1  0  1  0  1  0  1  0
    

    数据:

    df <- data.frame(customer_id=c(15251, 10101, 84787),
                     customer_math=c(10001010, 11111111, 10101010))
    

    编辑:

    正如@Sotos 所指出的,使用strsplit"" 空字符串作为拆分字符也可以。

    【讨论】:

    • 太棒了!你是明星!祝你有美好的一天!
    • 快速提问:为什么有这么复杂的正则表达式需要perl 参数? sep = '' 不够吗?
    • @GeorgeSoros 你是对的,我已经更新了我的答案。
    【解决方案2】:

    修复列标签的tidyverse 解决方案可能是:

    代码

    df %>% 
      mutate(customer_math = str_replace_all(customer_math,
                                             "\\B", " ")) %>% 
      separate(customer_math, 
               into = as.character(2012:2019), 
               sep = " ")
    

    结果

    # A tibble: 3 x 9
      customer_id `2012` `2013` `2014` `2015` `2016` `2017` `2018` `2019`
            <int> <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr>  <chr> 
    1       15251 1      0      0      0      1      0      1      0     
    2       10101 1      1      1      1      1      1      1      1     
    3       84787 1      0      1      0      1      0      1      0  
    

    【讨论】:

    • 该正则表达式背后的逻辑是什么?似乎有更直接的方法可以在不先操作字符串的情况下进行拆分。除非有什么优势?
    • @camille separate from tidyr 想要分开的东西。我的解决方案是在每个字符之间创建一个空格,然后按空格分隔。如果您知道更好的正则表达式,我可以更新我的答案:)
    • 一个想法是您可以跳过mutate 步骤,只需使用一些匹配字符之间每个步骤的正则表达式,例如"\\B"
    • 感谢@camille,您的建议改进了解决方案。我改了。
    【解决方案3】:

    我们可以使用splitstackshape 中的cSplit 并将每个字符拆分到不同的列中。

    splitstackshape::cSplit(df, "customer_math", sep = "", stripWhite = FALSE)
    
    #   customer_id customer_math_1 customer_math_2 customer_math_3 customer_math_4 
    #1:       15251               1               0               0               0  
    #2:       10101               1               1               1               1  
    #3:       84787               1               0               1               0   
    
    #   customer_math_5 customer_math_6 customer_math_7 customer_math_8
    #1:               1               0               1               0
    #2:               1               1               1               1
    #3:               1               0               1               0
    

    【讨论】:

      【解决方案4】:

      对于这样的任务,我喜欢保持扩展至未知列数的能力。从 2012 年开始,您有多年的列名称,如果您采取一些额外的步骤来重塑您的数据,那么您可能会在没有太多硬编码的情况下获得这些年。

      tidyr::separate_rows 将拆分一列并为来自它的每个项目创建一行。您可以使用诸如"\\B" 之类的正则表达式来匹配每个字符之间的非空格。通过从 2012 年开始沿每个 ID 的行数计数来创建年份列。可选择将这些“0”/“1”值转换为数字,然后重新整形为宽数据。

      library(dplyr)
      library(tidyr)
      df %>%
        separate_rows(customer_math, sep = "\\B") %>%
        group_by(customer_id) %>%
        mutate(year = seq(from = 2012, length.out = n()),
               customer_math = as.numeric(customer_math)) %>%
        pivot_wider(names_from = year, values_from = customer_math)
      #> # A tibble: 3 x 9
      #> # Groups:   customer_id [3]
      #>   customer_id `2012` `2013` `2014` `2015` `2016` `2017` `2018` `2019`
      #>         <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
      #> 1       15251      1      0      0      0      1      0      1      0
      #> 2       10101      1      1      1      1      1      1      1      1
      #> 3       84787      1      0      1      0      1      0      1      0
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-17
        相关资源
        最近更新 更多