在R中的数据帧的n列中拆分字符串

时间:2019-11-21 15:34:42

标签: r

我有以下数据框(实际数据具有更多的列数):

df <- data.frame(
l1=c(ind1='000000',ind2='100100'), 
l2=c(ind1='200204',ind2='124124'), 
l3=c(ind1='400204',ind2='124124'))

在R中,我想将每列分为长度为3的两列。只要保留原始顺序,列名称就无关紧要。因此,我想要的输出是:

ind1 000 000 200 204 400 204
ind2 100 100 124 124 124 124

我确实找到了一些有关如何工作的指针,因此我根据this帖子中的答案之一创建了一个函数。

splitGT <- function(x) {
  return(strsplit(x, "(?<=.{3})", perl=TRUE)[[1]])
}

虽然可以正确进行拆分,但是将其应用于数据框时的结果是一个由原始列分隔的数组:

apply(df, c(1,2), splitGT)

, , l1

     ind1  ind2 
[1,] "000" "100"
[2,] "000" "100"

, , l2

     ind1  ind2 
[1,] "200" "124"
[2,] "204" "124"

, , l3

     ind1  ind2 
[1,] "400" "124"
[2,] "204" "124"

我设法克服了这个问题,但这产生了一个数据帧,每个ind两行,每个原始列一列。虽然这更接近我的需求,但我感觉我似乎遗漏了一些非常明显的东西,因为这似乎对我来说太复杂了。

adply(apply(df, c(1,2), splitGT), c(1, 2))

  X1   X2    l1     l2     l3
1  1 ind1    000    200    400
2  2 ind1    000    204    204
3  1 ind2    100    124    124
4  2 ind2    100    124    124

2 个答案:

答案 0 :(得分:2)

一种选择是使用str_extract_all,然后将各列绑定在一起以获得所需的输出。请记住,输出是一个字符矩阵。应该很容易使用。让我知道您是否有任何问题!

library(stringr)

do.call(cbind, lapply(df, str_extract_all, ".{3}", simplify = T))
     [,1]  [,2]  [,3]  [,4]  [,5]  [,6] 
[1,] "000" "000" "200" "204" "400" "204"
[2,] "100" "100" "124" "124" "124" "124"

# or you could use `dplyr::bind_cols()` with a slight adjustment, keep in mind this 
# is now a dataframe with factor columns. But you could easily work with it, too

library(dplyr)

bind_cols(lapply(df, function(x) as.data.frame(str_extract_all(x, ".{3}", simplify = T))))
   V1  V2 V11 V21 V12 V22
1 000 000 200 204 400 204
2 100 100 124 124 124 124

答案 1 :(得分:1)

这里有两种重塑tidyr的方式。基于最近的pivot_*升级,您还可以根据值是字符串的前半部分还是后半部分来获得漂亮的列名,这有助于确保一切保持秩序。两者都可以很好地扩展到更大的数据帧或更复杂的操作。

第一版:将"l*"列中的所有字符串分隔为前3位和后3位之间的无边界。标记完行后,根据这些"l*"列将其整形为宽。

library(dplyr)
library(tidyr)

df %>%
  tibble::rownames_to_column("id") %>%
  separate_rows(starts_with("l"), sep = "(?<=^\\d{3})\\B(?=\\d{3}$)") %>%
  group_by(id) %>%
  mutate(row = row_number())%>%
  pivot_wider(names_from = row, values_from = starts_with("l"))
#> # A tibble: 2 x 7
#> # Groups:   id [2]
#>   id    l1_1  l1_2  l2_1  l2_2  l3_1  l3_2 
#>   <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 ind1  000   000   200   204   400   204  
#> 2 ind2  100   100   124   124   124   124

第二个版本:将所有"l*"列放入一个长列中,并使用相同的正则表达式进行拆分。然后使用"l*"标记和行号的组合将列整形为宽。

df %>%
  tibble::rownames_to_column("id") %>%
  pivot_longer(starts_with("l")) %>%
  separate_rows(value, sep = "(?<=^\\d{3})\\B(?=\\d{3}$)") %>%
  group_by(id, name) %>%
  mutate(row = row_number()) %>%
  pivot_wider(names_from = c(name, row))
# same output as previous