【问题标题】:R - dplyr - How to mutate rows or divitions between rowsR - dplyr - 如何改变行或行之间的分区
【发布时间】:2018-07-30 02:23:42
【问题描述】:

我发现 dplyr 可以快速简单地聚合和汇总数据。但我不知道如何用 dplyr 解决以下问题。

鉴于这些数据框:

df_2017 <- data.frame(
  expand.grid(1:195,1:65,1:39), 
  value = sample(1:1000000,(195*65*39)),
  period = rep("2017",(195*65*39)),
   stringsAsFactors = F
)

df_2017 <- df_2017[sample(1:(195*65*39),450000),]

names(df_2017) <- c("company", "product", "acc_concept", "value", "period")

df_2017$company <- as.character(df_2017$company)
df_2017$product <- as.character(df_2017$product)
df_2017$acc_concept <- as.character(df_2017$acc_concept)
df_2017$value <- as.numeric(df_2017$value)

ratio_df <- data.frame(concept=c("numerator","numerator","numerator","denom", "denom", "denom","name"),
ratio1=c("1","","","4","","","Sales over Assets"),
ratio2=c("1","","","5","6","","Sales over Expenses A + B"), stringsAsFactors = F)

df_2017 中的列在哪里:

  • company = 这是一个分类变量,公司从 1 到 195
  • product = 这是一个分类,家用电器产品从 1 到 65。例如,1 可能等于熨斗,2 可能等于电视,等等
  • acc_concept = 这是一个分类变量,会计概念从 1 到 39。例如,1 等于“销售额”,2 等于“总费用”,3 等于退货”,4 等于“资产”等
  • value = 这是一个数值变量,USD 从 1 到 100.000.000
  • 期间 = 分类变量。永远是 2017 年

正如 expand.grid 所暗示的那样,company - product - acc_concept 的组合永远不会重复,但是,某些主题可能不会具有每个 company - product - acc_concept em> 组合。这就是代码行“df_2017

ratio_df 中的列在哪里:

  • Concept = 哪个 acc_concept 对应分子,哪个对应 分母,哪个是比率的名称
  • ratio1 = acc_concept 和 ratio1 的名称
  • ratio2 = acc_concept 和 ratio2 的名称

我想为每个公司的每个产品计算 acc_concept 之间的 2 个比率 (ratio_df)。

例如:

我从 ratio_df 中取第一个比率“acc_concepts”和“name”:

num_acc_concept   <- ratio_df[ratio_df$concept == "numerator", 2]
denom_acc_concept <- ratio_df[ratio_df$concept == "denom", 2]
ratio_name        <- ratio_df[ratio_df$concept == "name", 2]

然后我计算一个公司的一种产品的比率,只是为了表明你想要我想做的事情:

ratio1_value <- sum(df_2017[df_2017$company == 1 & df_2017$product == 1 & df_2017$acc_concept %in% num_acc_concept, 4]) / sum(df_2017[df_2017$company == 1 & df_2017$product == 1 & df_2017$acc_concept %in% denom_acc_concept, 4])

输出:

output <- data.frame(Company="1", Product="1", desc_ratio=ratio_name, ratio_value = ratio1_value, stringsAsFactors = F)

正如我之前所说,我想为每个公司的每个产品都这样做

输出的data.frame可能是这样的(比率不是真实的,因为我还没有进行计算)

company    product   desc_ratio              ratio_value
1           1        Sales over Assets           0.9303675
1           2        Sales over Assets           1.30
1           3        Sales over Assets           Nan
1           4        Sales over Assets           Inf
1           5        Sales over Assets           2.32
1           6        Sales over Assets           NA
.
.
.
1           1        Sales over Expenses A + B   3.25
.
.
.
2           1        Sales over Assets          0.256

等等……

  • 当比率为 0 / 0 时为 NaN
  • Inf 当比率为数字/0时
  • 当没有特定公司和产品的数据时不适用。

我希望这次我已经说清楚了:)

有没有办法用 dplyr 解决这个行问题?我应该使用 df_2017 进行变异吗?在这种情况下,哪种投射方式最好?

欢迎任何帮助!

【问题讨论】:

  • 你真的需要一个 450k 行的数据框来解释你的问题吗?您可以构建一个最小的可重现示例。
  • 完全一样,罗纳克。但是,我正在处理的数据框就是那个大小,所以我需要一个性能良好的解决方案;不仅仅是一个循环函数。
  • 当然,有时需要特异性和准确的表示,但通常不需要它们来解决需求或方法。通常情况下可以显着简化问题;这有许多有益的副作用,包括:(1)更具可读性,更有可能有人会通读您的整个问题以帮助您; (2) 更广泛的问题和解决方案,因此具有足够相似问题的其他人可以从中推断和充分学习; (3) 也许你可以把你学到的东西应用到其他地方。
  • 它已经被简化了。菲佛明白了。问题的核心在于标题。如果您想改变行,请阅读此内容。无论如何,我会在下一篇文章中考虑您的评论。

标签: r rows dplyr


【解决方案1】:

这是一种方法。最后,我对您所有记录的代码进行了计时。

首先创建一个函数来创建所有比率。请注意,此函数仅在 dplyr 代码中有用。

ratio <- function(data){
  result <- data.frame(desc_ratio = rep(NA, ncol(ratio_df) -1), ratio_value = rep(NA, ncol(ratio_df) -1))

  for(i in 2:ncol(ratio_df)){
    num   <- ratio_df[ratio_df$concept == "numerator", i]
    denom <- ratio_df[ratio_df$concept == "denom", i]
    result$desc_ratio[i-1] <- ratio_df[ratio_df$concept == "name", i]
    result$ratio_value[i-1] <- sum(ifelse(data$acc_concept %in% num, data$value, 0)) / sum(ifelse(data$acc_concept %in% denom, data$value, 0))
  }
  return(result)
}

使用 dplyr、tidyr 和 purrr 将所有内容放在一起。首先按数据分组,嵌套函数所需的数据,在嵌套数据上使用 mutate 运行函数。删除不需要的嵌套数据和 unnest 以获得您想要的输出。我把排序留给你。

library(dplyr)
library(purrr)
library(tidyr)
output <- df_2017 %>%
  group_by(company, product, period) %>% 
  nest() %>% 
  mutate(ratios = map(data, ratio)) %>% 
  select(-data) %>% 
  unnest

output

# A tibble: 25,350 x 5
   company product period desc_ratio                ratio_value
   <chr>   <chr>   <chr>  <chr>                           <dbl>
 1 103     2       2017   Sales over Assets               0.733
 2 103     2       2017   Sales over Expenses A + B       0.219
 3 26      26      2017   Sales over Assets               0.954
 4 26      26      2017   Sales over Expenses A + B       1.01 
 5 85      59      2017   Sales over Assets               4.14 
 6 85      59      2017   Sales over Expenses A + B       1.83 
 7 186     38      2017   Sales over Assets               7.85 
 8 186     38      2017   Sales over Expenses A + B       0.722
 9 51      25      2017   Sales over Assets               2.34 
10 51      25      2017   Sales over Expenses A + B       0.627
# ... with 25,340 more rows

system.time测量在我的机器上运行这段代码所花费的时间:

   user  system elapsed 
   6.75    0.00    6.81 

【讨论】:

  • 非常感谢您抽出宝贵时间,phiver。这正是我想要的。我从你那里学到了一些关键功能。
猜你喜欢
  • 2021-02-18
  • 2019-03-10
  • 2021-12-20
  • 2016-09-23
  • 2020-07-20
  • 1970-01-01
  • 1970-01-01
  • 2018-11-30
  • 1970-01-01
相关资源
最近更新 更多