我有以下数据框(实际数据具有更多的列数):
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
答案 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