2014-12-24 2 views
3

Мои данные выглядит следующим образом:Расчет на несколько столбцов и совокупных значений множества факторов уровня

df <- data.frame(Price=seq(1, 1.5, 0.1), 
       Sales=seq(6, 1, -1), 
       Quality=c('A','A','A','B','B','B'), 
       Brand=c('F','P','P','P','F','F')) 

Иногда мне нужно делать какие-то сложные расчеты по нескольким столбцам и агрегатные значения многократным уровня факторов. Для упрощенного примера, если я хочу, чтобы получить Revenue (= Price * Sales) распределение внутри каждого Quality и раскола по Brand, я бы

df$Revenue <- df$Price*df$Sales 

RevSumByQ <- aggregate(Revenue~Quality, data=df, sum) 
colnames(RevSumByQ)[2] <- "RevSumByQ" 
df <- merge(df, RevSumByQ) 

RevSumWithinQByB <- aggregate(RevSumByQ~Brand, data=df, sum) 
colnames(RevSumWithinQByB)[2] <- "RevSumWithinQByB" 
df <- merge(df, RevSumWithinQByB) 

df$RevDistWithinQByB = df$RevSumByQ/df$RevSumWithinQByB 
df 

    Brand Quality Price Sales Revenue RevSumByQ RevSumWithinQByB RevDistWithinQByB 
1  F  A 1.0  6  6.0  16.3    32.7   0.4984709 
2  F  B 1.4  2  2.8  8.2    32.7   0.2507645 
3  F  B 1.5  1  1.5  8.2    32.7   0.2507645 
4  P  A 1.1  5  5.5  16.3    40.8   0.3995098 
5  P  A 1.2  4  4.8  16.3    40.8   0.3995098 
6  P  B 1.3  3  3.9  8.2    40.8   0.2009804 

Если шоу в сюжете:

require(ggplot2) 
ggplot(data=df, aes(x=Brand, y=RevDistWithinQByB, fill=Quality)) + geom_bar(stat='identity') 

enter image description here

Там должно лучше всего рисовать этот сюжет, но мой главный интерес здесь - получить структуру данных с менее промежуточными результатами (Revenue, RevSumByQ, RevSumWithinQByB). Я вижу структуру в моем подходе, поэтому я задаюсь вопросом, есть ли более элегантные решения или есть некоторые функции, которые облегчают эту задачу.

ответ

3

Вы можете попробовать dplyr

res <- df %>% 
     group_by(Quality) %>% 
     mutate(Revenue= Price*Sales,RevSumByQ=sum(Revenue)) %>% 
     group_by(Brand) %>% 
     mutate(RevSumWithinQByB= sum(RevSumByQ), 
      RevDistWithinQByB= RevSumByQ/RevSumWithinQByB) 
+1

Вы могли бы упростить свой первый мутировать: 'мутировать (RevSumByQ = сумма (цена * продажи))%>% ', так как выручка не нужна после –

+0

@docendodiscimus Да, я подумал об этом, но тогда подумал, может быть, OP нужна эта колонка для чего-то ... :-) – akrun

+0

Хорошо, я понимаю, что вы имеете в виду. –

2

Вот data.table подход:

library(data.table) 
setDT(df) 
## 
df[,Revenue:=Price*Sales][ 
    ,RevSumByQ:=sum(Revenue), 
    by=Quality][ 
    ,RevSumWithinQByB:=sum(RevSumByQ), 
    by=Brand][ 
     ,RevDistWithinQByB:=RevSumByQ/RevSumWithinQByB] 

И хотя я обычно не делаю это сам, вы можете позвонить ggplot код внутри одного и того же объекта :

df[,Revenue:=Price*Sales][ 
    ,RevSumByQ:=sum(Revenue), 
    by=Quality][ 
    ,RevSumWithinQByB:=sum(RevSumByQ), 
    by=Brand][ 
     ,RevDistWithinQByB:=RevSumByQ/RevSumWithinQByB][ 
     ,{print(ggplot(
      data=.SD, 
      aes(x=Brand, 
       y=RevDistWithinQByB, 
       fill=Quality))+ 
      geom_bar(stat="identity"))}] 
2

В основном (как указано в @arun) вам не нужны слияния здесь, и вы можете делать все, используя ave из базы R. Также кажется, что будет трудно пропустить первые два этапа агрегации. Хотя вы можете пропустить последний расчет и поместить его прямо в ggplot. Что-то вроде:

df$Revenue <- df$Price*df$Sales 
df$RevSumByQ <- with(df, ave(Revenue, Quality, FUN = sum)) 
df$RevSumWithinQByB <- with(df, ave(RevSumByQ, Brand, FUN = sum)) 

require(ggplot2) 
ggplot(data = df, 
     aes(x = Brand, y = RevSumByQ/RevSumWithinQByB, fill = Quality)) + 
     geom_bar(stat = 'identity') 

enter image description here

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