【问题标题】:Average row values of a subset of columns based on (excluded) corresponding column value in R基于(排除)R中对应列值的列子集的平均行值
【发布时间】:2020-05-05 16:03:20
【问题描述】:

我正在寻找一种更简洁的解决方案,用于根据相应列值的条件为我的数据中的选择列创建一列行均值。 我创建了一些虚拟数据来说明我的意思。 每行是一组响应,每个编号为 AB 的变量是来自组内相同响应的变量。 我想找到每一行的 A 值的平均值,但只有那些满足相应 B 值标准的人(例如> 17)。

df = data.frame(
  A1 = c(15,15,1,5,8),
  A2 = c(10,NA,5,3,10),
  A3 = c(NA,NA,6,4,10),
  A4 = c(NA,NA,5,5,NA),
  B1 = c(55,40,29,33,42),
  B2 = c(29,NA,18,11,26),
  B3 = c(NA,NA,14,8,22),
  B4 = c(NA,NA,11,16,NA))

> df
  A1 A2 A3 A4 B1 B2 B3 B4
1 15 10 NA NA 55 29 NA NA
2 15 NA NA NA 40 NA NA NA
3  1  5  6  5 29 18 14 11
4  5  3  4  5 33 11  8 16
5  8 10 10 NA 42 26 22 NA

所以寻找这样的东西。

    mean
1 12.500
2 15.000
3  3.000
4  5.000
5  9.333

到目前为止,我的解决方案是创建一个新列,复制我想要包含的所有 A 值,然后在这些列上执行 rowMeans

for (i in 1:4){
  A_inc = ifelse(df[,paste('B',i,sep='')] >= 17, df[,paste('A',i,sep='')],
                NA)
  df[, paste0('A_inc',i,sep = '')] <- A_inc
}

df$mean = rowMeans(df[grep('A_inc', names(df))], na.rm=TRUE)

> df
  A1 A2 A3 A4 B1 B2 B3 B4 A_inc1 A_inc2 A_inc3 A_inc4      mean
1 15 10 NA NA 55 29 NA NA     15     10     NA     NA 12.500000
2 15 NA NA NA 40 NA NA NA     15     NA     NA     NA 15.000000
3  1  5  6  5 29 18 14 11      1      5     NA     NA  3.000000
4  5  3  4  5 33 11  8 16      5     NA     NA     NA  5.000000
5  8 10 10  0 42 26 22  3      8     10     10     NA  9.333333

这很有效,但是对于我更大的数据集以及来自更多列(B、C、D 等)的更复杂的条件来说很麻烦。我知道必须有更好的方法来做到这一点,并希望得到一些更好的方法。

【问题讨论】:

    标签: r


    【解决方案1】:

    您可以使用rowMeans 覆盖!B&gt;17 的值:

    x <- df[,startsWith(colnames(df), "A")]
    x[!df[,gsub("A", "B", colnames(x))] > 17] <- NA
    rowMeans(x, na.rm=TRUE)
    #[1] 12.500000 15.000000  3.000000  5.000000  9.333333
    

    我假设每个 A 都有一个对应的 B。

    【讨论】:

    • 我担心将这种方法扩展到更大的数据集、更复杂的条件和更多列会多么容易。很容易出错,每次你想要一个稍微不同的规范时,你都必须从头开始。
    • 你能举个例子吗?
    • 如果 B 的均值大于某个值,条件是 B 大于某个值,您将如何处理?我想更一般地说,我认为施加越来越多的条件会变得很俗气。不过我肯定是错的!
    • 但不问这个条件。我认为它适用于更大的数据集更多的列
    • 还要求提供“更复杂的条件”,我的示例当然可能是所需的条件。我的意思是,如果他只是想要类似这个特定示例的东西,那么我完全同意您的方法很好,我只是认为更一般地说,他的问题从根本上是关于重组数据集,然后对其进行分析,而不是使用当前的数据集。
    【解决方案2】:

    如您所愿,为了提供更大的灵活性,您需要从根本上重组数据。一旦您以易于操作的形式获得它,您就可以轻松地进行任何您想要的分析。因此,成本从构建这个数据集开始,然后任何操作都相对成本较低。特别是,您想使用 R 的 data.frame 功能,因此需要相应地熔化/转换您的数据集,以便每一行都是带有变量 A 和 B 的 groupXid 观察值。下面是使用@987654321 完成此操作的一种方法@:

    df = data.frame(
      A1 = c(15,15,1,5,8),
      A2 = c(10,NA,5,3,10),
      A3 = c(NA,NA,6,4,10),
      A4 = c(NA,NA,5,5,NA),
      B1 = c(55,40,29,33,42),
      B2 = c(29,NA,18,11,26),
      B3 = c(NA,NA,14,8,22),
      B4 = c(NA,NA,11,16,NA))
    
    setDT(df)
    
    #each group is a row, so define these groups
    df[, group := 1:.N]
    
    #melt where idvar is a group
    df = melt(df, id.var = "group")
    
    #variables are defined by the first letter you define, easy to adapt this accordingly
    df[, vars := substring(variable,1,1)]
    #individuals within a group are defined by the number, 
    #ie the second character in the column names of your original dataset
    df[, id := substring(variable,2)]
    df[, variable := NULL]
    
    #now cast so that each row is a groupXid observation, and columns are the variables vars
    rdy_dt = dcast(df, group + id ~ vars, value.var = "value")
    

    这样您就拥有了所需的数据集,现在可以使用 data.table 的功能来做任何您想做的事情。例如,要获得手段,只需这样做

    #condition is B >= 17, and we want the mean by group.
    rdy_dt[B >= 17, mean(A,na.rm = T), by = group]
       group        V1
    1:     1 12.500000
    2:     2 15.000000
    3:     3  3.000000
    4:     4  5.000000
    5:     5  9.333333
    

    您基本上可以组合来自多个变量的任何条件集。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-05
      • 2021-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-25
      • 2020-12-22
      • 2015-04-11
      相关资源
      最近更新 更多