日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Learning to Rank 中Listwise关于ListNet算法讲解及实现

發布時間:2025/3/21 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Learning to Rank 中Listwise关于ListNet算法讲解及实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
 【學習排序】 Learning to Rank 中Listwise關于ListNet算法講解及實現 ???????????





    目錄(?)[+]

  • 一 基于列的學習排序Listwise介紹
  • 二 ListNet算法介紹
  • 三 ListNet算法Java實現
  • 四 總結
  • ? ? 前一篇文章"Learning to Rank中Pointwise關于PRank算法源碼實現"講述了基于點的學習排序PRank算法的實現.該篇文章主要講述Listwise Approach和基于神經網絡的ListNet算法及Java實現.包括:
    ? ? 1.基于列的學習排序(Listwise)介紹
    ? ? 2.ListNet算法介紹
    ? ? 3.ListNet算法Java實現

    ? ? LTR中單文檔方法是將訓練集里每一個文檔當做一個訓練實例,文檔對方法是將同一個查詢的搜索結果里任意兩個文檔對作為一個訓練實例,文檔列方法是將一個查詢里的所有搜索結果列表作為一個訓練實例.?

    一. 基于列的學習排序(Listwise)介紹

    ? ? Listwise方法將一個查詢對應的所有搜索結果評分作為一個實例,訓練得到一個最優的評分函數.在給出如下數據集中:(數據集介紹詳見上一篇文章)

    =============================================================================== 0 qid:10 1:0.000000 2:0.000000 3:0.000000 ... 45:0.000000 46:0.000000 #docid = 1 qid:10 1:0.031310 2:0.666667 3:0.500000 ... 45:0.448276 46:0.000000 #docid = 1 qid:10 1:0.078682 2:0.166667 3:0.500000 ... 45:1.000000 46:0.000000 #docid = 0 qid:50 1:0.044248 2:0.400000 3:0.333333 ... 45:0.622951 46:0.000000 #docid =? 2 qid:50 1:0.764381 2:0.200000 3:0.000000 ... 45:0.252874 46:0.000000 #docid = 1 qid:50 1:0.693584 2:0.000000 3:0.000000 ... 45:0.275862 46:0.000000 #docid = =============================================================================== ? ? 基于列的學習排序(Listwise Approach)是將qid=10對應的所有查詢文檔作為一個實例進行訓練,即一個查詢及其對應的所有搜索結果評分作為一個實例進行訓練;訓練得到一個最后評分函數F后,test測試集中一個新的查詢,函數F對每一個文檔進行打分,之后按照得分順序由高到低排序即是對應搜索的結果.
    ? ? 下面介紹一種基于搜索結果排序組合的概率分布情況來訓練.如下圖:
    ? ? 參考《這就是搜索引擎:核心技術詳解 by:張俊林》第5章


    ? ? 用戶輸入查詢Q1,假設返回的搜索結果集合里包含A、B和C三個文檔,搜索引擎要對搜索結果排序,而3個文檔順序共有6種排列組合方式:ABC、ACB、BAC、BCA、CAB和CBA,每種排列組合都是一種可能的搜索結果排序方法.
    ? ? 我們可以把函數g設想成最優評分函數(人工打分),對查詢Q1來說:文檔A得6分,文檔B得4分,文檔C得3分;我們的任務是找到一個函數,使得其對Q1的搜索結果打分順序盡可能的接近標準函數g.其中函數f和h就是實際的評分函數,通過比較兩個概率之間的KL距離,發現f比h更接近假想的最優函數g.故選擇函數f為搜索的評分函數.
    ? ? Listwise主要的算法包括:AdaRank、SVM-MAP、ListNet、LambdaMART等.

    二. ListNet算法介紹

    ? ? Pointwise學習排序是將訓練集中的每個文檔看作一個樣本獲取Rank函數,主要解決辦法是把分類問題轉換為單個文檔的分類和回歸問題,如PRank.
    ? ? Pairwise學習排序(下篇介紹)是將同一個查詢中不同的相關標注的兩個文檔看作一個樣本,主要解決思想是把Rank問題轉換為二值分類問題,如RankNet.
    ? ? Listwise學習排序是將整個文檔序列看作一個樣本,主要是通過直接優化信息檢索的評價方法和定義損失函數兩種方法實現.ListNet算法將Luce模型引入到了排序學習方法中來表示文檔序列,同時大多數基于神經網絡的排序學習算法都是基于Luce模型(Luce模型就是將序列的任意一種排序方式表示成一個概率值)來表示序列的排序方式的.

    ? ? ListNet算法參考:
    ? ?《Learning to Rank: From Pairwise Approach to Listwise Approach
    ? ?《基于神經網絡的Listwise排序學習方法的研究》 By:林原


    ? ? 通過該算法步驟解釋如下:
    ? ? 1.首先輸入訓練集train.txt數據.{x,y}表示查詢號對應的樣本文檔,包括標注等級Label=y(46維微軟數據集共3個等級:0-不相關,1-部分相關,2-全部相關),x表示對應的特征和特征值,需要注意的是x(m)表示m個qid數,每個x(m)中有多個樣本文檔.
    ? ? 2.初始化操作.迭代次數T(設置為30次)和Learning rate(ita可以為0.003、0.001、0.03、0.01等),同時初始化權重w.
    ? ? 3.兩層循環操作.第一層是循環迭代次數:for t = 1 to T do;第二層循環是迭代查詢總數(qid總數):for i = 1 to m do.
    ? ? 4.計算該行分數用當前權重w.注意權重w[46]是一維數組,分別對應46個特征值,同時f(w) = w * x.

    ? ?5.計算梯度向量delta_w(46個維度).其中計算公式如下:

    ? ? 其中n(i)表示查詢號qid=i對應的總文檔數,j表示qid=i的當前文檔.x的右上方下標表示對應的qid數,右下方下標表示對應的文檔標號.而P是計算概率的函數,如下:

    ? ? 它表示S1排第一、S2排第二且S3排第三的概率值.這就是使用Luce模型使一個序列的排序方式表示成一個單一的概率值.實際過程中,我們通過使用exp()函數來表示fai.主要保證其值為正、遞增.
    ? ? 但N!的時間復雜度很顯然效率很低,所以提出了Top-K概率來解決,即用前k項的排列概率來近似原有的整個序列的概率,通過降低精準度來換取運行時間.
    ? ? Top-K概率公式如下:

    ? ? 在下面的Java代碼實現中我采用的是Top-1,即獲取當前行文檔排第一的概率值.
    ? ? 6.循環更新權重w.
    ? ? 7.最后輸出w[46]權重,訓練過程結束.通過該模型可以進行測試預測排序,test.txt通過該權重進行w*x打分,再進行從高到低排序即可.

    ? ? PS:這僅僅是我結合兩篇論文后的個人理解,如果有錯誤或不足之處,歡迎探討!同時感謝我的同學XP和MT,我們一起探討和分享才理解了一些ListNet算法及代碼.

    三. ListNet算法Java實現

    ? ? (PS:該部分代碼非常感謝我的組長XP和MT,他們在整個編程路上對我幫助是一生的.同時自己也希望以后工作中能找到更多的老師和摯友指導我前行~)
    ? ? 代碼中有詳細的注釋,按照每個步驟完成.左圖是主函數,它主要包括:讀取文件并解析數據、寫數據、學習排序模型和打分預測,右圖是學習排序的核心算法.

    ??
    ? ? 代碼如下:
    [java] view plaincopyprint?
  • package?listNet_xiuzhang;??
  • ??
  • import?java.io.BufferedReader;??
  • import?java.io.File;??
  • import?java.io.FileInputStream;??
  • import?java.io.FileWriter;??
  • import?java.io.InputStreamReader;??
  • ??
  • public?class?listNet?{??
  • ??????
  • ????//文件總行數(標記數)??
  • ????private?static?int?sumLabel;?????????????????????
  • ????//特征值?46個?(標號1-46)??
  • ????private?static?double?feature[][]?=?new?double[100000][48];??????????????????
  • ????//特征值權重?46個?(標號1-46)??
  • ????private?static?double?weight?[]?=?new?double[48];??
  • ????//相關度?其值有0-2三個級別?從1開始記錄??
  • ????private?static?int?label?[]?=?new?int[1000000];??
  • ????//查詢id?從1開始記錄??
  • ????private?static?int?qid?[]?=?new?int[1000000];??
  • ????//每個Qid的doc數量??
  • ????private?static?int?doc_ofQid[]?=?new?int[100000];???
  • ??
  • ????private?static?int?ITER_NUM=30;?????//迭代次數??
  • ????private?static?int?weidu=46;????????//特征數??
  • ????private?static?int?qid_Num=0;???????//Qid數量??
  • ????private?static?int?tempQid=-1;??????//臨時Qid數??
  • ????private?static?int?tempDoc=0;???????//臨時doc數??
  • ??????
  • ????/**???
  • ?????*?函數功能?讀取文件?
  • ?????*?參數?String?filePath?文件路徑?
  • ?????*/??
  • ????public?static?void?ReadTxtFile(String?filePath)?{??
  • ????????try?{??
  • ????????????String?encoding="GBK";??
  • ????????????File?file=new?File(filePath);??
  • ????????????if(file.isFile()?&&?file.exists())?{?//判斷文件是否存在??
  • ????????????????InputStreamReader?read?=?new?InputStreamReader(new?FileInputStream(file),?encoding);???
  • ????????????????BufferedReader?bufferedReader?=?new?BufferedReader(read);??
  • ????????????????String?lineTxt?=?null;??
  • ????????????????sumLabel?=1;?//初始化從1記錄??
  • ????????????????//按行讀取數據并分解數據??
  • ????????????????while((lineTxt?=?bufferedReader.readLine())?!=?null)?{??
  • ????????????????????String?str?=?null;??
  • ????????????????????int?lengthLine?=?lineTxt.length();??
  • ????????????????????//獲取數據?字符串空格分隔??
  • ????????????????????String?arrays[]?=?lineTxt.split("?");??
  • ????????????????????for(int?i=0;?i<arrays.length;?i++)?{??
  • ????????????????????????//獲取每行樣本的Label值??
  • ????????????????????????if(i==0)?{??
  • ????????????????????????????label[sumLabel]?=?Integer.parseInt(arrays[0]);??
  • ????????????????????????}???
  • ????????????????????????else?if(i>=weidu+2){?//讀取至#跳出?0-label?1-qid?2:47-特征??
  • ????????????????????????????continue;??
  • ????????????????????????}??
  • ????????????????????????else?{??
  • ????????????????????????????String?subArrays[]?=?arrays[i].split(":");?//特征:特征值??
  • ????????????????????????????if(i==1)?{?//獲取qid????????
  • ????????????????????????????????//判斷是否是新的Qid??
  • ????????????????????????????????if(tempQid?!=?Integer.parseInt(subArrays[1]))?{???
  • ????????????????????????????????????if(tempQid?!=?-1){?//不是第一次出現新Qid??
  • ????????????????????????????????????????//賦值上一個為qid_Num對應的tempDoc個文檔??
  • ????????????????????????????????????????doc_ofQid[qid_Num]=tempDoc;??????
  • ????????????????????????????????????????tempDoc=0;??
  • ????????????????????????????????????}??
  • ????????????????????????????????????//當tempQid不等于當前qid時下標加1???
  • ????????????????????????????????????//相等則直接跳至Doc加1直到不等??
  • ????????????????????????????????????qid_Num++;??
  • ????????????????????????????????????tempQid=Integer.parseInt(subArrays[1]);???????????????????????
  • ????????????????????????????????}??
  • ????????????????????????????????tempDoc++;?//新的文檔???
  • ????????????????????????????????qid[sumLabel]?=?Integer.parseInt(subArrays[1]);??
  • ????????????????????????????}???
  • ????????????????????????????else?{?//獲取46維特征值??
  • ????????????????????????????????int?number?=?Integer.parseInt(subArrays[0]);?//判斷特征??
  • ????????????????????????????????double?value?=?Double.parseDouble(subArrays[1]);??
  • ????????????????????????????????feature[sumLabel][number]?=?value;?//number數組標號:1-46??
  • ????????????????????????????}??
  • ????????????????????????}??
  • ????????????????????}??
  • ????????????????????sumLabel++;??
  • ????????????????}??
  • ????????????????doc_ofQid[qid_Num]=tempDoc;??
  • ????????????????read.close();??
  • ????????????}?else?{??
  • ????????????????System.out.println("找不到指定的文件\n");??
  • ????????????}??
  • ????????}?catch?(Exception?e)?{??
  • ????????????System.out.println("讀取文件內容出錯");??
  • ????????????e.printStackTrace();??
  • ????????}??
  • ????}??
  • ??
  • ????/**?
  • ?????*?學習排序?
  • ?????*?訓練模型得到46維權重?
  • ?????*/??
  • ????public?static?void?LearningToRank()?{??
  • ??????????
  • ????????//變量??
  • ????????double?index?[]?=?new?double[1000000];??
  • ????????double?tao?[]?=?new?double[1000000];??
  • ????????double?yita=0.00003;??
  • ????????//初始化??
  • ????????for(int?i=0;i<weidu+2;i++)?{?//從1到136為權重,0和137無用??
  • ????????????weight[i]?=?(double)?1.0;?//權重初值??
  • ????????}??
  • ????????System.out.println("training...");????????????????
  • ????????//計算權重?學習算法??
  • ????????for(int?iter?=?0;?iter<ITER_NUM;?iter++)?//迭代ITER_NUM次??
  • ????????{???
  • ????????????System.out.println("---迭代次數:"+iter);??
  • ????????????int?now_doc=0;?//全局文檔索引??
  • ????????????for(int?i=1;?i<=qid_Num;?i++)?//總樣qid數??相當于兩層循環T和m???
  • ????????????{???
  • ????????????????double?delta_w[]?=?new?double[weidu+2];?//46個梯度組成的向量??
  • ????????????????int?doc_of_i=doc_ofQid[i];?//該Qid的文檔數??
  • ????????????????//得分f(w),一個QID有多個文檔,一個文檔為一個分,所以一個i對應一個分數數組??
  • ????????????????double?fw[]?=?new?double[doc_of_i+2];??
  • ??????????????????
  • ????????????????/*?第一步?算得分數組fw?fin?*/??
  • ????????????????for(int?k=1;k<=doc_of_i;k++)?{?//初始化??
  • ????????????????????fw[k]=0.0;??
  • ????????????????}??
  • ????????????????for(int?k=1;k<=doc_of_i;k++)?{?//每個文檔的得分??
  • ????????????????????for(int?p=1;p<=weidu;p++)?{??
  • ????????????????????????fw[k]=fw[k]+weight[p]*feature[now_doc+k][p];?//算出這個文檔的分數??
  • ????????????????????}??
  • ????????????????}??
  • ??????????????????
  • ????????????????/*?
  • ?????????????????*?第二步??算梯度delta_w向量?
  • ?????????????????*?a=Σp*x,a是向量???
  • ?????????????????*?b=Σexpf(x),b是數字?
  • ?????????????????*?c=expf(x)*x,c是向量?
  • ?????????????????*?最終結果delta_w是向量?
  • ?????????????????*/??
  • ????????????????double[]?a=new?double[weidu+2],c=new?double[weidu+2];??
  • ????????????????for(int?k=0;k<weidu+2;k++){a[k]=0.0;}?//初始化??
  • ????????????????for(int?k=0;k<weidu+2;k++){c[k]=0.0;}?//初始化??
  • ????????????????double?b=0.0;??
  • ????????????????//算a:----??
  • ????????????????for(int?k=1;?k<=doc_of_i;?k++)?{??
  • ????????????????????double?p=1.0;?//先不topK??
  • ????????????????????double[]?temp=new?double[48];??
  • ????????????????????for(int?q=1;q<=weidu;q++)?{??
  • ????????????????????????//算P:?----第q個向量排XX的概率是多少??
  • ????????????????????????//分母:??
  • ????????????????????????double?fenmu=0.0;??
  • ????????????????????????for(int?m=1;m<=doc_of_i;m++)?{??
  • ????????????????????????????fenmu=fenmu+Math.exp(fw[m]);?//所有文檔得分??
  • ????????????????????????}??
  • ????????????????????????//top-1??exp(s1)?/?exp(s1)+exp(s2)+..+exp(sn)??
  • ????????????????????????for(int?m=1;m<=doc_of_i;m++)?{??
  • ????????????????????????????p=p*(Math.exp(fw[m])/fenmu);??
  • ????????????????????????}??
  • ????????????????????????//算積??
  • ????????????????????????temp[q]=temp[q]+p*feature[now_doc+k][q];??
  • ????????????????????}??
  • ????????????????????for(int?q=1;?q<=weidu;?q++){???????????
  • ????????????????????????a[q]=a[q]+temp[q];??
  • ????????????????????}?????
  • ????????????????}?//End?a??
  • ????????????????//算b:----?fin.??
  • ????????????????for(int?k=1;?k<=doc_of_i;?k++){??
  • ????????????????????b=b+Math.exp(fw[k]);??
  • ????????????????}??
  • ????????????????//算c:----??
  • ????????????????for(int?k=1;?k<=doc_of_i;?k++){??
  • ????????????????????double[]?temp=new?double[weidu+2];??
  • ????????????????????for(int?q=1;?q<=weidu;?q++){???????????
  • ????????????????????????temp[q]=temp[q]+Math.exp(fw[k])*feature[now_doc+k][q];??
  • ????????????????????}??
  • ????????????????????for(int?q=1;?q<=weidu;?q++){???????????
  • ????????????????????????c[q]=c[q]+temp[q];??
  • ????????????????????}?????
  • ????????????????}??
  • ????????????????//算梯度:delta_x=-a+1/b*c??
  • ????????????????for(int?q=1;?q<=weidu;?q++){??
  • ????????????????????delta_w[q]=?(-1)*a[q]?+?((1.0/b)*c[q]);??
  • ????????????????}??
  • ????????????????//**********??
  • ??????????????????
  • ????????????????/*?第三步?更新權重?fin.?*/??
  • ????????????????for(int?k=1;?k<=weidu;?k++){??
  • ????????????????????weight[k]=weight[k]-yita*delta_w[k];??
  • ????????????????}??
  • ????????????????now_doc=now_doc+doc_of_i;?//更新當前文檔索引??
  • ????????????}??
  • ????????}?//End?迭代次數??
  • ??????????
  • ????????//輸出權重??
  • ????????for(int?i=1;i<=weidu;i++)?//從1到136為權重,0和137無用??
  • ????????{??
  • ????????????System.out.println(i+"wei:"+weight[i]);??
  • ????????}??
  • ????}??
  • ??????
  • ????/**?
  • ?????*?輸出權重到文件fileModel?
  • ?????*?@param?fileModel?
  • ?????*/??
  • ????public?static?void?WriteFileModel(String?fileModel)?{??
  • ????????//輸出權重到文件??
  • ????????try?{??
  • ????????????System.out.println("write?start.總行數:"+sumLabel);??
  • ????????????FileWriter?fileWriter?=?new?FileWriter(fileModel);??
  • ????????????//寫數據??
  • ????????????fileWriter.write("##?ListNet");??
  • ????????????fileWriter.write("\r\n");??
  • ????????????fileWriter.write("##?Epochs?=?"+ITER_NUM);??
  • ????????????fileWriter.write("\r\n");??
  • ????????????fileWriter.write("##?No.?of?features?=?46");??
  • ????????????fileWriter.write("\r\n");??
  • ????????????fileWriter.write("1?2?3?4?5?6?7?8?9?10?...??39?40?41?42?43?44?45?46");??
  • ????????????fileWriter.write("\r\n");??
  • ????????????fileWriter.write("0");??
  • ????????????fileWriter.write("\r\n");??
  • ????????????for(int?k=0;?k<weidu;?k++){??
  • ????????????????fileWriter.write("0?"+k+"?"+weight[k+1]);??
  • ????????????????fileWriter.write("\r\n");??
  • ????????????}??
  • ????????????fileWriter.close();??
  • ????????????System.out.println("write?fin.");??
  • ????????}?catch(Exception?e)?{??
  • ????????????System.out.println("寫文件內容出錯");??
  • ????????????e.printStackTrace();??
  • ????????}??
  • ????}??
  • ??????
  • ????/**?
  • ?????*?預測排序?
  • ?????*?正規應對test.txt文件進行打分排序?
  • ?????*?但我們是在Hadoop實現該打分排序步驟?此函數僅測試train.txt打分?
  • ?????*/??
  • ????public?static?void?PredictRank(String?fileScore)?{??
  • ????????//輸出得分??
  • ????????try?{??
  • ????????????System.out.println("write?start.總行數:"+sumLabel);??
  • ????????????String?encoding?=?"GBK";??
  • ????????????FileWriter?fileWriter?=?new?FileWriter(fileScore);??
  • ????????????//寫數據??
  • ????????????for(int?k=1;?k<sumLabel;?k++){??
  • ????????????????double?score=0.0;??
  • ????????????????for(int?j=1;j<=weidu;j++){??
  • ????????????????????score=score+weight[j]*feature[k][j];??
  • ????????????????}??
  • ????????????????fileWriter.write("qid:"+qid[k]+"?score:"+score+"?label:"+label[k]);??
  • ????????????????fileWriter.write("\r\n");??
  • ????????????}?????
  • ????????????fileWriter.close();??
  • ????????????System.out.println("write?fin.");?????
  • ????????}?catch(Exception?e)?{??
  • ????????????System.out.println("寫文件內容出錯");??
  • ????????????e.printStackTrace();??
  • ????????}??
  • ????}??
  • ??????
  • ????/**?
  • ?????*?主函數?
  • ?????*/??
  • ????public?static?void?main(String?args[])?{??
  • ????????String?fileInput?=?"Fold1\\train.txt";???????//訓練??
  • ????????String?fileModel?=?"model_weight.txt";???????//輸出權重模型??
  • ????????String?fileScore?=?"score_listNet.txt";??????//輸出得分??
  • ????????//第1步?讀取文件并解析數據??
  • ????????System.out.println("read...");??
  • ????????ReadTxtFile(fileInput);??
  • ????????System.out.println("read?and?write?well.");??
  • ????????//第2步?排序計算??
  • ????????LearningToRank();??
  • ????????//第3步?輸出模型??
  • ????????WriteFileModel(fileModel);??
  • ????????//第4步?打分預測排序??
  • ????????PredictRank(fileScore);??
  • ??????}??
  • ??????
  • ????/*?
  • ?????*?End?
  • ?????*/??
  • ??????
  • }??
  • package listNet_xiuzhang;import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.InputStreamReader;public class listNet {//文件總行數(標記數)private static int sumLabel; //特征值 46個 (標號1-46)private static double feature[][] = new double[100000][48]; //特征值權重 46個 (標號1-46)private static double weight [] = new double[48];//相關度 其值有0-2三個級別 從1開始記錄private static int label [] = new int[1000000];//查詢id 從1開始記錄private static int qid [] = new int[1000000];//每個Qid的doc數量private static int doc_ofQid[] = new int[100000]; private static int ITER_NUM=30; //迭代次數private static int weidu=46; //特征數private static int qid_Num=0; //Qid數量private static int tempQid=-1; //臨時Qid數private static int tempDoc=0; //臨時doc數/** * 函數功能 讀取文件* 參數 String filePath 文件路徑*/public static void ReadTxtFile(String filePath) {try {String encoding="GBK";File file=new File(filePath);if(file.isFile() && file.exists()) { //判斷文件是否存在InputStreamReader read = new InputStreamReader(new FileInputStream(file), encoding); BufferedReader bufferedReader = new BufferedReader(read);String lineTxt = null;sumLabel =1; //初始化從1記錄//按行讀取數據并分解數據while((lineTxt = bufferedReader.readLine()) != null) {String str = null;int lengthLine = lineTxt.length();//獲取數據 字符串空格分隔String arrays[] = lineTxt.split(" ");for(int i=0; i<arrays.length; i++) {//獲取每行樣本的Label值if(i==0) {label[sumLabel] = Integer.parseInt(arrays[0]);} else if(i>=weidu+2){ //讀取至#跳出 0-label 1-qid 2:47-特征continue;}else {String subArrays[] = arrays[i].split(":"); //特征:特征值if(i==1) { //獲取qid //判斷是否是新的Qidif(tempQid != Integer.parseInt(subArrays[1])) { if(tempQid != -1){ //不是第一次出現新Qid//賦值上一個為qid_Num對應的tempDoc個文檔doc_ofQid[qid_Num]=tempDoc; tempDoc=0;}//當tempQid不等于當前qid時下標加1 //相等則直接跳至Doc加1直到不等qid_Num++;tempQid=Integer.parseInt(subArrays[1]); }tempDoc++; //新的文檔 qid[sumLabel] = Integer.parseInt(subArrays[1]);} else { //獲取46維特征值int number = Integer.parseInt(subArrays[0]); //判斷特征double value = Double.parseDouble(subArrays[1]);feature[sumLabel][number] = value; //number數組標號:1-46}}}sumLabel++;}doc_ofQid[qid_Num]=tempDoc;read.close();} else {System.out.println("找不到指定的文件\n");}} catch (Exception e) {System.out.println("讀取文件內容出錯");e.printStackTrace();}}/*** 學習排序* 訓練模型得到46維權重*/public static void LearningToRank() {//變量double index [] = new double[1000000];double tao [] = new double[1000000];double yita=0.00003;//初始化for(int i=0;i<weidu+2;i++) { //從1到136為權重,0和137無用weight[i] = (double) 1.0; //權重初值}System.out.println("training..."); //計算權重 學習算法for(int iter = 0; iter<ITER_NUM; iter++) //迭代ITER_NUM次{ System.out.println("---迭代次數:"+iter);int now_doc=0; //全局文檔索引for(int i=1; i<=qid_Num; i++) //總樣qid數 相當于兩層循環T和m { double delta_w[] = new double[weidu+2]; //46個梯度組成的向量int doc_of_i=doc_ofQid[i]; //該Qid的文檔數//得分f(w),一個QID有多個文檔,一個文檔為一個分,所以一個i對應一個分數數組double fw[] = new double[doc_of_i+2];/* 第一步 算得分數組fw fin */for(int k=1;k<=doc_of_i;k++) { //初始化fw[k]=0.0;}for(int k=1;k<=doc_of_i;k++) { //每個文檔的得分for(int p=1;p<=weidu;p++) {fw[k]=fw[k]+weight[p]*feature[now_doc+k][p]; //算出這個文檔的分數}}/** 第二步 算梯度delta_w向量* a=Σp*x,a是向量 * b=Σexpf(x),b是數字* c=expf(x)*x,c是向量* 最終結果delta_w是向量*/double[] a=new double[weidu+2],c=new double[weidu+2];for(int k=0;k<weidu+2;k++){a[k]=0.0;} //初始化for(int k=0;k<weidu+2;k++){c[k]=0.0;} //初始化double b=0.0;//算a:----for(int k=1; k<=doc_of_i; k++) {double p=1.0; //先不topKdouble[] temp=new double[48];for(int q=1;q<=weidu;q++) {//算P: ----第q個向量排XX的概率是多少//分母:double fenmu=0.0;for(int m=1;m<=doc_of_i;m++) {fenmu=fenmu+Math.exp(fw[m]); //所有文檔得分}//top-1 exp(s1) / exp(s1)+exp(s2)+..+exp(sn)for(int m=1;m<=doc_of_i;m++) {p=p*(Math.exp(fw[m])/fenmu);}//算積temp[q]=temp[q]+p*feature[now_doc+k][q];}for(int q=1; q<=weidu; q++){ a[q]=a[q]+temp[q];} } //End a//算b:---- fin.for(int k=1; k<=doc_of_i; k++){b=b+Math.exp(fw[k]);}//算c:----for(int k=1; k<=doc_of_i; k++){double[] temp=new double[weidu+2];for(int q=1; q<=weidu; q++){ temp[q]=temp[q]+Math.exp(fw[k])*feature[now_doc+k][q];}for(int q=1; q<=weidu; q++){ c[q]=c[q]+temp[q];} }//算梯度:delta_x=-a+1/b*cfor(int q=1; q<=weidu; q++){delta_w[q]= (-1)*a[q] + ((1.0/b)*c[q]);}//**********/* 第三步 更新權重 fin. */for(int k=1; k<=weidu; k++){weight[k]=weight[k]-yita*delta_w[k];}now_doc=now_doc+doc_of_i; //更新當前文檔索引}} //End 迭代次數//輸出權重for(int i=1;i<=weidu;i++) //從1到136為權重,0和137無用{System.out.println(i+"wei:"+weight[i]);}}/*** 輸出權重到文件fileModel* @param fileModel*/public static void WriteFileModel(String fileModel) {//輸出權重到文件try {System.out.println("write start.總行數:"+sumLabel);FileWriter fileWriter = new FileWriter(fileModel);//寫數據fileWriter.write("## ListNet");fileWriter.write("\r\n");fileWriter.write("## Epochs = "+ITER_NUM);fileWriter.write("\r\n");fileWriter.write("## No. of features = 46");fileWriter.write("\r\n");fileWriter.write("1 2 3 4 5 6 7 8 9 10 ... 39 40 41 42 43 44 45 46");fileWriter.write("\r\n");fileWriter.write("0");fileWriter.write("\r\n");for(int k=0; k<weidu; k++){fileWriter.write("0 "+k+" "+weight[k+1]);fileWriter.write("\r\n");}fileWriter.close();System.out.println("write fin.");} catch(Exception e) {System.out.println("寫文件內容出錯");e.printStackTrace();}}/*** 預測排序* 正規應對test.txt文件進行打分排序* 但我們是在Hadoop實現該打分排序步驟 此函數僅測試train.txt打分*/public static void PredictRank(String fileScore) {//輸出得分try {System.out.println("write start.總行數:"+sumLabel);String encoding = "GBK";FileWriter fileWriter = new FileWriter(fileScore);//寫數據for(int k=1; k<sumLabel; k++){double score=0.0;for(int j=1;j<=weidu;j++){score=score+weight[j]*feature[k][j];}fileWriter.write("qid:"+qid[k]+" score:"+score+" label:"+label[k]);fileWriter.write("\r\n");} fileWriter.close();System.out.println("write fin."); } catch(Exception e) {System.out.println("寫文件內容出錯");e.printStackTrace();}}/*** 主函數*/public static void main(String args[]) {String fileInput = "Fold1\\train.txt"; //訓練String fileModel = "model_weight.txt"; //輸出權重模型String fileScore = "score_listNet.txt"; //輸出得分//第1步 讀取文件并解析數據System.out.println("read...");ReadTxtFile(fileInput);System.out.println("read and write well.");//第2步 排序計算LearningToRank();//第3步 輸出模型WriteFileModel(fileModel);//第4步 打分預測排序PredictRank(fileScore);}/** End*/}

    四. 總結

    ? ? 上面的代碼我更希望你關注的是ListNet在訓練模型過程中的代碼,也就是通過train.txt獲取得到46維的權重的模型.通過該模型你可以對test.txt進行打分(權重*特征值)排序,而上面的代碼僅是對train.txt進行了簡單的打分操作,那時因為我們的作業是基于Hadoop或Spark分布式處理基礎上的.所以該部分由其他同學完成.
    ? ? 同時你也可以通過開源的RankLib或羅磊同學的ListNet算法進行學習,地址如下:
    ? ??http://sourceforge.net/projects/minorthird/
    ? ??http://code.google.com/p/learning-to-rank-listnet/

    ? ??http://people.cs.umass.edu/~vdang/ranklib.html
    ? ? 最后我們使用開源的MAP和NDCG@r簡單對該算法進行了性能評估,同時附上Hadoop上的運行截圖(MapReduce只找到了PRank的一張截圖).

    ?
    ?
    ? ? 希望文章對大家有所幫助,同時我是根據論文寫出的Java代碼,如果有錯誤或不足之處,還請海涵~同時歡迎提出問題,我對機器學習和算法的了解還是初學,但是會盡力答復.同時發現該部分的代碼真的很少,所以才寫了這樣一些文章,后面還準備寫寫Pairwise和Map\NDCG評價.
    ? ? (By:Eastmount 2015-2-5 夜10點 ?http://blog.csdn.net/eastmount/article/)

    總結

    以上是生活随笔為你收集整理的Learning to Rank 中Listwise关于ListNet算法讲解及实现的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。