Совокупность данных в данном столбце и отображение другого столбца
У меня есть dataframe в R следующего вида:
> head(data)
Group Score Info
1 1 1 a
2 1 2 b
3 1 3 c
4 2 4 d
5 2 3 e
6 2 1 f
Я хотел бы объединить его после столбца Score
, используя функцию max
> aggregate(data$Score, list(data$Group), max)
Group.1 x
1 1 3
2 2 4
Но я также хотел бы отобразить столбец Info
, связанный с максимальным значением столбца Score
для каждой группы. Я не знаю, как это сделать. Мой желаемый результат:
Group.1 x y
1 1 3 c
2 2 4 d
Любые подсказки?
Ответы
Ответ 1
Сначала вы разделите данные с помощью split
:
split(z,z$Group)
Чем для каждого фрагмента выберите строку с максимальным счетом:
lapply(split(z,z$Group),function(chunk) chunk[which.max(chunk$Score),])
Наконец, вернемся к data.frame do.call
ing rbind
:
do.call(rbind,lapply(split(z,z$Group),function(chunk) chunk[which.max(chunk$Score),]))
Результат:
Group Score Info
1 1 3 c
2 2 4 d
Одна строка, никакие магические заклинания, быстрая, результат имеет хорошие имена =)
Ответ 2
Базовое решение R заключается в объединении вывода aggregate()
с шагом merge()
. Я считаю интерфейс формул aggregate()
немного более полезным, чем стандартный интерфейс, отчасти потому, что имена на выходе более приятные, поэтому я буду использовать это:
Шаг aggregate()
-
maxs <- aggregate(Score ~ Group, data = dat, FUN = max)
а шаг merge()
- это просто
merge(maxs, dat)
Это дает нам желаемый результат:
R> maxs <- aggregate(Score ~ Group, data = dat, FUN = max)
R> merge(maxs, dat)
Group Score Info
1 1 3 c
2 2 4 d
Вы могли бы, конечно, вставить это в однострочный (промежуточный шаг был больше для экспозиции):
merge(aggregate(Score ~ Group, data = dat, FUN = max), dat)
Основная причина, по которой я использовал интерфейс формулы, заключается в том, что он возвращает фрейм данных с правильным names
для шага слияния; это имена столбцов из исходного набора данных dat
. Нам нужно, чтобы на выходе aggregate()
были правильные имена, чтобы merge()
знал, какие столбцы в исходном и агрегированном кадрах данных совпадают.
Стандартный интерфейс дает нечетные имена, в зависимости от того, как вы его называете:
R> aggregate(dat$Score, list(dat$Group), max)
Group.1 x
1 1 3
2 2 4
R> with(dat, aggregate(Score, list(Group), max))
Group.1 x
1 1 3
2 2 4
Мы можем использовать merge()
на этих выходах, но нам нужно сделать больше работы, сообщая R, которые соответствуют столбцам.
Ответ 3
Вот решение, использующее пакет plyr
.
Следующая строка кода по существу сообщает ddply
, чтобы сначала группировать ваши данные по Group, а затем внутри каждой группы возвращает подмножество, в котором показатель равен максимальному значению в этой группе.
library(plyr)
ddply(data, .(Group), function(x)x[x$Score==max(x$Score), ])
Group Score Info
1 1 3 c
2 2 4 d
И, как указывает @SachaEpskamp, это может быть дополнительно упрощено:
ddply(df, .(Group), function(x)x[which.max(x$Score), ])
(что также имеет то преимущество, что which.max
вернет несколько максимальных строк, если они есть).
Ответ 4
Для этого может использоваться пакет plyr
. С помощью функции ddply()
вы можете разделить фрейм данных на один или несколько столбцов и применить функцию и вернуть кадр данных, а затем с помощью функции summarize()
вы можете использовать столбцы разбитого кадра данных в качестве переменных, чтобы сделать новый кадр данных /;
dat <- read.table(textConnection('Group Score Info
1 1 1 a
2 1 2 b
3 1 3 c
4 2 4 d
5 2 3 e
6 2 1 f'))
library("plyr")
ddply(dat,.(Group),summarize,
Max = max(Score),
Info = Info[which.max(Score)])
Group Max Info
1 1 3 c
2 2 4 d
Ответ 5
Поздний ответ, но и с помощью data.table
library(data.table)
DT <- data.table(dat)
DT[, .SD[which.max(Score),], by = Group]
Или, если возможно иметь более одного наименьшего балла
DT[, .SD[which(Score == max(Score)),], by = Group]
Отмечая, что (из ?data.table
.SD
представляет собой таблицу данных, содержащую подмножество x данных для каждой группы, за исключением столбца (ов) группы
Ответ 6
Чтобы добавить к ответам Gavin: до слияния, можно получить агрегат для использования собственных имен, если не использовать интерфейс формулы:
aggregate(data[,"score", drop=F], list(group=data$group), mean)
Ответ 7
Вот как я base
подумал о проблеме.
my.df <- data.frame(group = rep(c(1,2), each = 3),
score = runif(6), info = letters[1:6])
my.agg <- with(my.df, aggregate(score, list(group), max))
my.df.split <- with(my.df, split(x = my.df, f = group))
my.agg$info <- unlist(lapply(my.df.split, FUN = function(x) {
x[which(x$score == max(x$score)), "info"]
}))
> my.agg
Group.1 x info
1 1 0.9344336 a
2 2 0.7699763 e