Имею следующий 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.
возможный дубликат stackoverflow.com/questions/24558328/…
и stackoverflow.com/questions/27534284/…
@Tjebo Да, есть много других постов с «найти максимальное количество на группу», но в этом посте есть шаг «фильтрации»: делайте это только для подмножества студентов, которые также находятся в d dataframe.
@Tjebo, пожалуйста, прочтите вопрос внимательно, он не требует максимума в группе.
@RonakShah, название для меня говорит на другом языке.
@ zx8754 Даже если список групп, для которых должен быть найден максимум, взят из другого фрейма данных, это все равно вопрос «максимум в группе», который имеет множество дубликатов (8+ просто поиск с текущим заголовком). Шаг «фильтр» не отражен в заголовке вопроса, и, честно говоря, в любом случае должен быть отдельный вопрос (который также был задан раньше).
@MikkoMarttila, конечно, делай (голосуй) как хочешь. Согласитесь не согласиться.





Если я прав, вам не нужен 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. Не обязательно, что образец представляет фактические данные.
Мы можем использовать 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() может это сделать
Как в таком случае преобразовать результат в df?
С обновленным ответом я просто получаю scores без student# ... у вас есть students и scores?
@Cahidora На самом деле это были имена строк, вместо них добавлена опция с transform, извините за путаницу.
Просто, быстро и без библиотек ... Отлично работает! Спасибо.
И последнее ... если у меня есть дополнительный столбец рядом с Class в dat, и я хочу включить его в вывод, где я могу его добавить?
@Cahidora На каком основании вы хотите выбрать значение в дополнительном столбце? Будет ли это соответствующее значение max?
Это просто столбец с дополнительной информацией, соответствующей значению max.
@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 - это дополнительный столбец, который вы хотите добавить.
@RonakShah отлично работает, чтобы добавить столбцы ... ты гений! Большое спасибо!
Использование 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.
вам также нужно сгруппировать по классу, если есть несколько значений класса
После правок это выглядит как копия ответа @SandipanDey.
Думаю, очевидно, что мы используем (немного) разные подходы.
с 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 и т. д.
Да, но это изменит порядок элементов в вашем окончательном выводе (порядок будет отличаться от d), хотя это будет эффективно с точки зрения оптимизации запросов и т. д.
Хороший момент, я предпочитаю эффективность порядку данных.
Используя 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,]
Не думаю, что это дубликат, потому что я никогда не просил использовать библиотеку. К тому же принятый ответ был написан на
base R, а не наdplyr.