我对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
我的目标是查看每个产品类别并比较每个客户十分位数的地板毛利率;如果较低十分位数的客户比较高十分位数的客户具有较高的楼层GM,则较高十分位数的客户应采用较低十分位数的地板GM。
我使用的逻辑按每个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()
增加我的数据集将阻碍性能,因为我在数百万个事务中扩展此解决方案。
感谢您的任何输入和/或其他参考!
不能保证数百万行的速度有多快(在我的慢速系统上,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 个十分位数 - 所以我认为它应该没问题(。