агрегированные строки матрицы на основе групп, указанных в списке - PullRequest
0 голосов
/ 17 декабря 2018

У меня есть следующая матрица 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 строк должны образовывать группу в следующем смысле:

Строки 3-5 из M следует заменить одной строкой, у которой min каждого значения должно быть min минимумав строках 3-5 значение max должно быть максимальным, а число наблюдений должно быть суммой.

Таким образом, результат должен выглядеть следующим образом:

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 голосов
/ 17 декабря 2018

Мы предполагаем, что нам следует использовать min или max для определенного столбца, если имя столбца заканчивается на _min или _max и sum, если имя столбца содержит Num.

Теперь создайте группирующую переменную g.Мы использовали общее выражение ниже, но если бы мы знали, что unlist(L) равняется 1:nrow(M), как здесь, то values будет равно 1:nrow(M), а выражение для g сводится к более простому выражению g <- stack(setNames(L, seq_along(L))$ind.

Также определите fn как символьный вектор имен функций ("min", "max", "sum") для применения.Затем выполните итерацию одновременно по столбцам и fn, используя mapply, и для каждой пары используйте tapply для обработки, как показано.

Это должно обобщаться, если для имен столбцов используется одна и та же кодировкаmin, max и sum.Порядок входных столбцов является произвольным и будет сохраняться при выводе.Например, если бы порядок столбцов был pregnant_min, pregnant_max, glucose_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)

подача:

  pregnant_min glucose_min blood_min skin_min INSULIN_min MASS_min DIAB_min
1          0.0           0         0        0           0        0        0
2          0.2           0         0        0           0        0        0
3          0.4           0         0        0           0        0        0
  AGE_min CLASS_min pregnant_max glucose_max blood_max skin_max INSULIN_max
1       0         0          0.2           1         1        1           1
2       0         0          0.4           1         1        1           1
3       0         0          1.0           1         1        1           1
  MASS_max DIAB_max AGE_max CLASS_max NumOfObser
1        1        1       1         1        423
2        1        1       1         1        176
3        1        1       1         1        169
0 голосов
/ 17 декабря 2018
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, то мы возвращаем строку в том виде, как она есть, поскольку max и min в матрице с 1 строкой дали бы нам ту же строку.Если length больше 1, то мы берем минимум каждого min_col и максимум в каждом max_col, берем sum столбца «NumOfObser» и возвращаем одну строку для этой группы.Наконец, мы rbind все эти строки и присваиваем им оригинальные значимые имена, используя setNames.


Я использовал функции colMins и colMaxs, потому что это легко понять и делает операцию простой,Если кого-то интересует только базовый ответ R, он может использовать sapply для получения по столбцам max и min

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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...