【问题标题】:Improve speed of r 'for loop'提高 r 'for loop' 的速度
【发布时间】:2020-01-01 23:58:06
【问题描述】:

我是 r 的新手,希望在加快以下“for 循环”代码方面得到一些帮助。

代码旨在根据 ROE 列按部门和月份为每一行创建一个百分位排名

我在 r 中复制一个 excel 电子表格,该电子表格使用 PERCENTRANK.INC 函数,并且 r 代码需要精确复制它。我已经研究了 r 中的选项来匹配这个函数、dplyr 方法等,但除了下面的循环之外,似乎没有一个能完全复制结果。

问题的症结在于,循环需要 30 分钟才能为数据框创建所有百分位等级(输入数据框中的总行数约为 90,000)。有没有人有任何提示来加快下面的循环?我已经阅读了该站点上的许多类似问题/答案,并尝试了许多方法,例如对循环顶部附近的子集语句进行调整,但只成功地进行了有限的改进。

输入文件“ROE_Quintiles”的详细信息

  • 它由历史股票 ROE 值组成,按月计算
  • 关键列是:
  • Merge_Var4,这是股票所属的 Sector 的组合 和月份,例如汽车和零部件Dec-03
  • ROE2 是代码获得百分位排名的列(按部门和月份)
  • Merge_Var3 是股票、它所属的行业和 月,例如Ford Motor CoAutomobiles & ComponentsDec-03
  • ROE2_percrank 是在结束时输出的百分等级 每次迭代

非常感谢您的帮助。

冲锋枪

我的r代码如下所示:

# Create dataframe to append to at the end of each iteration
ROE_Quintiles3 <- data.frame("Merge_Var3" = c('Temp'), "ROE2_percrank" = c(0.5))
End <- nrow(ROE_Quintiles)
system.time({
  for(i in 1:End) {
    Row <- ROE_Quintiles[i,]
    Row_Value <- subset(Row, select=c(ROE2))
    Row_Value2 <- mean(Row_Value$ROE2) # PercentRankArgument Value

    Row_Sector_Month <- subset(Row, select=c(Merge_Var4))
    Row_Sector_Month_Values <- subset(ROE_Quintiles, Merge_Var4==Row_Sector_Month$Merge_Var4, select=c(ROE2))

    # Filter Number to values less than the row value
    NumberLessThanArgument = subset(Row_Sector_Month_Values, ROE2 < Row_Value2)

    # Filter Number to values greater than or equal to the row value
    NumberGreaterThanOrEqualArgument = subset(Row_Sector_Month_Values, ROE2 >= Row_Value2)

    # RankLower = the count of Numbers less than row value, and is used later for 
    # interpolation of ranks
    RankLower <- nrow(NumberLessThanArgument)

    # NumberLower = the largest Number < row value, used for interpolation
    NumberLower <- ifelse(RankLower==0, Row_Value2, max(NumberLessThanArgument))

    # NumberUpper = the smallest Number >= row value, used for interpolation
    NumberUpper = min(NumberGreaterThanOrEqualArgument) 

    # PercentRankArgumentRank =  the rank of row value over the Number table, which is 
    # just RankLower + 1. This is the same rank as NumberUpper in the Number table itself.
    PercentRankArgumentRank = RankLower + 1

    # InterpolationFraction = fraction that row value is from NumberLower to NumberUpper  
    InterpolationFraction <- ifelse(RankLower==0, 0, (Row_Value2 - NumberLower)/(NumberUpper - NumberLower))

    # Calculate the interpolated rank
    RankInterpolated = max(1, RankLower + InterpolationFraction * (PercentRankArgumentRank - RankLower))

    # Get the count of Numbers
    NumberCount = nrow(Row_Sector_Month_Values)

    # Final PercentRank is (RankInterpolated - 1)/(NumberCount - 1)
    PercentRankOutput = (RankInterpolated - 1)/(NumberCount - 1)

    # Append to create main dataframe
    Row_Output <- subset(Row, select=c(Merge_Var3))
    Row_Output$ROE2_percrank <- PercentRankOutput
    ROE_Quintiles3 <- rbind(ROE_Quintiles3, Row_Output)
  }
})
ROE_Quintiles3 <- subset(ROE_Quintiles3, Merge_Var3 != 'Temp')

【问题讨论】:

  • 你可能根本不需要for loop。如果您能提供ROE_Quintiles 的小示例数据,并说明您的预期结果,将更便于其他人提供帮助。
  • 一个肮脏的技巧是简单地使用像 doParallel 这样的包进行多处理
  • 这太宽泛了,主要是要求重写。您能否尝试一个包含数据的最小示例?

标签: r performance for-loop


【解决方案1】:

由于大多数问题“我的 R 循环很慢”,问题通常与循环内的对象增长有关。当我在你的循环中看到ROE_Quintiles3 &lt;- rbind(ROE_Quintiles3, Row_Output) 时,我想这就是问题所在。

请参阅https://privefl.github.io/blog/why-loops-are-slow-in-r/ 以了解我向您指出的问题和几个解决方案(提示:我会选择类似于gen_list() 的东西)。

【讨论】:

  • 感谢您的帮助,最终让我找到了解决方案。我在每次迭代的底部创建了一个列表,例如dfs[[i]]
  • 很好,请随时在此处添加您自己的答案。
猜你喜欢
  • 1970-01-01
  • 2020-08-31
  • 1970-01-01
  • 2019-08-01
  • 2014-06-02
  • 1970-01-01
  • 1970-01-01
  • 2020-07-20
  • 1970-01-01
相关资源
最近更新 更多