一、思维概述
这个算法是来源于毕设、本来是打算采用遗传算法优化安踏一个最佳优惠策略的算法,但是后来因为商业合作的原因并没有用在安踏上。就将此算法用到了另外设计的一个生鲜上层的系统上。应用的场景是,通过商品的属性、用户行为等信息通过定时任务执行遗传算法来计算出一个商家利益最大化的每日推荐商品列表、站在每个用户角度角度的猜你喜欢列表(根据用户的行为特征不同)每个用户的列表都是不同的。
遗传算法顾名思义就是运用了生物上的达尔文进化论的思想,我们需要想明白的是达尔文进化轮中有群体、群体中有个体、个体中会进行交叉遗传、根据适者生存的法则能够存活下来的个体就能够进行下一代的遗传进化,代代相叠,最终剩下的群体就是我们想要的最优群体。上面的这句话可以看成是算法的一个核心,此算法的实现也是围绕着对上面各个概念的解释而展开的,我们需要明白在系统中下列的各个名词所代表的是什么:
1、个体:在每日推荐列表中个体就是若干个(取决于推荐列表中需要的商品个数)不同的商品组成的一组商品,这组商品我们可以称之为个体,每一个商品对应的二级制编码我们可以看做是个体的一个基因。
2、群体:若干个个体组成的就是我们的一个群体,初始的群体是随机生成的,后边每一代的群体都是进过前一代交叉遗传后进过自然选择得到的。
3、交叉遗传:生物中我们知道两个个体之间可以进行交叉变异,在这里的交叉变异就是指两个个体的基因(01字符串)进行交换,交换之后根据一定的概率再进行随机变异。如果交换或是变异之后的某段基因映射不到我们一个个体就需要进行一定的处理否则的话就会造成最后的基因序列翻译的得不到商品。
4、生存法则:自然界中有自然界的法则可以将好的个体留下来,这里的规则需要我们自己定义——在某一代中那一个体是最符合商家的最大利益的——那么商家的最大利益应该如何设计、如何反应出来,这是算法最核心的东西,也最能体现算法的好坏。在下面会有专门的小结来介绍算法的接评估维度。这里面就是根据定义好的维度来计算一组商品的权重,我们最终选择权重排名最大的一群个体,将这群个体单做下一代进化的基础。
二、算法设计
算法是基于遗传算法的电商智能推荐算法,算法的运算结果为用户 小程序端的“猜你喜欢”、“今日推荐”两个模块的商品信息列表。整个算法的数据主要 来源于数据库设计—DBMS 实现模块中的三张相关表。智能算法的整体运作流程是:
(1)通过 PC 管理端设置智能算法的定时任务;
(2)从数据库读取数据并写入内存中,供智能算法使用;
(3)运算智能算法并输出结果,将结果保存在持久层;
(4)用户调用接口从持久层获取相应商品信息列表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xtumrZg2-1636383109373)(F:\typroa\aimages\image-20211108215438950.png)]
根据算法的实现以及数据库表的实现,设计了智能算法中单个商品信息的数据结构 —IntelligentDataSource,在算法中也可以将值称之为基因组,一个商品就可以称为一 个基因组,基因组是通过将 goodId 字段翻译成一个固定长度的 01 字符串,这个固定长度 的大小取决所有商品中 goodId 的最大值。
public class IntelligentDataSource {
private int uid;
private int goodId;
private int synRelationValues;
private int synVisitValue;
private double profit;
private double disparityPrice;
private double giveIntegral;
private int sales;
private int stock;
private boolean isGood;
private boolean isNew;
private boolean isBenefit;
}
HashMap<String,IndividualValue> groups;
其中的 synRelationValues、synVisitValue 是结合点赞收藏、浏览的次数与触发这 些事件的时间经过一个自定义算法计算得到的,目的是希望将时间的因素考虑在内,通过 这两个参数的值来更大程度反映商品最近一段时间的受欢迎程度,这其中是借鉴了 JVM 中 垃圾回收算法中有关衰减均值的思想,算法的数学描述为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cYk9v2wO-1636383109377)(F:\typroa\aimages\image-20211108215733956.png)]
x 的取值为:(当前时间-触发点时间),在计算中时间的取值为 1970 年 1 月 1 日 (UTC/GMT 的午夜)开始到某个时间点的小时数。计算式中 W 的取值是一个重要的因子, 他的取值范围在[0.9,0.98]为宜,在算法中的默认值是 0.92。Z、P 的取值都是可调节的 在算法中取默认值 95、5。Z、W、P 的取值调节的是评价及浏览量的先后时间在计算商品 推荐值比重时的影响。
根据 goodId 生成基因组基因的代码实现为:
public String geneOrderProduct(int index){
StringBuilder geneOrder = new StringBuilder();
while (index > 0){
geneOrder = geneOrder.append(index % 2);
index /= 2;
};
while (geneOrder.length()<geneLeng){
geneOrder.append(0);
}
return geneOrder.reverse().toString();
}
关于基因序列生成这一块的算法是存在很大的优化空间的,当初由于时间紧急就没有做过多的考虑,大家感兴趣的可以尝试进行优化。
算法中种群个体是由多个不重复的商品组成,个体的基因就是多个基因组的逐一拼接。 算法的实现逻辑是模拟生物遗传中自然选择的思想,来做优胜略汰,通过多轮的选择找到 一个局部最优解。首先我们构建一个用来模拟自然环境的函数,这个函数可以计算出个体 (商品列表)价值在这里我们将之为推荐值,在淘汰的过程中只留下群体中推荐值高的个 体,再让这些个体进行后代繁殖,逐代筛选直到得到一个相对最优解。后代繁殖的过程中 还存在交叉变异、算法中是通过采用“01”编码来模拟实现,将每一个体赋予一个由 01 组成的编号,编号模拟交叉变异,个体中的属性用来计算评估推荐值。
每日推荐算法的具体设计考虑三个维度:欢迎度 f (rela,vist) 、放映浏览量与实际销售 的实销度f(sale,visit)、库存量f(stocks)、还有一个商家用来设定的是否推荐、是否新 品等的自由维度,在描述中所用到的变量均来自于 IntelligentDataSource 实体,变量名 为相应属性名的简写:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-80HBsS4E-1636383109379)(F:\typroa\aimages\image-20211108220043839.png)]
将 x 的一组织收敛在[0,10],其中的 X 代表的是 x 所属的整个数组:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8BPOVqJt-1636383109382)(F:\typroa\aimages\image-20211108220124521.png)]
猜你喜欢的算法设计与自我推荐相似,在猜你喜欢的算法中权重最大的一个维度是个 人利益最大化,以及用户个人对一个商品可能的喜爱程度。本文对猜你喜欢部分的算法设 计不再做详细描述。
三、智能算法的实现
(1)系统全局变量,在本系统旨对于关键参数都设计为全局变量的形式从而提高代 码的可配置性。算法采用的遗传策略并不是固定遗传多少代而是设置经过多少代生物种群 的最大推荐值仍旧不变就自动结束算法,默认找到了相对最优解。
static final boolean sourceFlag = false;
static int geneCount = 120;
static final int geneLeng =Integer.toBinaryString(geneCount).length();
static final int individualCount = 36;
static final double evoluRate = 0.5;
public static double relasVisiAverage = 0;
public static double stockAverage = 0;
public static double visiMax = 0;
public static double visiMin = Double.MAX_VALUE;
static double saleMax =0;
static double saleMin =Double.MAX_VALUE;
public static double giveMax = 0;
public static double giveMin = Double.MIN_VALUE;
static int userCount = 100;
作为突变基因
public double mutation = 0.01;
public int currentEvolutionIndex = 0;
public static boolean ifShowInitData = false;
public static boolean ifShowAnalysisProcess = false;
public static boolean isIfShowResult = true;
public static int recordGranularity = 500;
static HashMap<Integer,HashMap<Integer,Integer[]>> userGoodsValues = new
HashMap<Integer, HashMap<Integer, Integer[]>>();
static DecimalFormat df2 =new java.text.DecimalFormat("#.00");
static DecimalFormat df3 =new java.text.DecimalFormat("#.000");
static Random random = new Random();
public static HashMap<String, GoodsGene> genes = new HashMap<>();
(2)根据基因库信息产生种群个体
public void productIndividual(){
String geneSequences = "";
for (int i = 0; i < individualCount; i++) {
IndividualValue individualValue = new IndividualValue();
StringBuilder indiGeneString = new StringBuilder();
while (individualValue.getGeneSet().size()<indiviGeneCoutRec){
geneSequences = geneOrderProduct(random.nextInt(geneCount));
if (individualValue.getGeneSet().add(geneSequences)){
indiGeneString.append(geneSequences);
individualValue.getIndividuals().put(geneSequences,genes.get(geneSequences));
}
}
individualValue.setGeneSequences(indiGeneString.toString());
individuals.put(individualValue.getGeneSequences(),individualValue);
}
}
(3)设置基因发生突变的位置
public String geneMutation(String geneOrder){
char[] geneTemp = geneOrder.toCharArray();
int geneIndex = random.nextInt(geneTemp.length);
if (geneTemp[geneIndex]=='1'){
geneTemp[geneIndex] = '0';
}else{
geneTemp[geneIndex]= '1';
}
String tempResult = new String(geneTemp);
String geneSequences = "";
if(!genes.containsKey(tempResult)){
do {
geneSequences = geneOrderProduct(random.nextInt(geneCount));
}while (!genes.containsKey(geneSequences));
return geneSequences;
}
return tempResult;
}
(4)XY 染色体的交叉变异,在此产生的突变策略是随机突变,如果最终产生的突变基 因不再基因库中则视为无效基因,重新在基因库中随机选取一个基因作为此突变基因 的最终基因。
public IndividualValue[] geneCross(String[] crossGenes,int indiviGeneCout){
String[] manGeneArray = new String[indiviGeneCout];
String[] womanGeneArray = new String[indiviGeneCout];
String geneTemp = "";
IndividualValue manIndividual = new IndividualValue();
IndividualValue womanIndividual = new IndividualValue();
StringBuilder manTemp = new StringBuilder();
StringBuilder womanTemp = new StringBuilder();
IndividualValue[] result = new IndividualValue[2];
for (int i = 0; i <indiviGeneCout; i++) {
manGeneArray[i] = crossGenes[0].substring(i*geneLeng,(i+1)*geneLeng);
womanGeneArray[i] = crossGenes[1].substring(i*geneLeng,(i+1)*geneLeng);
}
for (int i = 0; i < indiviGeneCout; i++) {
do {
if(random.nextBoolean()){
geneTemp = manGeneArray[i];
manGeneArray [i] = womanGeneArray[i];
womanGeneArray[i] = geneTemp;
}
if(random.nextDouble()<=mutation){
if (random.nextBoolean()){
womanGeneArray[i] = geneMutation(womanGeneArray[i]);
}else {
manGeneArray[i] = geneMutation(manGeneArray[i]);
}
}
}while (womanIndividual.getGeneSet().contains(womanGeneArray[i])||
manIndividual.getGeneSet().contains(manGeneArray[i]));
womanIndividual.getGeneSet().add(womanGeneArray[i]);
manIndividual.getGeneSet().add(manGeneArray[i]);
womanIndividual.getIndividuals().put(womanGeneArray[i],genes.get(womanGeneArray[i]));
manIndividual.getIndividuals().put(manGeneArray[i],genes.get(manGeneArray[i]));
};
for (int i = 0; i < manGeneArray.length; i++) {
womanTemp.append(womanGeneArray[i]);
manTemp.append(manGeneArray[i]);
}
womanIndividual.setGeneSequences(womanTemp.toString());
manIndividual.setGeneSequences(manTemp.toString());
result[0] = manIndividual;result[1] = womanIndividual;
return result;
}
四、代码结构介绍与详细代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4i2n6bnq-1636383109384)(F:\typroa\aimages\image-20211108221610690.png)]
另个遗传算法模块需要用到的公共部分代码,这里进行一定程度的抽象,来实现代码的一个共用与封装。本以上也是想要引入模板方法的设计模式,但是做的并不成功。
@Slf4j
@AllArgsConstructor
public abstract class GenticAlgorithmAbstract {
static final boolean sourceFlag = false;
static int geneCount = 120;
static final int geneLeng =Integer.toBinaryString(geneCount).length();
static final int individualCount = 36;
static final double evoluRate = 0.5;
public static double relasVisiAverage = 0;
public static double stockAverage = 0;
public static double visiMax = 0;
public static double visiMin = Double.MAX_VALUE;
static double saleMax =0;
static double saleMin =Double.MAX_VALUE;
public static double giveMax = 0;
public static double giveMin = Double.MIN_VALUE;
static int userCount = 100;
public static double mutation = 0.01;
public static int currentEvolutionIndex = 0;
public static boolean ifShowInitData = false;
public static boolean ifShowAnalysisProcess = true;
public static boolean isIfShowResult = true;
public static int recordGranularity = 100;
static HashMap<Integer,HashMap<Integer,Integer[]>> userGoodsValues = new HashMap<Integer, HashMap<Integer, Integer[]>>();
static DecimalFormat df2 =new java.text.DecimalFormat("#.00");
static DecimalFormat df3 =new java.text.DecimalFormat("#.000");
static Random random = new Random();
public static HashMap<String, GoodsGene> genes = new HashMap<>();
public static HashMap<String, YxStoreProduct> allGoodLists = new HashMap<>();
public static YxStoreProductService yxStoreProductService;
public static YxStoreProductRelationService yxStoreProductRelationService;
public static RedisUtils redisUtils;
public static void productGene(){
if(sourceFlag){
databaseProduct();return;
}
randomProduct();
if (ifShowInitData){
log.info("智能分析算法基因为:");
showGenes();
log.info("商品用户行为数据为:");
showUserGoodsMes();
}
log.info("计算基因库特征值");
gensAverage();
}
public void productIndividual(HashMap<String, IndividualValue> individuals,int indiviGeneCout) {
String geneSequences = "";
for (int i = 0; i < individualCount; i++) {
IndividualValue individualValue = new IndividualValue();
StringBuilder indiGeneString = new StringBuilder();
while (individualValue.getGeneSet().size()<indiviGeneCout){
geneSequences = geneOrderProduct(random.nextInt(geneCount));
if (individualValue.getGeneSet().add(geneSequences)){
indiGeneString.append(geneSequences);
individualValue.getIndividuals().put(geneSequences,genes.get(geneSequences));
}
}
individualValue.setGeneSequences(indiGeneString.toString());
individuals.put(individualValue.getGeneSequences(),individualValue);
if(ifShowInitData)showIndividual(i,individualValue);
}
}
public static void randomProduct(){
for (int i = 0; i < geneCount; i++) {
GoodsGene goodsGene = new GoodsGene();
goodsGene.setGene(geneOrderProduct(i));
goodsGene.setGoodId(i+1);
goodsGene.setSynRelationValues(Double.parseDouble(df2.format(99*random.nextDouble()+1)));
goodsGene.setSynVisitValue(Double.parseDouble(df2.format(99*random.nextDouble()+1)));
goodsGene.setProfit(Double.parseDouble(df2.format(19*random.nextDouble()+1)));
goodsGene.setDisparityPrice(Double.parseDouble(df2.format(9*random.nextDouble()+1)));
goodsGene.setGiveIntegral(Double.parseDouble(df2.format(4*random.nextDouble()+1)));
goodsGene.setSales(random.nextInt(999)+1);
goodsGene.setStock(random.nextInt(199)+1);
goodsGene.setGood(random.nextBoolean());
goodsGene.setNew(random.nextBoolean());
goodsGene.setBenefit(random.nextBoolean());
genes.put(goodsGene.getGene(), goodsGene);
}
log.info("开始生成商品用户行为数据");
randomUserGoods();
}
public static void randomUserGoods(){
int goodsCount = 0;
for (int i =1; i <=userCount; i++) {
HashMap<Integer,Integer[]> goodsMesTemp = new HashMap<>();
int goodId = 0 ;
goodsCount = random.nextInt(10)+1;
for(int j = 1; j <=goodsCount; j++){
Integer [] values = new Integer[3];
values[0] = random.nextInt(2);
values[1] = random.nextInt(2);
values[2] = random.nextInt(50);
goodId = random.nextInt(geneCount)+1;
if (!goodsMesTemp.containsKey(goodId)){
goodsMesTemp.put(goodId,values);
}
}
userGoodsValues.put(i,goodsMesTemp);
}
}
public static void databaseProduct(){
YxStoreProductQueryCriteria criteria = new YxStoreProductQueryCriteria();
List<YxStoreProduct> yxStoreProductList = yxStoreProductService.queryAll(criteria);
log.info("智能算法查出的用户总数量为:"+yxStoreProductList.size());
YxStoreProductRelationQueryCriteria criteria1 = new YxStoreProductRelationQueryCriteria();
List<YxStoreProductRelation> relations = yxStoreProductRelationService.queryAll(criteria1);
log.info("用户商品行为信息的数据量为:"+relations.size());
HashMap<Integer,YxStoreProduct> goodsMap = new HashMap<>();
if(yxStoreProductList!=null&&yxStoreProductList.size() >0){
for (YxStoreProduct item:yxStoreProductList){
GoodsGene goodsGene = new GoodsGene();
goodsGene.setGene(geneOrderProduct(item.getId()));
goodsGene.setGoodId(item.getId());
goodsGene.setSynRelationValues(0);
goodsGene.setSynVisitValue(0);
goodsGene.setProfit(item.getPrice().doubleValue()-item.getCost().doubleValue());
goodsGene.setDisparityPrice(item.getOtPrice().doubleValue()-item.getPrice().doubleValue());
goodsGene.setGiveIntegral(item.getGiveIntegral().doubleValue());
goodsGene.setSales(item.getSales());
goodsGene.setStock(item.getStock());
goodsGene.setGood(item.getIsGood()==1?true:false);
goodsGene.setNew(item.getIsNew()==1?true:false);
goodsGene.setBenefit(item.getIsBenefit()==1?true:false);
genes.put(goodsGene.getGene(),goodsGene);
goodsMap.put(item.getId(),item);
}
redisUtils.set("goodsMap",goodsMap);
goodsMap = null;
}
if(relations!=null&&relations.size()>0){
for (YxStoreProductRelation item:relations){
}
}
}
public static String geneOrderProduct(int index){
StringBuilder geneOrder = new StringBuilder();
while (index > 0){
geneOrder = geneOrder.append(index % 2);
index /= 2;
};
while (geneOrder.length()<geneLeng){
geneOrder.append(0);
}
return geneOrder.reverse().toString();
}
public static void gensAverage(){
for(String key:genes.keySet()){
GoodsGene temp = genes.get(key);
relasVisiAverage = relasVisiAverage+temp.getSynVisitValue()+temp.getSynRelationValues();
stockAverage = stockAverage+ temp.getStock();
if(temp.getSynVisitValue()>visiMax){
visiMax = temp.getSynVisitValue();
}
if(temp.getSynVisitValue()<visiMin){
visiMin = temp.getSynVisitValue();
}
if(temp.getSales()>saleMax){
saleMax = temp.getSales();
}
if(temp.getSales()<saleMin){
saleMin = temp.getSales();
}
if(temp.getGiveIntegral()>giveMax){
giveMax = temp.getGiveIntegral();
}
if(temp.getGiveIntegral()<giveMin){
giveMin = temp.getGiveIntegral();
}
}
relasVisiAverage = Double.parseDouble(df2.format(relasVisiAverage/(2*genes.size())));
stockAverage = Double.parseDouble(df2.format(stockAverage/genes.size()));
}
public void individualsRecValue(HashMap<String, IndividualValue> individuals){
IndividualValue individualValue = null;
for (String key:individuals.keySet()){
individualValue = individuals.get(key);
individualValue.setRecommendValue(Double.parseDouble(df3.format(recValue(individualValue))));
}
}
public HashMap<String, IndividualValue> productNextGroup(ArrayList<IndividualValue> betterIndividuals,int indiviGeneCout){
int betterIndivLength = betterIndividuals.size()-1;
HashMap<String, IndividualValue> currentIndividuals = new HashMap<>();
while (currentIndividuals.size()<individualCount){
String[] crossGenes = new String[2];
crossGenes[0] = betterIndividuals.get(random.nextInt(betterIndivLength)).getGeneSequences();
do {
crossGenes[1] = betterIndividuals.get(random.nextInt(betterIndivLength)).getGeneSequences();
}while (crossGenes[0].equals(crossGenes[1]));
IndividualValue[] individualValues = geneCross(crossGenes,indiviGeneCout);
currentIndividuals.put(individualValues[0].getGeneSequences(),individualValues[0]);
currentIndividuals.put(individualValues[1].getGeneSequences(),individualValues[1]);
}
return currentIndividuals;
}
public IndividualValue[] geneCross(String[] crossGenes,int indiviGeneCout){
String[] manGeneArray = new String[indiviGeneCout];
String[] womanGeneArray = new String[indiviGeneCout];
String geneTemp = "";
IndividualValue manIndividual = new IndividualValue();
IndividualValue womanIndividual = new IndividualValue();
StringBuilder manTemp = new StringBuilder();
StringBuilder womanTemp = new StringBuilder();
IndividualValue[] result = new IndividualValue[2];
for (int i = 0; i <indiviGeneCout; i++) {
manGeneArray[i] = crossGenes[0].substring(i*geneLeng,(i+1)*geneLeng);
womanGeneArray[i] = crossGenes[1].substring(i*geneLeng,(i+1)*geneLeng);
}
for (int i = 0; i < indiviGeneCout; i++) {
do {
if(random.nextBoolean()){
geneTemp = manGeneArray[i];
manGeneArray [i] = womanGeneArray[i];
womanGeneArray[i] = geneTemp;
}
if(random.nextDouble()<=mutation){
if (random.nextBoolean()){
womanGeneArray[i] = geneMutation(womanGeneArray[i]);
}else {
manGeneArray[i] = geneMutation(manGeneArray[i]);
}
}
}while (womanIndividual.getGeneSet().contains(womanGeneArray[i])||
manIndividual.getGeneSet().contains(manGeneArray[i]));
womanIndividual.getGeneSet().add(womanGeneArray[i]);
manIndividual.getGeneSet().add(manGeneArray[i]);
womanIndividual.getIndividuals().put(womanGeneArray[i],genes.get(womanGeneArray[i]));
manIndividual.getIndividuals().put(manGeneArray[i],genes.get(manGeneArray[i]));
};
for (int i = 0; i < manGeneArray.length; i++) {
womanTemp.append(womanGeneArray[i]);
manTemp.append(manGeneArray[i]);
}
womanIndividual.setGeneSequences(womanTemp.toString());
manIndividual.setGeneSequences(manTemp.toString());
result[0] = manIndividual;result[1] = womanIndividual;
return result;
}
public String geneMutation(String geneOrder){
char[] geneTemp = geneOrder.toCharArray();
int geneIndex = random.nextInt(geneTemp.length);
geneTemp[geneIndex]=geneTemp[geneIndex]=='1'?'0':'1';
String tempResult = new String(geneTemp);
String geneSequences = "";
if(!genes.containsKey(tempResult)){
do {
geneSequences = geneOrderProduct(random.nextInt(geneCount));
}while (!genes.containsKey(geneSequences));
return geneSequences;
}return tempResult;
}
public static void showUserGoodsMes(){
for (Integer key:userGoodsValues.keySet()){
System.out.println("User-"+key+"的商品行为数据如下:");
for (Integer item:userGoodsValues.get(key).keySet()){
Integer[] temp = userGoodsValues.get(key).get(item);
System.out.println("goodId:"+item+";点赞:"+temp[0]+";收藏:"+temp[1]+";浏览量:"+temp[2]);
temp = null;
}
}
}
public static void showGenes(){
for (String key: genes.keySet()){
System.out.println(genes.get(key).toString());
}
}
public static void showIndividual(int index,IndividualValue individualValue){
System.out.println("第 "+index+" 个体,种群个体的基因序列为:"+individualValue.getGeneSet());
}
public abstract double recValue(IndividualValue individualValue);
public abstract boolean filtrate(ArrayList<IndividualValue> betterIndividuals, ArrayList<EvolutionRecord>
evolutionRecords,HashMap<String, IndividualValue> individuals);
}
-
GeneticAlorithmGueYouLick
@Slf4j
public class GeneticAlorithmGueYouLick extends GenticAlgorithmAbstract {
private int indiviGeneCout = 10;
public ArrayList<EvolutionRecord> evolutionRecords = new ArrayList<>();
private HashMap<String, IndividualValue> individuals = new HashMap<>();
private final boolean sourceUserFlag = false;
public int userVisitMax;
public int userVisitMin;
public final double isNewUnit = 5/indiviGeneCout;
public final double isBenefitUnit = 20/indiviGeneCout;
public Integer currentUserId = 0;
public final int intergenerationCount =500;
public double beforeMax = 0;
public int beforeMaxIntergeneration = 0;
private HashMap<String, HashSet<String>> youLikeGoods = new HashMap<>();
@Test
public void run(){
log.info("开始生产猜你喜欢种群个体~");
productIndividual(individuals,indiviGeneCout);
evolution();
}
public void showResult(){
log.info("猜你喜欢模块分析的结果为:");
for (String key:youLikeGoods.keySet()){
System.out.println("用户:"+key+";推荐商品组合为:"+youLikeGoods.get(key));
}
}
public void evolution(){
for (Integer key:userGoodsValues.keySet()){
currentUserId = key;
userVisitMax = 0;userVisitMin = Integer.MAX_VALUE;
for (Integer item:userGoodsValues.get(key).keySet()){
if (userGoodsValues.get(key).get(item)[2]<userVisitMin){
userVisitMin = userGoodsValues.get(key).get(item)[2];
}
if (userGoodsValues.get(key).get(item)[2]>userVisitMax){
userVisitMax = userGoodsValues.get(key).get(item)[2];
}
}
if(ifShowAnalysisProcess){
System.out.println("现在正在用户编号为:"+key+"用户进行分析");
}
boolean envolutionFlag = true;
currentEvolutionIndex = 0;
beforeMaxIntergeneration = 0;
beforeMax = 0;
do {
ArrayList<IndividualValue> betterIndividuals = new ArrayList<>();
++currentEvolutionIndex;
individualsRecValue(individuals);
envolutionFlag = filtrate(betterIndividuals,evolutionRecords,individuals);
individuals = productNextGroup(betterIndividuals,indiviGeneCout);
betterIndividuals = null;
}while (envolutionFlag);
}
}
@Override
public double recValue(IndividualValue individualValue) {
double behaviorValue = 0,isNewValue = 0,giveInteValue = 0,isBenefitValue =0;
for (String key:individualValue.getGeneSet()){
GoodsGene curDataSource = genes.get(key);
if (curDataSource==null){
System.out.println("*****报错为空,基因序列非法");
}
isNewValue = isNewValue +(curDataSource.isNew()==true?isBenefitUnit:0);
giveInteValue = giveInteValue + 4*(curDataSource.getGiveIntegral()-giveMin)/(giveMax-giveMin)+1;
isBenefitValue = isBenefitValue + (curDataSource.isBenefit()==true?isBenefitUnit:0);
behaviorValue = behaviorValue + behaviorValueCal(curDataSource.getGoodId());
}
giveInteValue = giveInteValue/indiviGeneCout;
behaviorValue = behaviorValue/indiviGeneCout;
return behaviorValue+isNewValue+giveInteValue+isBenefitValue;
}
@Override
public boolean filtrate(ArrayList<IndividualValue> betterIndividuals, ArrayList<EvolutionRecord>
evolutionRecords,HashMap<String, IndividualValue> individuals){
double averageTemp =0.0;
int betterCount = (int) (individualCount*evoluRate);
List<IndividualValue> temp = new ArrayList<>();
for (String key:individuals.keySet()){
temp.add(individuals.get(key));
}
Collections.sort(temp);
for (int i = 0; i < betterCount; i++) {
betterIndividuals.add(temp.get(i));
averageTemp =averageTemp+temp.get(i).getRecommendValue() ;
}
if ((currentEvolutionIndex%recordGranularity==0||currentEvolutionIndex==1)&&ifShowAnalysisProcess){
EvolutionRecord evolutionRecord = new EvolutionRecord(currentEvolutionIndex);
evolutionRecord.setArts(Double.parseDouble(df3.format(averageTemp/betterCount)),
temp.get(0).getRecommendValue(),temp.get(temp.size()-1).getRecommendValue());
System.out.println(evolutionRecord.toString());
evolutionRecord = null;
}
if (temp.get(0).getRecommendValue()>beforeMax){
beforeMax = temp.get(0).getRecommendValue();
beforeMaxIntergeneration = currentEvolutionIndex;
}
if (currentEvolutionIndex-beforeMaxIntergeneration>intergenerationCount){
youLikeGoods.put(currentUserId+"",temp.get(0).getGeneSet());
if(ifShowAnalysisProcess){
System.out.println("在第"+currentEvolutionIndex+"中找到了用户"+currentUserId+"的推荐最大值:"+temp.get(0));
}
return false;
}
return true;
}
public double behaviorValueCal(Integer goodsId){
double visitValue = 0;
Integer[] temp = userGoodsValues.get(currentUserId).get(goodsId);
double visitRuler = 0;
if (temp == null) return 0;
if((userVisitMin - userVisitMax)==0)return 40;
if (visitRuler>=9){
visitValue = 40;
}else if (visitRuler>=6){
visitValue = 30;
}else if (visitRuler>=4){
visitValue = 20;
}else if (visitRuler>=2){
visitValue = 10;
}else if (visitRuler>0){
visitValue = 5;
}else{
visitValue =0;
}
return visitValue+(temp[0]==1?10:0)+(temp[1]==1?20:0);
}
}
@Slf4j
public class GeneticAlorithmRecommend extends GenticAlgorithmAbstract {
private int indiviGeneCout = 5;
public double synProfitMax = 0;
public double synProfitMin = Double.MAX_VALUE;
public int evolutionCount = 1000000;
public final int intergenerationCount =2000;
public double beforeMax = 0;
public int beforeMaxIntergeneration = 0;
public ArrayList<EvolutionRecord> evolutionRecords = new ArrayList<>();
private HashMap<String, IndividualValue> individuals = new HashMap<>();
private IndividualValue individualValueBest = new IndividualValue();
@Test
public void run(){
log.info("开始生产猜你喜欢种群个体~");
productIndividual(individuals,indiviGeneCout);
evolution();
}
public void showResult(){
log.info("系统推荐算法分析的结果为:");
System.out.println(individualValueBest.toString());
}
public void evolution(){
boolean envolutionFlag = true;
currentEvolutionIndex = 0;
do{
ArrayList<IndividualValue> betterIndividuals = new ArrayList<>();
++currentEvolutionIndex;
calProfitTemp();
individualsRecValue(individuals);
envolutionFlag = filtrate(betterIndividuals,evolutionRecords,individuals);
individuals = productNextGroup(betterIndividuals,indiviGeneCout);
betterIndividuals = null;
}while (envolutionFlag);
}
public void calProfitTemp(){
double visiTemp = 0;
double saleTemp = 0;
GoodsGene temp = null;
for (String key:genes.keySet()){
temp = genes.get(key);
visiTemp = 9*(temp.getSynVisitValue()-visiMin)/(visiMax-visiMin)+1;
saleTemp = 9*(temp.getSales()-saleMin)/(saleMax-saleMin)+1;
temp.setSynProfitTemp((saleTemp/visiTemp)*(saleTemp+visiTemp)*temp.getProfit());
if(temp.getSynProfitTemp()>synProfitMax){
synProfitMax = temp.getSynProfitTemp();
}
if(temp.getSynProfitTemp()<synProfitMin){
synProfitMin = temp.getSynProfitTemp();
}
}
synProfitMin = Double.parseDouble(df2.format(synProfitMin));
synProfitMax = Double.parseDouble(df2.format(synProfitMax));
}
@Override
public double recValue(IndividualValue individualValue){
double relaVisi = 0,stock = 0,prof = 0,free = 0;
double profis[] = new double[indiviGeneCout];
for (String key:individualValue.getIndividuals().keySet()){
GoodsGene curDataSource = individualValue.getIndividuals().get(key);
relaVisi =relaVisi+curDataSource.getSynRelationValues()+curDataSource.getSynVisitValue();
free = free + (curDataSource.isGood()==true?6:0)+(curDataSource.isNew()==true?2:0);
stock = stock+calStock(curDataSource.getStock());
prof = prof + 39*(curDataSource.getSynProfitTemp()-synProfitMin)/(synProfitMax-synProfitMin)+1;
curDataSource = null;
}
relaVisi = 0.65*(relaVisi/indiviGeneCout)-relasVisiAverage;
stock = stock/indiviGeneCout;
prof = prof/indiviGeneCout;
return relaVisi+stock+prof+free;
}
@Override
public boolean filtrate(ArrayList<IndividualValue> betterIndividuals, ArrayList<EvolutionRecord>
evolutionRecords,HashMap<String, IndividualValue> individuals){
double averageTemp =0.0;
int betterCount = (int) (individualCount*evoluRate);
List<IndividualValue> temp = new ArrayList<>();
for (String key:individuals.keySet()){
temp.add(individuals.get(key));
}
Collections.sort(temp);
for (int i = 0; i < betterCount; i++) {
betterIndividuals.add(temp.get(i));
averageTemp =averageTemp+temp.get(i).getRecommendValue() ;
}
if ((currentEvolutionIndex%recordGranularity==0||currentEvolutionIndex==1)&&ifShowAnalysisProcess){
EvolutionRecord evolutionRecord = new EvolutionRecord(currentEvolutionIndex);
evolutionRecord.setArts(Double.parseDouble(df3.format(averageTemp/betterCount)),
temp.get(0).getRecommendValue(),temp.get(temp.size()-1).getRecommendValue());
System.out.println(evolutionRecord.toString());
evolutionRecord = null;
}
if (temp.get(0).getRecommendValue()>beforeMax){
beforeMax = temp.get(0).getRecommendValue();
beforeMaxIntergeneration = currentEvolutionIndex;
}
if (currentEvolutionIndex-beforeMaxIntergeneration>intergenerationCount){
individualValueBest = temp.get(0);
if (ifShowAnalysisProcess){
System.out.println("在第"+currentEvolutionIndex+"中找到推荐最大值:"+temp.get(0));
}
return false;
}
return true;
}
private double calStock(double stock){
double flag = stock/stockAverage;
double stockValue = 0;
if(flag>2){
return 30;
}else if(flag>1.5){
return 20;
}else if(flag>1){
return 10;
}else{
return 0;
}
}
}
五、尚需优化的方向
优化项 | 原因与策略 | 是否已优化 |
---|
程序执行在执行的过程中会越来越慢甚至到最后的时候还会出现卡死或是内存溢出的情况 | 在迭代的过程中产生了大量的对象,虽然JVM有垃圾自动回收的能力但是仍然会存在回收不及时或是有些对象存在强引用,所以造成内存浪费。需要做的是及时的将对象置null。进行内存释放 | 90% | 配置将较多,后续配置耦合性太高 | 现在是初步提取做来作为了常量,实际上可进一步进行抽取为配置文件——>配置文件搭配配置中心使用或是将配置项持久化到数据库在通过图形界面进行展示动态的配置 | 20% | 代码结构总体较为凌乱,需要进一步进行抽象 | 可以参照模板方法的设计模式进行分装与公共部分代码共用 | 65% | 得带进化的过程比较复杂 | 借用函数式编程的流处理的思想与方法处理进化迭代部分的代码 | 0% | 算法完整之后代码量应该在1000行左右,不同情况下的日志项难以控制 | 结合配置项与日志处理函数进行不同粒度日志的打印,不同环境下不同内容的日志打印 | 30% | 定时任务执行时,目前的代码运行不起来 | 初步排查是因为static、abstract等机加载时机先后顺序引起的问题;此部分的解决需要对算法的代码结构进行重构,并且处理好两种模式——自动生成、数据库读取的切换 | 0% |
目前想到的就只有这些,感觉还是挺有意思的,后边也会抽出时间将这个算法的代码进行一次彻底的重构。
|