Назначение класса на основе значений столбца - PullRequest
3 голосов
/ 25 мая 2019

У меня есть набор данных, подобный следующему:

a <- structure(list(ID = c("a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9"), 
                    E = c(1, 0, 0, 0,4, 4, 3, 0,1), 
                    W = c(0, 3, 2, 0, 3, 3, 3, 4,1), 
                    N = c(1, 0, 2, 0, 3, 4, 3, 7,1), 
                    S=c(0, 0, 0, 2, 1, 1, 3, 0,1)), 
               .Names = c("ID", "E", "W", "N", "S"), row.names = c(NA, -9L), class = "data.frame")
a
  ID E W N S
1 a1 1 0 1 0
2 a2 0 3 0 0
3 a3 0 2 2 0
4 a4 0 0 0 2
5 a5 4 3 3 1
6 a6 4 3 4 1
7 a7 3 3 3 3
8 a8 0 4 7 0
9 a9 1 1 1 1

Мне нравится создавать столбец class, который будет показывать column name на основе максимального числа для каждой строки. Например, вторая строка с идентификатором a2 имеет максимальное значение 3 для столбца W. Класс будет W, а максимальное - 3. Когда связывание произойдет в максимальных значениях , оно будет включать все имена связанных столбцов. Например, для строки 1 (ID=a1) оба столбца E и столбец N имеют одинаковое максимальное значение , поэтому класс будет определен как E-N, а максимальное значение будет равно 1 .

Я начал с функции melt:

library(reshape2)
a1= melt(a, id=c("ID"))
head(a1)
  ID variable value
1 a1        E     1
2 a2        E     0
3 a3        E     0
4 a4        E     0
5 a5        E     4
6 a6        E     4

Окончательный результат будет:

  ID   Class Max
1 a1     E-N   1
2 a2       W   3
3 a3     W-N   2
4 a4       S   2
5 a5       E   4
6 a6     E-N   4
7 a7 E-W-N-S   3
8 a8       N   7
9 a9 E-W-N-S   1

Ответы [ 2 ]

4 голосов
/ 25 мая 2019

Подход Base R с использованием apply будет состоять в том, чтобы найти max в каждой строке и найти соответствующие имена столбцов.

a[c("max", "class")] <- t(apply(a[-1], 1, function(x) {
      val <- max(x)
      c(val, paste(names(a)[-1][x == val], collapse = "-"))
}))

a[c(1, 6, 7)]
#  ID   max   class
#1 a1     1     E-N
#2 a2     3       W
#3 a3     2     W-N
#4 a4     2       S
#5 a5     4       E
#6 a6     4     E-N
#7 a7     3 E-W-N-S
#8 a8     7       N
#9 a9     1 E-W-N-S

Вы также можете получить имя столбца, используя which (как предложено @tmfmnk), заменив последнюю строку в вызове apply на

c(val, paste(names(which(x == val)), collapse = "-")) 
3 голосов
/ 25 мая 2019

1) Можно указать gather в формате 'long', сгруппированные по 'ID', filter строки, имеющие max 'val', затем summarize по paste с помощью «ключа» и возьмите first из «val»

library(tidyverse)
gather(a, key, val, -ID) %>% 
    group_by(ID) %>%
    filter(val == max(val)) %>% 
    summarise(Class = str_c(key, collapse="-"), Max = first(val))
# A tibble: 9 x 3
#  ID    Class     Max
#  <chr> <chr>   <dbl>
#1 a1    E-N         1
#2 a2    W           3
#3 a3    W-N         2
#4 a4    S           2
#5 a5    E           4
#6 a6    E-N         4
#7 a7    E-W-N-S     3
#8 a8    N           7
#9 a9    E-W-N-S     1

2) Или другой вариант в tidyverse без изменения формы

a %>% 
  mutate(out = select(., -1)  %>%
                  pmap(.,  ~ c(...) %>%
                   keep(. == max(.)) %>%
                  {tibble(Class = str_c(names(.), collapse='-'),
                          Max = first(.))})) %>%
  unnest
#   ID E W N S   Class Max
#1 a1 1 0 1 0     E-N   1
#2 a2 0 3 0 0       W   3
#3 a3 0 2 2 0     W-N   2
#4 a4 0 0 0 2       S   2
#5 a5 4 3 3 1       E   4
#6 a6 4 3 4 1     E-N   4
#7 a7 3 3 3 3 E-W-N-S   3
#8 a8 0 4 7 0       N   7
#9 a9 1 1 1 1 E-W-N-S   1

3) Или с использованием data.table

library(data.table)
melt(setDT(a), id.var = 'ID')[, {
     dat <- .SD[value == max(value)]
 .(Class = paste(dat$variable, collapse='-'), Max = dat$value[1])}, by = ID]

ПРИМЕЧАНИЕ. Это дает ожидаемый выходной сигнал OP


4) или используя base R

Max <- do.call(pmax, a[-1])
Class <-  tapply(names(a)[-1][col(a[-1]) *NA^(a[-1] != Max)], 
     c(row(a[-1])), FUN = function(x)  paste(na.omit(x), collapse='-'))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...