文本分割-隐马尔可夫模型

/**
 文字分词 隐马尔可夫模型
 共4种状态S B M E
 AMap 为状态转移概率矩阵 4*4,表示从{S B M E}到{S B M E}的概率
 BMap 为当前字属于某种状态{S B M E}的概率
 * */
//有限状态
const S=['S','B','Mn','E']

const mekflink={
  empty:{S:1/16},
  AMap:{
    'S-S':1000,
    'S-B':1000,
    'E-B':1000,
    'E-S':1000,
  },
  BMap:{},
  AMapGl:{},
  BMapGl:{},
  add(text){
    if(text.length>1){
      for(let i=0;i<text.length;i++){
        if(i===0){
          this.push(text[i],'B')
        }else if(i===text.length-1){
          this.push(text[i],'E')
          if(text.length>2){
            this.pushState('M'+(i-1),'E')
          }else{
            this.pushState('B','E')
          }
        }else if(i===1){
          this.push(text[i],'M'+i)
          this.pushState('B','M'+i)
        }else{
          this.push(text[i],'M'+i)
          this.pushState('M'+(i-1),'M'+i)
        }
      }
    }else{
      this.push(text,'S')
    }
  },
  pushState(t0N,t1N){
    const AMap=this.AMap;
    const key=t0N+'-'+t1N
    if(!AMap[key]){
      AMap[key]=0
    }
    AMap[key]++;
  },
  push(key,state){
    const BMap=this.BMap
    if(!BMap[key]){
      BMap[key]={}
    }
    if(!BMap[key][state]){
      BMap[key][state]=0
    }
    BMap[key][state]++;
  },
  //生成模型
  makeGl() {
    const AMap=this.AMap;
    const BMap=this.BMap;
    const AMapGl=this.AMapGl;
    const BMapGl=this.BMapGl;
    //统计A
    const AMapT={}
    for(let key in AMap){
      const [t0,t1]=key.split('-')
      if(!AMapT[t0]){
        AMapT[t0]=0;
      }
      AMapT[t0]=AMapT[t0]+AMap[key];
    }
    for(let key in AMap){
      const [t0,t1]=key.split('-')
      AMapGl[key]=this.chu(AMap[key],AMapT[t0])
    }
    //统计B
    for(let key in BMap){
      let t=0;
      for(let k in BMap[key]){
        t=t+BMap[key][k]
      }
      const obj=Object.create(this.empty)
      for(let k in BMap[key]){
        obj[k]=this.chu(BMap[key][k],t)
      }
      BMapGl[key]=obj;
    }
    return {
      AMapGl,BMapGl
    }
  },
  chu(p1,p2){
    return p1/p2;
  },
  exex(p1,p2){
    return p1*p2;
  },
  isBig(p1,p2){
    return p1>p2
  },
  getT1Arr(t0Obj,BObj){
    const AMapGl=this.AMapGl;
    const t1Obj={};
    let glAll=0;
    for(let t0 in t0Obj){
      const link=t0Obj[t0]
      for(let k in AMapGl){
        const arr=k.split('-')
        if(t0===arr[0]&&BObj[arr[1]]){
          const gl=this.exex(link.gl,this.exex(AMapGl[k],BObj[arr[1]]))
          if(gl>0){
            if(!t1Obj[arr[1]]){
              glAll=glAll+gl;
              t1Obj[arr[1]]={
                gl:gl,
                data:link.data+'-'+arr[1]
              }
            }else if(this.isBig(gl,t1Obj[arr[1]].gl)){
              glAll=glAll+gl-t1Obj[arr[1]].gl;
              t1Obj[arr[1]]={
                gl:gl,
                data:link.data+'-'+arr[1]
              }
            }
          }

        }
      }
    }
    for(let k in t1Obj){
      const gl=parseInt(t1Obj[k].gl/glAll*100);
      t1Obj[k].gl=gl
      if(gl===0){
        delete t1Obj[k]
      }
    }
    return t1Obj;
  },
  solve(text){
    const AMapGl=this.AMapGl;
    const BMapGl=this.BMapGl;
    console.log('状态转移概率',AMapGl)
    console.log('特征统计概率',BMapGl)
    //马尔可夫链条
    //获取当前状态可能的下一个状态
    let t0Obj={
      'S':{
        gl:1,data:'S'
      },
      'B':{
        gl:1,data:'B'
      }
    }

    for(let i=1;i<text.length;i++){
      t0Obj=this.getT1Arr(t0Obj,BMapGl[text[i]]||Object.create(this.empty))
    }
    const lArr=[]
    const cache={}
    for(let k in t0Obj){
      const dstr=t0Obj[k].data.replace(/[\d-]/g,'')
      const data=[]
      let start,end;
      for(let i=0;i<text.length;i++){
        if(dstr[i]==='B'){
          start=i;
        }else if(dstr[i]==='E'){
          end=i;
          data.push(text.substring(start,end));
        }
        // else if(dstr[i]==='S'){
        //   data.push(text[i]);
        // }
      }
      t0Obj[k].data=data
      const key=JSON.stringify(data)
      if(typeof cache[key]!=='undefined'){
        if(t0Obj[k].gl>lArr[cache[key]].gl){
          lArr[cache[key]]=t0Obj[k]
        }
      }else{
        cache[key]=lArr.length;
        lArr.push(t0Obj[k])
      }
    }
    if(lArr.length>1){
      lArr.sort(function (p1,p2) {
        return p2.gl-p1.gl;
      })
    }
    return lArr;
  }
}

module.exports=mekflink;

const arrH=['1ec66668876666666']
arrH.forEach(function (text) {
  mekflink.add(text)
})
mekflink.makeGl()
const text='1ec666688766666661ec66668876666666211ec6666887666666621';

console.log(mekflink.solve(text))

  

上一篇:vue中使用高德地图


下一篇:vue调用高德地图:vue-amap