使用dplyr按列中的字符串拆分数据框

3
我看到这里的示例展示了如何使用列索引范围来拆分数据框,但是我该如何使用dplyr在列中找到的字符串来拆分我的数据框?我特意创建了我的数据框,以便将来可以根据特定字符串拆分列。
示例数据:
Site   A_Argas   A_Arachnicea   A_Brus   B_Burkoll   B_Brielle  B_Bact
 1       10        0              0         0           0         0
 2       0         0              0         10          22        123
 3       1         2              3         88          12        546

我希望根据字符串,如"A_"或"B_",将此数据框分成多个数据框并分配给它们。
例如,输出结果将是:
 dataframeA
 Site   A_Argas   A_Arachnicea   A_Brus 
 1       10        0              0        
 2       0         0              0        
 3       1         2              3       

 dataframeB
 Site   B_Burkoll   B_Brielle  B_Bact
  1       0           0         0
  2      10          22        123
  3      88          12        546

由于这些数据不是长格式,我似乎无法弄清如何更改我曾用于拆分长格式数据框的旧代码(用于不同的分析)。

dataframeA <- data %>% filter("GroupID" == "Arachnids") # where "A_" in column headers signify arachnid species
dataframeB <- data %>% filter("GroupID" == "Bacteria") # where all "B_" in the column headers are bacterial species
3个回答

2

一个基本的R选项可能是使用grep查找以A_B_开头的列,然后对原始数据框进行子集操作。

a_names <- grep("^A_", names(data), value=TRUE)
dataframeA <- data[ , c("Site", a_names)]
b_names <- grep("^B_", names(data), value=TRUE)
dataframeB <- data[ , c("Site", b_names)]

1
实际上,它在我的完整数据框中没有起作用。不确定为什么,因为我在这里提供的示例只是其中的一小部分...您的解决方案确实适用于我提供的样本集。我的完整数据框只有更多类似于“V_”等的迷你字符串,所以我不明白为什么这不会起作用。 - CuriousDude
哦,我觉得问题是因为我决定摆脱“站点”列,只将它们插入到我的索引中。一旦我放弃了“站点”调用,只使用data[,a_names]就可以解决问题。 - CuriousDude

2

基于group_splitpivot_longerpivot_widermap的另一种可能的解决方案:

library(tidyverse)

df <- structure(list(Site = c(1, 2, 3), A_Argas = c(10, 0, 1), A_Arachnicea = c(0, 
0, 2), A_Brus = c(0, 0, 3), B_Burkoll = c(0, 10, 88), B_Brielle = c(0, 
22, 12), B_Bact = c(0, 123, 546)), row.names = c(NA, -3L), class = "data.frame")

df %>%
  pivot_longer(-1) %>% 
  group_split(str_extract(name, "^[A-Z]\\_")) %>% 
  map(~ pivot_wider(.x, id_cols = Site))

#> [[1]]
#> # A tibble: 3 × 4
#>    Site A_Argas A_Arachnicea A_Brus
#>   <dbl>   <dbl>        <dbl>  <dbl>
#> 1     1      10            0      0
#> 2     2       0            0      0
#> 3     3       1            2      3
#> 
#> [[2]]
#> # A tibble: 3 × 4
#>    Site B_Burkoll B_Brielle B_Bact
#>   <dbl>     <dbl>     <dbl>  <dbl>
#> 1     1         0         0      0
#> 2     2        10        22    123
#> 3     3        88        12    546

1
我们可以在base R中使用split.default来完成此操作,首先删除第一列('Site'),然后通过删除包含_的子字符串(使用trimws)将数据split成一个dataframe的list,接着在list的数据框中添加第一列并更改list名称。请保留HTML标签。
lst1 <- split.default(data[-1], trimws(names(data)[-1], whitespace = "_.*"))

lst2 <- Map(cbind, Site = data['Site'], lst1)
names(lst2) <- paste0("dataframe", names(lst1))

-输出

> lst2
$dataframeA
  Site A_Argas A_Arachnicea A_Brus
1    1      10            0      0
2    2       0            0      0
3    3       1            2      3

$dataframeB
  Site B_Burkoll B_Brielle B_Bact
1    1         0         0      0
2    2        10        22    123
3    3        88        12    546

最好将其保存在列表中,并按元素访问

lst2[["dataframeA"]]
lst2$dataframeA

不要创建多个对象(尽管可以使用list2env创建)

list2env(lst2, .GlobalEnv)

使用 tidyverse,我们可以循环遍历列名的子字符串,并使用 map select 选择相关列。

library(purrr)
library(dplyr)
library(stringr)
str_remove(names(data)[-1] , "_.*") %>%
   unique %>% 
   map(~ data %>% 
   select(Site, starts_with(.x)))

-输出

[[1]]
  Site A_Argas A_Arachnicea A_Brus
1    1      10            0      0
2    2       0            0      0
3    3       1            2      3

[[2]]
  Site B_Burkoll B_Brielle B_Bact
1    1         0         0      0
2    2        10        22    123
3    3        88        12    546

数据

data <- structure(list(Site = 1:3, A_Argas = c(10L, 0L, 1L), A_Arachnicea = c(0L, 
0L, 2L), A_Brus = c(0L, 0L, 3L), B_Burkoll = c(0L, 10L, 88L), 
    B_Brielle = c(0L, 22L, 12L), B_Bact = c(0L, 123L, 546L)), 
class = "data.frame", row.names = c(NA, 
-3L))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接