Вычислить максимальное значение в нескольких столбцах по нескольким группам

У меня есть файл данных с числовыми значениями в трех столбцах и две группирующие переменные (ID и Group), из которых мне нужно вычислить одно максимальное значение по ID и Group:

structure(list(ID = structure(c(1L, 1L, 1L, 2L), .Label = c("a1", 
"a2"), class = "factor"), Group = structure(c(1L, 1L, 2L, 2L), .Label = 
c("abc", 
"def"), class = "factor"), Score1 = c(10L, 0L, 0L, 5L), Score2 = c(0L, 
0L, 5L, 10L), Score3 = c(0L, 11L, 2L, 11L)), class = "data.frame", row.names = 
c(NA, 
-4L))

Результат, который я пытаюсь получить:

structure(list(ID = structure(c(1L, 1L, 2L), .Label = c("a1", 
"a2"), class = "factor"), Group = structure(c(1L, 2L, 2L), .Label = c("abc", 
"def"), class = "factor"), Max = c(11L, 5L, 11L)), class = "data.frame", 
row.names = c(NA, 
-3L))

Я пробую в dplyr следующее:

SampTable<-SampDF %>% group_by(ID,Group) %>% 
summarize(max = pmax(SampDF$Score1, SampDF$Score2,SampDF$Score3))

Но он генерирует эту ошибку:

Error in summarise_impl(.data, dots) : 
Column `max` must be length 1 (a summary value), not 4

Есть ли простой способ добиться этого в dplyr или data.table?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
3 387
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

Решение с использованием data.table. Найдите максимальное значение в столбцах 3:5 (столбцы Score) по ID и Group.

library(data.table)
setDT(d)
d[, .(Max = do.call(max, .SD)), .SDcols = 3:5, .(ID, Group)]

   ID Group Max
1: a1   abc  11
2: a1   def   5
3: a2   def  11

Данные:

d <- structure(list(ID = structure(c(1L, 1L, 1L, 2L), .Label = c("a1", 
"a2"), class = "factor"), Group = structure(c(1L, 1L, 2L, 2L), .Label = 
c("abc", 
"def"), class = "factor"), Score1 = c(10L, 0L, 0L, 5L), Score2 = c(0L, 
0L, 5L, 10L), Score3 = c(0L, 11L, 2L, 11L)), class = "data.frame", row.names = 
c(NA, 
-4L))

Или аналогично ответу @ www, есть melt(DT, meas=patterns("Score"))[, .(Max = max(value)), by=.(ID, Group)]

Frank 13.07.2018 21:57

Это работает очень быстро и правильно с моим большим файлом данных. Я не знал о необходимости do.call с data.table.

user3594490 13.07.2018 21:59

Решение с использованием tidyverse.

library(tidyverse)

dat2 <- dat1 %>%
  gather(Column, Value, starts_with("Score")) %>%
  group_by(ID, Group) %>%
  summarise(Max = max(Value)) %>%
  ungroup()
dat2
# # A tibble: 3 x 3
#   ID    Group   Max
#   <fct> <fct> <dbl>
# 1 a1    abc      11
# 2 a1    def       5
# 3 a2    def      11

Вот пара других вариантов с tidyverse

library(tidyverse)
df1 %>%
     group_by(ID, Group) %>% 
     nest %>% 
     mutate(Max = map_dbl(data, ~ max(unlist(.x)))) %>% 
     select(-data)

Или используя pmax

df1 %>% 
    mutate(Max = pmax(!!! rlang::syms(names(.)[3:5]))) %>% 
    group_by(ID, Group) %>% 
    summarise(Max = max(Max))
# A tibble: 3 x 3
# Groups:   ID [?]
#  ID    Group   Max
#  <fct> <fct> <dbl>
#1 a1    abc      11
#2 a1    def       5
#3 a2    def      11

Или используя base R

aggregate(cbind(Max = do.call(pmax, df1[3:5])) ~ ID + Group, df1, max)

Вот примерное решение с использованием nest:

library(tidyverse)
df %>%
  nest(-(1:2),.key = "Max") %>%
  mutate_at("Max",map_dbl, max)
#   ID Group Max
# 1 a1   abc  11
# 2 a1   def   5
# 3 a2   def  11

В базе R:

res <- aggregate(. ~ ID + Group,df,max)
res <- cbind(res[1:2], Max = do.call(pmax,res[-(1:2)]))
res
#   ID Group Max
# 1 a1   abc  11
# 2 a1   def   5
# 3 a2   def  11

Вот базовое решение R

# gives 2x2 table
x <- by(df[, !names(df) %in% c("ID", "Group")], list(df$ID, df$Group), max)

# get requested format
tmp <- expand.grid(ID = rownames(x), Group = colnames(x))
tmp$Max <- as.vector(x)
tmp[complete.cases(tmp), ]
#R   ID Group Max
#R 1 a1   abc  11
#R 3 a1   def   5
#R 4 a2   def  11

с участием

df <- structure(list(
  ID = structure(c(1L, 1L, 1L, 2L), .Label = c("a1", "a2"), class = "factor"), 
  Group = structure(c(1L, 1L, 2L, 2L), .Label = c("abc", "def"), class = "factor"), 
  Score1 = c(10L, 0L, 0L, 5L), Score2 = c(0L, 0L, 5L, 10L), 
  Score3 = c(0L, 11L, 2L, 11L)), 
  class = "data.frame", row.names = c(NA, -4L))

Другие вопросы по теме