【问题标题】:Alternative to calculating Elasticity using For Loop使用 For 循环计算弹性的替代方法
【发布时间】:2015-07-23 14:33:08
【问题描述】:

我编写了一段代码来计算一些 200k 产品的弹性。弹性正在计算中,但已经超过 15 小时,并且该过程仍在运行。我看到正在创建新对象。在不使用 for 循环的情况下,是否有更快的替代方法?

下面是我的代码:

    sku_list <- unique(transact_data4$productId)
    elasticity_values <- data.frame()

    for (i in 1:length(sku_list)){
     test_sku <- subset(transact_data4, productId==sku_list[i])
     m1 <- lm(formula=sales~price, data= test_sku)
     coeffs <- as.data.frame(m1[[1]])
     gradient<- coeffs[2,1]
     gradient_final <- ifelse(is.na(gradient), -1, gradient)
     mean_price <- mean(test_sku$price)
     mean_sales <- mean(test_sku$sales)
     elasticity <- gradient_final*mean_price/mean_sales
     sku_elasticity <- cbind(sku_list[i],elasticity)
     elasticity_values <- rbind(elasticity_values,sku_elasticity)
    }
colnames(elasticity_values)[colnames(elasticity_values)=="V1"] <- "productId" 

这是一个示例数据集:

transact_data <- data.frame(productId=c('A', 'A','A', 'A','A', 'A','B', 'B','B', 'B','B', 'B'),
                  price=c(10, 10.5, 11, 12,10, 9,
                    10, 11, 13, 11,12.5, 11),
                    sales =c(100,93,90,85,99,110,101,95,80,103,82,102), stringsAsFactors=FALSE)

结果:

  productId         elasticity
1         A -0.913344887348354
2         B  -1.03051724343462

有没有更快的方法可以在不使用 for 循环的情况下实现这一点? 显然,由于样本较小(只有 2 个 productId),它运行得很快。 但我试图为超过 20 万个 productId 运行它。

谢谢。

【问题讨论】:

    标签: r for-loop


    【解决方案1】:

    代码

    library(dplyr)
    
    transact_data %>% group_by(productId) %>%
       do(mod = lm(sales ~ price, data = .), 
          mean.price = mean(.$price), 
          mean.sales = mean(.$sales)) %>%
       summarise(productId  = productId,
                 elasticity = ifelse(is.na(coef(mod)[2]), -1, coef(mod)[2]) * 
                              mean.price / mean.sales)
    
    #   productId elasticity
    # 1         A -0.9133449
    # 2         B -1.0305172
    

    说明

    使用library(dplyr),您可以方便地进行分组计算:

    • %&gt;% 是链接运算符,通过将左侧参数作为右侧函数的第一个参数输入,使代码更具可读性
    • group_by 告诉您要按列分组的下一个命令 productId
    • do 用于计算模型和所需的平均值,在do 中,您使用点. 来指代整个data.frame
    • summarise最后总结了你的计算,通过计算弹性

    更多信息请查看vignette("introduction")

    顺便说一句,您的代码很慢也就不足为奇了,因为您使用循环并在循环中增加数据。查看http://www.burns-stat.com/pages/Tutor/R_inferno.pdf 获取有关常见陷阱的一些教程。

    【讨论】:

    • 你是救生员。也感谢您提供解释。
    • 只需要补充一点,这种方法简直太棒了!它实际上显示了完成百分比。谢谢。
    • 不客气!只是出于好奇,计算最后持续了多久?在这里尝试了一个包含 1e7 行和 10000 个不同产品 ID 的示例数据集,只花了大约一分钟。那你是什么时候?
    • For Loop - 超过 15 个小时,我不得不杀死。使用管道和做 - 22 分钟。太棒了。
    【解决方案2】:

    如何优化代码

    1) 函数 apply、sapply、... 比 for 循环快得多

    2) rbind 和 cbind 在处理大数据时会很慢。我建议您使用已经足够多的列和行创建您的大 data.frame(空),然后填充它。

    玩得开心!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-09
      • 1970-01-01
      • 2020-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多