2017-01-16 3 views
1

Я нашел эту тему Find rows in dataframe with maximum values grouped by values in another column, где обсуждалось одно из решений. Я использую это решение для рекурсивного поиска индекса строки с максимальным количеством. Однако мое решение очень уродливое - очень процедурное, а не векторизованное.Поиск индекса, соответствующего максимальному значению

Вот мой фиктивные данные:

dput(Data) 

structure(list(Order_Year = c(1999, 1999, 1999, 1999, 1999, 1999, 
1999, 2000, 2000, 2001, 2001, 2001, 2001, 2001, 2001, 2001, 2002, 
2002, 2002, 2002), Ship_Year = c(1997, 1998, 1999, 2000, 2001, 
2002, NA, 1997, NA, 1997, 1998, 1999, 2000, 2001, 2002, NA, 1997, 
1998, 1999, 2000), Yen = c(202598.2, 0, 0, 0, 0, 0, 2365901.62, 
627206.75998, 531087.43, 122167.02, 143855.55, 0, 0, 0, 0, 53650.389998, 
17708416.3198, 98196.4, 31389, 0), Units = c(37, 1, 8, 5, 8, 
8, 730, 99, 91, 195, 259, 4, 1, 3, 3, 53, 3844, 142, 63, 27)), .Names = c("Order_Year", 
"Ship_Year", "Yen", "Units"), row.names = c(NA, 20L), class = "data.frame") 

Я хочу, чтобы узнать Ship_Year, для которых Yen и Units максимальны для данного Order_Year.

Вот что я пробовал:

a<-do.call("rbind", by(Data, Data$Order_Year, function(x) x[which.max(x$Yen), ])) 
rownames(a)<-NULL 
a$Yen<-NULL 
a$Units<-NULL 
#a has Ship_Year for which Yen is max for a given Order_Year 
names(a)[2]<-"by.Yen" 
#Now I'd find max year by units 
b<-do.call("rbind", by(Data, Data$Order_Year, function(x) x[which.max(x$Units), ])) 
rownames(b)<-NULL 
b$Yen<-NULL 
b$Units<-NULL 
#b has Ship_Year for which Units is max for a given Order_Year 
names(b)[2]<-"by.Qty" 
c<-a %>% left_join(b) 

Ожидаемый результат:

c 
    Order_Year by.Yen by.Qty 
1  1999  NA  NA 
2  2000 1997 1997 
3  2001 1998 1998 
4  2002 1997 1997 

В то время как я получил ожидаемый выход, метод выше очень неуклюжим. Есть ли лучший способ справиться с этим?

ответ

4

which.max хорошо работает с dplyr группировкой:

library(dplyr) 

Data %>% group_by(Order_Year) %>% 
    summarise(by.Yen = Ship_Year[which.max(Yen)], 
       by.Units = Ship_Year[which.max(Units)]) 

## # A tibble: 4 × 3 
## Order_Year by.Yen by.Units 
##  <dbl> <dbl> <dbl> 
## 1  1999  NA  NA 
## 2  2000 1997  1997 
## 3  2001 1998  1998 
## 4  2002 1997  1997 
2

Мы можем использовать data.table. Преобразуйте «data.frame» в «data.table» (setDT(Data)), сгруппированный по «Order_Year», мы получаем индекс максимального значения «Yen», «Units» с match, подмножество соответствующих значений «Ship_Year» на основе этого индекса, чтобы вернуть обобщенную выход

library(data.table) 
setDT(Data)[,.(by.Yen = Ship_Year[match(max(Yen), Yen)], 
     by.Units = Ship_Year[match(max(Units), Units)]) , Order_Year] 
# Order_Year by.Yen by.Units 
#1:  1999  NA  NA 
#2:  2000 1997  1997 
#3:  2001 1998  1998 
#4:  2002 1997  1997 

Если есть много столбцов, вместо того, чтобы делать это отдельно, можно указать столбцы, представляющие интерес в .SDcols, сгруппированных по «Order_Year», цикл через Подмножество Data.table (.SD), чтобы получить индекс максимального значения, unlist вывод list, подмножество «Ship_Year» на основе этого индекса, конвертировать в list (as.list) и установить имена столбцов 'by.Yen' и '' by.Units

setnames(setDT(Data)[, as.list(Ship_Year[unlist(lapply(.SD, 
    which.max))]), Order_Year, .SDcols = c("Yen", "Units")], 
       2:3, c("by.Yen", "by.Units"))[] 
# Order_Year by.Yen by.Units 
#1:  1999  NA  NA 
#2:  2000 1997  1997 
#3:  2001 1998  1998 
#4:  2002 1997  1997 
+0

@akrun - Большое спасибо за помощь. Не возражаете ли вы объяснить шаги? Я попытался выполнить ваш код, но не мог этого понять. – watchtower

+1

@watchtower Я обновил объяснение. Надеюсь, это поможет – akrun

+0

за вашу помощь. Я думал о том, чтобы пойти с ответом Алистира в качестве ответа из-за его простоты. Надеюсь, вы понимаете. – watchtower

2

с использованием базы R

a1 <- with(df1, 
      by(data = df1, 
       INDICES = Order_Year, 
       FUN  = function(x) list(Yen = x$Ship_Year[which.max(x$Yen)], 
             Units = x$Ship_Year[which.max(x$Units)]))) 

do.call("rbind", lapply(a1, function(x) data.frame(x))) 
#  Yen Units 
# 1999 NA NA 
# 2000 1997 1997 
# 2001 1998 1998 
# 2002 1997 1997 

данных:

df1 <- structure(list(Order_Year = c(1999, 1999, 1999, 1999, 1999, 1999, 1999, 
            2000, 2000, 2001, 2001, 2001, 2001, 2001, 
            2001, 2001, 2002, 2002, 2002, 2002), 
         Ship_Year = c(1997, 1998, 1999, 2000, 2001, 2002, NA, 
            1997, NA, 1997, 1998, 1999, 2000, 2001, 
            2002, NA, 1997, 1998, 1999, 2000), 
         Yen = c(202598.2, 0, 0, 0, 0, 0, 2365901.62, 627206.75998, 
           531087.43, 122167.02, 143855.55, 0, 0, 0, 0, 
           53650.389998, 17708416.3198, 98196.4, 31389, 0), 
         Units = c(37, 1, 8, 5, 8, 8, 730, 99, 91, 195, 259, 4, 
           1, 3, 3, 53, 3844, 142, 63, 27)), 
       .Names = c("Order_Year", "Ship_Year", "Yen", "Units"), 
       row.names = c(NA, 20L), 
       class = "data.frame") 
+0

Отредактированный ответ дает правильное решение. Предыдущая функция агрегата и выход из нее не будут работать все время, а совпадение результатов с вашими ожидаемыми результатами будет совпадающим. Надеюсь, что это поможет без какой-либо упаковки – Sathish

Смежные вопросы