Агрегируйте кадр данных для данного столбца и отобразите другой столбец

r aggregate plyr greatest-n-per-group

109825 просмотра

8 ответа

У меня есть датафрейм в 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

Любой намек?

Автор: jul635 Источник Размещён: 24.07.2019 12:29

Ответы (8)


36 плюса

Решение

Сначала вы разделяете данные, используя split:

split(z,z$Group)

Затем для каждого чанка выберите строку с максимальным счетом:

lapply(split(z,z$Group),function(chunk) chunk[which.max(chunk$Score),])

Наконец уменьшить обратно к data.frame do.callИнг 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

Одна строка, никаких магических заклинаний, быстрая, результат имеет хорошие имена =)

Автор: mbq Размещён: 09.06.2011 08:30

49 плюса

Основным решением 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, какие столбцы совпадают.

Автор: Gavin Simpson Размещён: 09.06.2011 08:16

13 плюса

Вот решение с использованием plyrпакета.

Следующая строка кода, по сути, говорит, ddplyчто сначала нужно сгруппировать ваши данные по группам, а затем в каждой группе возвращается подмножество, где балл равен максимальному баллу в этой группе.

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которое возвратит многократные линии максимума, если они есть).

Автор: Andrie Размещён: 09.06.2011 07:51

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
Автор: Sacha Epskamp Размещён: 09.06.2011 07:53

4 плюса

Поздний ответ, но и подход с использованием 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 для каждой группы, исключая столбцы группы

Автор: mnel Размещён: 31.10.2012 10:55

4 плюса

Чтобы добавить к ответу Гевина: до слияния, можно получить агрегат для использования собственных имен, когда не используется интерфейс формулы:

aggregate(data[,"score", drop=F], list(group=data$group), mean) 
Автор: Dan Размещён: 28.01.2013 04:39

3 плюса

Вот как я 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
Автор: Roman Luštrik Размещён: 09.06.2011 08:17

1 плюс

У меня недостаточно высокая репутация, чтобы комментировать ответ Гэвина Симпсона, но я хотел предупредить, что, по-видимому, существует разница в обработке по умолчанию пропущенных значений между стандартным синтаксисом и синтаксисом формулы для aggregate.

#Create some data with missing values 
a<-data.frame(day=rep(1,5),hour=c(1,2,3,3,4),val=c(1,NA,3,NA,5))
  day hour val
1   1    1   1
2   1    2  NA
3   1    3   3
4   1    3  NA
5   1    4   5

#Standard syntax
aggregate(a$val,by=list(day=a$day,hour=a$hour),mean,na.rm=T)
  day hour   x
1   1    1   1
2   1    2 NaN
3   1    3   3
4   1    4   5

#Formula syntax.  Note the index for hour 2 has been silently dropped.
aggregate(val ~ hour + day,data=a,mean,na.rm=T)
  hour day val
1    1   1   1
2    3   1   3
3    4   1   5
Автор: John Размещён: 18.06.2018 09:36
Вопросы из категории :
32x32