【问题标题】:R: find number of columns > 0 per row for a group of column names with a partial string matchR:为具有部分字符串匹配的一组列名查找每行> 0的列数
【发布时间】:2021-09-20 07:49:02
【问题描述】:

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

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 Y 0 0 0 0 0 0 0
x X Y 0 0 3 0 0 0 0
y X Y 0 1 0 4 0 1 0
z X Y 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)] &gt; 0) 找到值 > 0 的总列数,但我似乎无法弄清楚如何将两者结合起来以找到样本总数 > 0

【问题讨论】:

    标签: r dataframe strsplit rowsum


    【解决方案1】:

    我们可以在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", 
    "X"), Y = c("Y", "Y", "Y", "Y"), A_1_l = c(0L, 0L, 0L, 3L), A_2_m = c(0L, 
    0L, 1L, 4L), B_1_n = c(0L, 3L, 0L, 5L), B_2_l = c(0L, 0L, 4L, 
    6L), C_1_m = c(0L, 0L, 0L, 2L), C_2_n = c(0L, 0L, 1L, 1L), C_3_l = c(0L, 
    0L, 0L, 5L)), class = "data.frame", row.names = c(NA, -4L))
    

    【讨论】:

      【解决方案2】:

      首先过滤数据以仅保留数字列。

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

      tmp <- Filter(is.numeric, df)
      
      rowSums(sapply(split.default(tmp, sub('_.*', '', names(tmp))), 
              function(x) rowSums(x) > 0))
      
      #[1] 0 1 3 3
      

      【讨论】:

      • 我还有其他的字符串列,应该包含在我的原始数据框中。在此示例中是否有一种仅选择数字列的简单方法?我不关心保留 ID 值或任何其他列,我只需要计数结果
      猜你喜欢
      • 2013-10-23
      • 1970-01-01
      • 1970-01-01
      • 2015-11-03
      • 2013-02-25
      • 2023-03-29
      • 1970-01-01
      • 2020-03-29
      • 1970-01-01
      相关资源
      最近更新 更多