【问题标题】:Summing across rows conditional on groups with dplyr using select, group_by, and mutate使用 select、group_by 和 mutate 对具有 dplyr 的组进行跨行求和
【发布时间】:2020-04-04 05:05:00
【问题描述】:

问题:我正在计算一个汽车市场的总市场份额变量,该市场销售了 286 种不同的车型,总共售出了 501 辆汽车。该组份额仅基于汽车特性:cat= "compact", "midsize", "large" and yr=77,78,79,80,81,以及份额,一个小的双变量;市场上共有 15 组。

我找到的最接近的答案:由 community.rstudio 上的 mishabalyasin 撰写:“使用 tidyeval 计算按行总计和比例?” link to post on community.rstudio

应用 select-split-combine 的原理是我得到的最接近正确答案的是 15 个组 (15 x 3(cat, yr, s)):

df<- blp %>% 
  select(cat,yr,s) %>%
  group_by(cat,yr) %>% 
  summarise(group_share = sum(s))

#in my actual data, this is what fills by group share to get what I want, but this isn't the desired pipele-based answer
blp$group_share=0 #initializing the group_share, the 50th col
for(i in 1:501){
  for(j in 1:15){
    if((blp[i,31]==df[j,1])&&(blp[i,3]==df[j,2])){ #if(sameCat & sameYr){blpGS=dfGS}
      blp[i,50]=df[j,3]
      }
  }
}

这很好,但我知道这可以一举完成......希望从我上面描述的内容中可以清楚地看到这个想法。一个简单的修复可能是一个循环,并由 cat 和 yr 上的条件设置,这会有所帮助,但我真的想更好地使用 dplyr 处理数据,因此,沿着这条线获得流水线答案的任何见解都是太棒了。

网站示例:下面的示例不适用于我提供的代码,但这是我的数据的“外观”。份额是一个因素存在问题。

#45 obs, 3 cats, 5 yrs
cat=c( "compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large")
yr=c(77,78,79,80,81,77,78,79,80,81,77,78,79,80,81,77,78,79,80,81,77,78,79,80,81,77,78,79,80,81,77,78,79,80,81,77,78,79,80,81,77,78,79,80,81)
s=c(.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002)

blp=as.data.frame(cbind(unlist(lapply(cat,as.character,stringsAsFactors=FALSE)),as.numeric(yr),unlist(as.numeric(s))))

names(blp)<-c("cat","yr","s")
head(blp)

#note: one example of a group share would be summing the share from
(group_share.blp.large.81.s=(blp[cat== "large" &yr==81,]))

#works thanks to akrun: applying the code I provided for what leads to the 15 groups 
df <- blp %>% 
    select(cat,yr,s) %>%
    group_by(cat,yr) %>% 
    summarise(group_share = sum(as.numeric(as.character(s)))) 
#manually filling doesn't work, but this is what I'd want if I didn't want pipelining
blp$group_share=0
for(i in 1:45){
        if( ((blp[i,1])==(df[j,1])) && (as.numeric(blp[i,2])==as.numeric(df[j,2]))){ #if(sameCat & sameYr){blpGS=dfGS}
          blp[i,4]=df[j,3];
    }
  }

【问题讨论】:

  • @akrun 我删除了 s=c(...,) 末尾多余的 ','
  • 在最后一段代码中,您将创建一个以 data.frame 作为输出的列。另外,它是一个factorsummarise(group_share = sum(as.numeric(as.character(s))))
  • @akrun,复制了 15 个组的汇总代码。更好的是更有效地流水线,因此我使用适当的组总和创建 group_share 变量,您对此有什么想法吗?我的 for 循环会在我的实际数据集上执行此操作,我将在此处输入该循环的样子以作为示例
  • blp 共享数据的预期输出是什么?
  • 共有15组;其中一个子样本是 5 个“大”组的份额,即 (large, 77)=.003, (large, 78)= .0015, (large, 79)=.006, (large, 80)= .0003 , (大, 81)= .0006)

标签: r dplyr


【解决方案1】:

如果我正确理解了您的问题,这应该会有所帮助! 这里唯一的区别是,您可以使用 mutate 保留原始列并向它们添加聚合列,而不是使用将自动生成分组列和汇总列的汇总。

# Sample input
## 45 obs, 3 cats, 5 yrs
cat <- c( "compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large","compact","midsize","large")

yr <- c(77,78,79,80,81,77,78,79,80,81,77,78,79,80,81,77,78,79,80,81,77,78,79,80,81,77,78,79,80,81,77,78,79,80,81,77,78,79,80,81,77,78,79,80,81)

s <- c(.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002,.001,.0005,.002,.0001,.0002)

# Calculation
blp <- 
  data.frame(cat, yr, s, stringsAsFactors = FALSE) %>% # To create dataframe
  group_by(cat, yr) %>% # Grouping by category and year
  mutate(group_share = sum(s, na.rm = TRUE)) %>% # Calculating sum share per category/year 
  ungroup()

预期输出 Expected output

【讨论】:

  • 太好了,谢谢。鉴于我的真正问题是一个更大的问题,这可以完成工作,这样我就可以在那里注入 select() 以完美地工作。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-14
  • 1970-01-01
  • 2018-10-14
  • 2018-11-17
  • 2016-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多