strsplit 在每个字符处拆分字符串

Strsplit split string at every character

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

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

我尝试过但失败了。

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

非常感谢您的支持!

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

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"" 空字符串作为拆分字符也可以。

修复列标签的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  

我们可以使用 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

对于这样的任务,我喜欢保持开放扩展到未知数量列的能力。从 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