根据列表中给出的组汇总矩阵行

时间:2018-12-17 13:21:19

标签: r list vectorization

我有以下矩阵M

structure(c(0, 0.2, 0.4, 0.6, 0.8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2, 0.4, 0.6, 0.8, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 423, 176, 135, 
30, 4), .Dim = c(5L, 19L), .Dimnames = list(NULL, c("pregnant_min", 
"glucose_min", "blood_min", "skin_min", "INSULIN_min", "MASS_min", 
"DIAB_min", "AGE_min", "CLASS_min", "pregnant_max", "glucose_max", 
"blood_max", "skin_max", "INSULIN_max", "MASS_max", "DIAB_max", 
"AGE_max", "CLASS_max", "NumOfObser")))

和列表L

L = list(1L, 2L, 3:5)

列表中的元素指示M的哪些行应分组在一起。 第一和第二行应该是它们自己的组。 3-5行应从以下意义上组成一个组:

M的第3-5行应替换为一行,其每个值的min应该是第3-5行的最小值的minmax应该是最大值,其观察值应为总和。

所以输出应如下所示:

structure(c(0, 0.2, 0.4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2, 0.4, 1, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 423, 
176, 169), .Dim = c(3L, 19L), .Dimnames = list(NULL, c("pregnant_min", 
"glucose_min", "blood_min", "skin_min", "INSULIN_min", "MASS_min", 
"DIAB_min", "AGE_min", "CLASS_min", "pregnant_max", "glucose_max", 
"blood_max", "skin_max", "INSULIN_max", "MASS_max", "DIAB_max", 
"AGE_max", "CLASS_max", "NumOfObser")))

列表L的元素可以由1-5的任意组合组成,对应于M的行数。

在一般情况下如何实现此输出?到目前为止,我已经遍历了L的各个元素,但是我敢肯定,这样做的方法更加简洁/有效。

2 个答案:

答案 0 :(得分:3)

library(matrixStats)
#Get index of "min" cols
min_col <- grep("min", colnames(M))
#Get index of "max" cols
max_col <- grep("max", colnames(M))

setNames(do.call("rbind.data.frame", lapply(L, function(x) {
         if (length(x) > 1)
           c(colMins(M[x, min_col]), colMaxs(M[x, max_col]), sum(M[x, "NumOfObser"]))
         else
           M[x, ]
})), colnames(M))


#  pregnant_min glucose_min blood_min skin_min INSULIN_min MASS_min DIAB_min AGE_min
#1          0.0           0         0        0           0        0        0       0
#2          0.2           0         0        0           0        0        0       0
#3          0.4           0         0        0           0        0        0       0

#  CLASS_min pregnant_max glucose_max blood_max skin_max INSULIN_max MASS_max DIAB_max
#1         0          0.2           1         1        1           1        1        1
#2         0          0.4           1         1        1           1        1        1
#3         0          1.0           1         1        1           1        1        1

#  AGE_max CLASS_max NumOfObser
#1       1         1        423
#2       1         1        176
#3       1         1        169

我们首先找出“ max”和“ min”列的索引,并将它们存储在单独的向量中。对于L中的每个列表元素,我们检查它是否为length,如果它为1,那么我们将按原样返回该行,因为1行矩阵上的maxmin将给我们同一行。如果length大于1,则我们取每个min_col的最小值,取每个max_col取最大值,取“ NumOfObser”列的sum,然后为该组返回一行。最后,我们rbind使用所有这些行,并使用setNames为其赋予原始的有意义的名称。


我已使用colMinscolMaxs函数,因为它易于理解并且使操作简单。如果有人只对基数R的答案感兴趣,他们可以使用sapply获取按列的maxmin

setNames(do.call("rbind.data.frame", lapply(L, function(x) {
    if (length(x) > 1)
      c(sapply(data.frame(M[x, min_col]), min), 
        sapply(data.frame(M[x, max_col]), max), 
        sum(M[x, "NumOfObser"]))
     else
       M[x, ]
 })), colnames(M))

答案 1 :(得分:1)

我们假设,如果列名以minmax结尾,而列名以_min结尾,则应在特定列上使用_maxsum名称包含Num

现在,创建一个分组变量g。我们在下面使用了一个通用表达式,但是如果我们知道unlist(L)等于1:nrow(M),就像这里一样,那么values将等于1:nrow(M),而{{1}的表达式}简化为更简单的表达式g

还将g <- stack(setNames(L, seq_along(L))$ind定义为要应用的函数名称(fn"min""max")的字符向量。然后使用"sum"在各列和fn上同时进行迭代,对于每一对,使用mapply对其进行处理,如图所示。

只要列名中的相同编码用于tapplyminmax,就应该推广。输入列的顺序是任意的,并将在输出时保持不变。例如,如果列顺序为sumpregnant_minpregnant_maxglucose_min等,它将仍然有效并按该顺序返回列。

不使用任何软件包。

glucose_max

给予:

g <- with(stack(setNames(L, seq_along(L))), ind[order(values)])
fn <- sub(".*_", "", colnames(M))
fn[grepl("Num", colnames(M))] <- "sum"
mapply(function(col, fn) tapply(col, g, fn), as.list(as.data.frame(M)), fn)