Выберите самые высокие значения в фрейме данных по группе

Имею следующий df

dat <- data.frame(Cases = c("Student3","Student3","Student3","Student1","Student1",
"Student2","Student2","Student2","Student4"), Class = rep("Math", 9),
Scores = c(9,5,2,7,3,8,5,1,7), stringsAsFactors = F)


> dat
   Cases    Class   Scores
1 Student3  Math      9
2 Student3  Math      5
3 Student3  Math      2
4 Student1  Math      7
5 Student1  Math      3
6 Student2  Math      8
7 Student2  Math      5
8 Student2  Math      1
9 Student4  Math      7

С другой стороны, у меня есть еще один df со следующей информацией:

d <- data.frame(Cases = c("Student3", "Student1",
"Student2", "Student4"), Class = rep("Math", 4), stringsAsFactors = F)

    Cases  Class
1 Student3  Math
2 Student1  Math
3 Student2  Math
4 Student4  Math

С помощью этих двух я хочу извлечь самый высокий scores для каждого student. Итак, мой результат будет выглядеть так:

> dat_output
    Cases  Class   Scores
1 Student3  Math      9
2 Student1  Math      7
3 Student2  Math      8
4 Student4  Math      7

Я пробовал с merge, но он не извлекает только самые высокие scores.

Не думаю, что это дубликат, потому что я никогда не просил использовать библиотеку. К тому же принятый ответ был написан на base R, а не на dplyr.

Cahidora 17.08.2018 10:21

возможный дубликат stackoverflow.com/questions/24558328/…

tjebo 17.08.2018 10:23

и stackoverflow.com/questions/27534284/…

tjebo 17.08.2018 10:24

@Tjebo Да, есть много других постов с «найти максимальное количество на группу», но в этом посте есть шаг «фильтрации»: делайте это только для подмножества студентов, которые также находятся в d dataframe.

zx8754 17.08.2018 10:25

@Tjebo, пожалуйста, прочтите вопрос внимательно, он не требует максимума в группе.

Ronak Shah 17.08.2018 10:26

@RonakShah, название для меня говорит на другом языке.

tjebo 17.08.2018 10:27

@ zx8754 Даже если список групп, для которых должен быть найден максимум, взят из другого фрейма данных, это все равно вопрос «максимум в группе», который имеет множество дубликатов (8+ просто поиск с текущим заголовком). Шаг «фильтр» не отражен в заголовке вопроса, и, честно говоря, в любом случае должен быть отдельный вопрос (который также был задан раньше).

Mikko Marttila 17.08.2018 12:21

@MikkoMarttila, конечно, делай (голосуй) как хочешь. Согласитесь не согласиться.

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

Ответы 7

Если я прав, вам не нужен d, поскольку в d нет дополнительной информации, которой уже нет в dat.

Вы можете просто сделать:

dat_output <- aggregate(Scores ~ Cases, dat, max)
dat_output

     Cases Scores
1 Student1      7
2 Student2      8
3 Student3      9
4 Student4      7

В d могут быть определенные записи, которых нет в dat. Не обязательно, что образец представляет фактические данные.

Ronak Shah 17.08.2018 09:32
Ответ принят как подходящий

Мы можем использовать sapply для каждого Cases в d, подмножество dat для этого Cases и получить для него оценку max.

sapply(d$Cases, function(x) max(dat$Scores[dat$Cases %in% x]))

#Student3 Student1 Student2 Student4 
#       9        7        8        7 

Чтобы получить результат в виде data.frame

transform(d, Scores = sapply(d$Cases, function(x) 
                     max(dat$Scores[dat$Cases %in% x])))

#    Cases Class Scores
# Student3  Math      9 
# Student1  Math      7
# Student2  Math      8
# Student4  Math      7

Примечание. Я предположил, что ваш d

d <- data.frame(Cases = c("Student3", "Student1",
      "Student2", "Student4"), Class = rep("Math", 4), stringsAsFactors = F)

также tapply() может это сделать

jogo 17.08.2018 09:29

Как в таком случае преобразовать результат в df?

Cahidora 17.08.2018 09:43

С обновленным ответом я просто получаю scores без student# ... у вас есть students и scores?

Cahidora 17.08.2018 09:48

@Cahidora На самом деле это были имена строк, вместо них добавлена ​​опция с transform, извините за путаницу.

Ronak Shah 17.08.2018 09:52

Просто, быстро и без библиотек ... Отлично работает! Спасибо.

Cahidora 17.08.2018 09:54

И последнее ... если у меня есть дополнительный столбец рядом с Class в dat, и я хочу включить его в вывод, где я могу его добавить?

Cahidora 17.08.2018 10:16

@Cahidora На каком основании вы хотите выбрать значение в дополнительном столбце? Будет ли это соответствующее значение max?

Ronak Shah 17.08.2018 10:25

Это просто столбец с дополнительной информацией, соответствующей значению max.

Cahidora 17.08.2018 10:26

@Cahidora Извините, я сейчас немного заблокирован, я не мог придумать ничего лучше, чем cbind(d, t(sapply(d$Cases, function(x) { sub_df = dat[dat$Cases %in% x,]; inds = which.max(sub_df$Scores); c(sub_df$Scores[inds], sub_df$New[inds]) }))), в тот момент, когда New - это дополнительный столбец, который вы хотите добавить.

Ronak Shah 17.08.2018 10:39

@RonakShah отлично работает, чтобы добавить столбцы ... ты гений! Большое спасибо!

Cahidora 17.08.2018 10:46

Использование dplyr:

df %>% 
  group_by(Cases, Class) %>% 
  summarise(Scores = max(Scores))

# A tibble: 4 x 3
# Groups:   Cases [?]
  Cases    Class Scores
  <chr>    <chr>  <dbl>
1 Student1 Math      7.
2 Student2 Math      8.
3 Student3 Math      9.
4 Student4 Math      7.

Учитывая, что вы хотите сопоставить два dfs:

df %>%  
  right_join(df2, by = c("Cases", "Class")) %>% 
  group_by(Cases, Class) %>% 
  summarise(Scores = max(Scores))

# A tibble: 4 x 3
# Groups:   Cases [?]
  Cases    Class Scores
  <chr>    <chr>  <dbl>
1 Student1 Math      7.
2 Student2 Math      8.
3 Student3 Math      9.
4 Student4 Math      7.

вам также нужно сгруппировать по классу, если есть несколько значений класса

Sandipan Dey 17.08.2018 09:33

После правок это выглядит как копия ответа @SandipanDey.

zx8754 17.08.2018 09:48

Думаю, очевидно, что мы используем (немного) разные подходы.

tmfmnk 17.08.2018 09:56

с dplyr, и учитывая случай, когда ваш d содержит подмножество студентов из вашего dat

library(dplyr)
inner_join(d, dat %>% group_by(Cases, Class) %>% summarize(Scores=max(Scores)))

# Cases Class Scores
#1 Student3  Math      9
#2 Student1  Math      7
#3 Student2  Math      8
#4 Student4  Math      7

если порядок не имеет значения, то более эффективно следующее:

inner_join(dat, d) %>% group_by(Cases, Class) %>% summarize(Scores=max(Scores))
# A tibble: 4 x 3
# Groups:   Cases [?]
#  Cases    Class Scores
#  <chr>    <chr>  <dbl>
#1 Student1 Math       7
#2 Student2 Math       8
#3 Student3 Math       9
#4 Student4 Math       7

Я предпочитаю этот ответ. Я предлагаю сначала выполнить соединение, а затем передать объединенные данные в group_by и т. д.

zx8754 17.08.2018 09:43

Да, но это изменит порядок элементов в вашем окончательном выводе (порядок будет отличаться от d), хотя это будет эффективно с точки зрения оптимизации запросов и т. д.

Sandipan Dey 17.08.2018 09:45

Хороший момент, я предпочитаю эффективность порядку данных.

zx8754 17.08.2018 09:47

Используя dplyr, группируйте по студентам и получайте первое значение на основе баллов:

library(dplyr)

dat %>% 
  filter(Cases %in% d$Cases) %>% 
  group_by(Cases) %>% 
  top_n(1, Scores) %>%
  ungroup()

# # A tibble: 4 x 3
#   Cases    Class Scores
#   <chr>    <chr>  <dbl>
# 1 Student1 Math       7
# 2 Student2 Math       8
# 3 Student3 Math       9
# 4 Student4 Math       7

Вы также можете использовать пакет sqldf следующим образом:

sqldf("select max(Scores), Cases from dat JOIN d USING(Cases) group by Cases")

Примените операцию JOIN, group by cases и select max(Scores),Cases, чтобы получить желаемый результат:

   max(Scores)    Cases
1           7    Student1
2           8    Student2
3           9    Student3
4           7    Student4

Вы можете отсортировать фрейм данных на Scores в порядке убывания с помощью order. Затем удалите дубликат Cases. Это решение base R.

dat <- dat[order(-dat$Scores),]
dat[duplicated(dat$Cases)==F,]

     Cases Class Scores
1 Student3  Math      9
6 Student2  Math      8
4 Student1  Math      7
9 Student4  Math      7

Если вы сначала хотите убедиться, что все сэмплы в dat также находятся в d, вы можете сделать это на первом этапе. %in% выполняет сопоставление значений. Однако это не имеет значения на основе приведенного выше примера.

dat <- dat[dat$Cases %in% d$Cases & dat$Class %in% d$Class,]

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