1

我对 R 相当陌生,并且花了很长时间寻找更好的方法来解决下面的问题,但没有成功。我能够使用有效的for循环开发解决方案;但是,我违反了此 GitHub 教程中描述的规则,该教程讨论了编写循环时应避免的内容。

我正在处理销售数据。我的特定数据框包括产品类别(“CAT_NO”)、客户十分位数(“CUST_DECILE”)(客户被放入从 1 到 10 的十分位数组,其中 1 是“最佳”客户)和地板毛利率(“floorGM” ) 对于该产品类别,客户十分位组合。可能值得注意的是,并非每个产品类别都代表所有客户十分位(例如,样本类别“A”可能只有客户十分位 4、7 和 9。为简单起见,下面的可重现示例确保每个产品类别都有所有 10 个客户十分位)。我的数据集可以表示为:

    df <- data.frame(CAT_NO = c(rep(c("A"), times = 10), rep(c("B"), times = 10),
                        rep(c("C"), times = 10), rep(c("D"), times = 10))
             , CUST_DECILE = rep(c(1:10), times = 4), floorGM = runif(40, 0.2, 0.8))

    df

我的目标是查看每个产品类别并比较每个客户十分位的底毛利率;如果处于较低十分位的客户的 floorGM 高于处于较高十分位的客户,则较高十分位的客户应采用较低十分位的 floorGM。

我使用的逻辑按每个 CAT_NO 对数据进行了子集化,然后应用循环来比较该 CAT_NO 中每个 CUST_DECILE 的 floorGM。我的代码是:

    Product_Categories <- as.character(unique(df$CAT_NO))

    for(k in seq_along(Product_Categories)) {
      subdata <- subset(df, CAT_NO == Product_Categories[k])
      deciles <- sort(unique(subdata$CUST_DECILE))

      for(k in 2:length(deciles)) {
        if(subdata[subdata$CUST_DECILE == subdata$CUST_DECILE[k], "floorGM"< subdata[subdata$CUST_DECILE == subdata$CUST_DECILE[k-1], "floorGM"]) {
          subdata[subdata$CUST_DECILE == subdata$CUST_DECILE[k], "floorGM"] <- subdata[subdata$CUST_DECILE == subdata$CUST_DECILE[k-1], "floorGM"]
        }
       }
      if (!exists("temp")) {
         temp <- subdata
      } else {
         temp <- rbind(temp, subdata) 
      }
    }

虽然这可行,但我确信有一种更快的方法来执行此操作,特别是当rbind()我在数百万个事务中扩展此解决方案时,在循环期间增长我的数据集会阻碍性能。

感谢您的任何意见和/或其他参考!

4

1 回答 1

0

无法保证数百万行的速度有多快(在我的慢速系统上,40,000 行肯定需要一段时间),但这是一个解决方案(使用dplyr):

df<-group_by(df,CAT_NO)
df<-mutate(df, lag=lag(floorGM))
while (any(df$floorGM<df$lag,na.rm=T)) {
  df<-mutate(df, floorGM=ifelse(!is.na(lag),ifelse(floorGM<lag,lag,floorGM),floorGM))
  df<-mutate(df, lag=lag(floorGM))
}

while循环基本上floorGM使整个类别的数字冒泡。

(实际上,想想看,它不应该需要很多循环——因为每个类别只能有 10 个十分位数——所以我认为应该没问题)。

于 2018-08-09T12:49:04.007 回答