R:为具有部分字符串匹配的一组列名查找每行 > 0 的列数 数据

问题描述

我有一个类似于以下内容的数据框:

ID X Y A_1_l A_2_m B_1_n B_2_l C_1_m C_2_n C_3_l
w X 0 0 0 0 0 0 0
x X 0 0 3 0 0 0 0
y X 0 1 0 4 0 1 0
z X 3 4 5 6 2 1 5

一个字母表示样本,数字表示重复,第二个字母表示批次。我正在尝试为每个 ID 找到至少一个值 > 0 的样本数量,并将这些数字存储在列表中。

这是我可以附加到现有数据帧的列表的期望结果:

0,1,3,3

在之前的分析中,我使用 strsplit 来计算每批的样本总数。

colsList <- colnames(df)
cols <- grep("_",colsList,value=TRUE)
splitList <- strsplit(cols,"_\\d_")
stats <-data.frame(t(as.data.frame.list(splitList)))
rownames(stats)<-NULL
names(stats)<-c("Sample","Batch")
perSample <- aggregate(Sample ~ Batch,stats,function(x) length(unique(x))) # number of strains

并且我能够使用 rowSums(df[sapply(df,is.numeric)] > 0) 找到值 > 0 的列总数,但我似乎无法弄清楚如何将两者结合起来以找到 > 0 的样本总数

解决方法

首先过滤数据,只保留数字列。

使用 split.default 将数据分组,以便您将所有 'A' 列归为一组,'B' 归为另一组,依此类推。在每个组内返回 TRUE 如果一行有一个大于 0 的值,sum 将所有组中的所有值放在一起以获得最终计数。

tmp <- Filter(is.numeric,df)

rowSums(sapply(split.default(tmp,sub('_.*','',names(tmp))),function(x) rowSums(x) > 0))

#[1] 0 1 3 3
,

我们可以在 tidyverse

library(dplyr)
library(stringr)
library(tidyr)
df1 %>%  
    select(ID,where(is.numeric)) %>%
    pivot_longer(cols = -ID) %>%
    mutate(name = str_remove(name,"_.*")) %>% 
    group_by(ID,name) %>% 
    summarise(value = sum(value > 0),.groups = 'drop_last') %>% 
    summarise(value = sum(value > 0))
# A tibble: 4 x 2
  ID    value
  <chr> <int>
1 w         0
2 x         1
3 y         3
4 z         3

数据

df1 <- structure(list(ID = c("w","x","y","z"),X = c("X","X","X"),Y = c("Y","Y","Y"),A_1_l = c(0L,0L,3L),A_2_m = c(0L,1L,4L),B_1_n = c(0L,3L,5L),B_2_l = c(0L,4L,6L),C_1_m = c(0L,2L),C_2_n = c(0L,1L),C_3_l = c(0L,5L)),class = "data.frame",row.names = c(NA,-4L))