如何发放优惠券的一个小项目

需求分析:

公司里有很多客户,客户之所以不继续用我们的产品了,是因为他账户余额是负的,所以,为了重新赢回这些客户,公司决定发放优惠券cover掉客户账户的负余额。

具体细节:

  1. 只有8元,80元,200元的优惠券
  2. 发放给一个客户的优惠券总张数不能超过15张
  3. 要既能cover掉客户的负余额,又要保证发放给客户的优惠券张数最少
  4. 发放给客户的总金额-客户的亏损额不能大于8,且越小越好。(不能送太多便宜了)

思路:

开始把这个问题理解为线性规划,觉得不好解,遂放弃。之后想用一大堆的逻辑判断来解决这个问题,总能解出来了吧(实在是烦 写一堆的 if else,最后都被绕晕了,遂放弃)。最后的思路,先列出所有送券的组合,然后把亏损和送券金额相加(亏损是负值),得到gap最小的券组合,就可以搞定了。有点暴力破解法的味道。

下面是代码:

## 检查是否安装 sqldf 和 reshape2  这两个包,若没有则安装,若已安装,则跳过。
if(!'sqldf' %in% installed.packages()[,1]) (install.packages('sqldf'))
if(!'reshape2' %in% installed.packages()[,1]) (install.packages('reshape2'))
## 如何发优惠券
## step 1
####################### 构造一个数据框,里面包含所有可能的送券组合################################
x=data.frame(x=rep(0:15,1)) # 表示 200的券 的张数
y=data.frame(y=rep(0:15,1))  # 表示 80的券 的张数
z=data.frame(z=rep(0:15,1))  # 表示 8的券 的张数
library(sqldf)
# 做笛卡尔积
df <- sqldf('select * from x,y,z')
df$coupon_sum <-apply(df,1,sum)
df$amt_sum <- df$x*200+df$y*80+df$z*8
#过滤掉 sum>15的 组合
 df <- sqldf('select * from df where coupon_sum<=15 order by amt_sum asc')
 ## step 2
#######################################################
### 下面是给出任意一个 亏损 比如 loss=-987,则 fun2(-987) 返回出用200,80,8各几张,能获得gap最小
fun2 <- function(i){
    if(i< -3000){
    return(data.frame(loss=i,x=15,y=0,z=0,coupon_sum=15,amt_sum=3000,gap=3000+i))
    } else {
        df$gap <- i+df$amt_sum
        df_positive <- sqldf('select * from df where gap>=0')
        res <- sqldf('select * from df 
                     where gap in (select gap from df_positive order by gap limit 1)
                     order by gap,coupon_sum
                     limit 1')
        return(cbind(loss=i,res))
    }
}
 ## step 3
# #### 建一个 函数 fun3,其中调用了fun2
fun3 <- function(original.df){
    final.res <- data.frame()
    for(m in 1:length(original.df[,1])){
        row.res <- cbind(original.df[m,],fun2(original.df[m,2]))
        final.res <- rbind(final.res,row.res)
    } 
    return(final.res)
}

#  n <- length(test.df[,2])
#  res <- lapply(test.df[2:100,2],fun2)
#  do.call(rbind,res)
 
 
 
## step 4
# 构造一个测试数据集 test.df  进行测试
test.df <- data.frame(phone_num=rep(1:200,1),loss=abs(rnorm(200))*(-2000))
final_res <- fun3(dd)

## step 5 
## 变换数据形式 宽表变窄表,然后写出结果数据集
library(reshape2)
final <- melt(final_res[,c(1,3:5)],id=c('phone_num'))
## 重新排序一下
final <- sqldf('select * from final order by phone_num')
# final
# write.csv() 

for(i in 1:length(dd[,2])){
    print(paste0('round ',i))
    print(fun2(dd[i,2]))
}

总结:

  • 由于代码是发给别人用的,但是经常别人有些包没安装,用不了。所以学会了一句code,搞定。
## 检查是否安装 sqldf 和 reshape2  这两个包,若没有则安装,若已安装,则跳过。
if(!'sqldf' %in% installed.packages()[,1]) (install.packages('sqldf'))
if(!'reshape2' %in% installed.packages()[,1]) (install.packages('reshape2'))
原文地址:https://www.cnblogs.com/litao1105/p/5039138.html