r-将一个id列包含到split.default生成的列表的所有元素中的规范方式



我正在根据列名将data.frame拆分成一个列表。我想要的是将id列(id(不仅包括在一个项目中,还包括在结果列表的所有元素中。

目前,我正在通过mapbind_cols(通过Map/do.call/mapply等的替代方案,我自己也可以这样做(将id列后续绑定到列表的所有项目。我想知道的是,是否有任何规范的方法可以直接执行,可能使用split.default的函数参数,也可能直接通过其他函数,从而节省两到三个额外的步骤

可复制示例

df <- data.frame(
stringsAsFactors = FALSE,
id = c("A", "B", "C"),
nm1_a = c(928L, 476L, 928L),
nm1_b = c(61L, 362L, 398L),
nm2_a = c(965L, 466L, 369L),
nm2_b = c(240L, 375L, 904L),
nm3_a = c(429L, 730L, 788L),
nm3_b = c(99L, 896L, 540L),
nm3_c = c(463L, 143L, 870L)
)
df
#>   id nm1_a nm1_b nm2_a nm2_b nm3_a nm3_b nm3_c
#> 1  A   928    61   965   240   429    99   463
#> 2  B   476   362   466   375   730   896   143
#> 3  C   928   398   369   904   788   540   870

我目前在做什么

library(tidyverse)
split.default(df[-1], gsub('^(nm\d+).*', '\1', names(df)[-1])) %>%
map(~ .x %>% bind_cols('id' = df$id, .))
#> $nm1
#>   id nm1_a nm1_b
#> 1  A   928    61
#> 2  B   476   362
#> 3  C   928   398
#> 
#> $nm2
#>   id nm2_a nm2_b
#> 1  A   965   240
#> 2  B   466   375
#> 3  C   369   904
#> 
#> $nm3
#>   id nm3_a nm3_b nm3_c
#> 1  A   429    99   463
#> 2  B   730   896   143
#> 3  C   788   540   870

我想要的是完全相同的输出,但有没有直接或更规范的方法?

为了获得多种选择,以下是您所说的不想做的。pivot/split/ppivot方法可以帮助更好地扩展和适应,而不仅仅是根据列位置来保持ID。它还利用ID来进行整形,因此如果在中间步骤中有其他操作要做,并且不确定行顺序是否会保持不变,它可能会更灵活——这也是我有时避免绑定列的原因之一。基于某个变量而不是按列组划分数据(至少对我来说(也是有意义的。

library(tidyr)
df %>%
pivot_longer(-id) %>%
split(stringr::str_extract(.$name, "^nm\d+")) %>%
purrr::map(pivot_wider, id_cols = id, names_from = name)
#> $nm1
#> # A tibble: 3 x 3
#>   id    nm1_a nm1_b
#>   <chr> <int> <int>
#> 1 A       928    61
#> 2 B       476   362
#> 3 C       928   398
#> 
#> $nm2
#> # A tibble: 3 x 3
#>   id    nm2_a nm2_b
#>   <chr> <int> <int>
#> 1 A       965   240
#> 2 B       466   375
#> 3 C       369   904
#> 
#> $nm3
#> # A tibble: 3 x 4
#>   id    nm3_a nm3_b nm3_c
#>   <chr> <int> <int> <int>
#> 1 A       429    99   463
#> 2 B       730   896   143
#> 3 C       788   540   870

您可以使用一个临时变量,这样代码就更简洁易懂了。

common_cols <- 1
tmp <- df[-common_cols]
lapply(split.default(tmp, sub('^(nm\d+).*', '\1', names(tmp))), 
function(x) cbind(df[common_cols], x))
#$nm1
#  id nm1_a nm1_b
#1  A   928    61
#2  B   476   362
#3  C   928   398
#$nm2
#  id nm2_a nm2_b
#1  A   965   240
#2  B   466   375
#3  C   369   904
#$nm3
#  id nm3_a nm3_b nm3_c
#1  A   429    99   463
#2  B   730   896   143
#3  C   788   540   870

这应该只是两个步骤,拆分和替换。

Map(`[<-`, split.default(df[-1], substr(names(df)[-1], 1, 3)), 'id', value=df[1])
# $nm1
#   nm1_a nm1_b id
# 1   928    61  A
# 2   476   362  B
# 3   928   398  C
# 
# $nm2
#   nm2_a nm2_b id
# 1   965   240  A
# 2   466   375  B
# 3   369   904  C
# 
# $nm3
#   nm3_a nm3_b nm3_c id
# 1   429    99   463  A
# 2   730   896   143  B
# 3   788   540   870  C

最新更新