主动排序学习算法之PRank

    PRank算法摘自梁斌博客    

    PRank是一个pointwise的监督学习排序的方法,一般被用作baseline。我看了下论文<PRank with ranking>,然后动手写了个小实验,进行了理解。
    
    其基本需求是:对于每个对象,会有不同角度的打分,现在需要一种方法融合这些打分来给他们一个排序。
例如,给体操打分,会有不同的项目,空中姿态分,落地分,技术难度分等等,单向打分一般比较容易,规则是死的,落地没站住就扣0.2。。但是这些单向分打出来了,怎么融合成一个最终分数呢?或者如果我们甚至不需要分数,直接得到其排序呢? 因为实际上,大家对具体的分数都不感兴趣,只感兴趣rank。

    Prank是解决类似问题的一种方法,该方法假定了最后融合的分数一定是每个单向得分的加权求和,因此第一步需要知道每个单向分的权重,其次还要知道得到了分数后能排在什么座次上,应此需要学习一个座次区间,比如第一名是200-190分,第二名是190-170分。学习目标是一个权重向量和名次的区间向量。
    实现比较简单。可以参考论文。
    重点说一下文章的里面,循环1和循环2,其实负责找到预测rank和label rank的误差数量和正负号。如果预测名次靠前,实际标注名次靠后,则是负的累计错误。最后表现为w需要减去相应的x,也就是w*x向量要缩短。
    
    我自己手写了一个toy data,10个学习样本学习,迭代1万次,最后预测这10个样本,顺序还都对,看了下权重
    w[0] = -64
    w[1] = -298
    w[2] = -360

    说明在这个排序逻辑中,忠诚是第一位的,其次是智力,最不可靠的是武力。

       武力    智力    忠诚    排序
诸葛亮  2       5       5       1
关羽    5       4       5       2
庞统    2       5       4       3
张飞    5       3       5       4
马超    5       4       4       5
魏延    5       4       4       6
周仓    3       3       4       7
孟达    4       3       2       8
糜竺    3       3       1       9
黄浩    2       2       2       10
    
    以下是实现代码,仅供参考

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <string>
#include "stdint.h"
using namespace std;

void split(const char* str,const char split_char,vector<uint32_t>& str_v)
{
        const char* term_head = str;
        const char* term_tail = str;
        for(;(term_head = term_tail )!='\0';)
        {
                string os ;
                char buf[2];
                buf[1]='\0';
                for(term_tail = term_head; *term_tail != split_char&&*term_tail!='\0'&&*term_tail!='\n' ;term_tail++)
                {
                        buf[0] = *term_tail;
                        os.append(buf);
                }
                if(*term_tail == split_char)
                {
                        str_v.push_back(atoi(os.c_str()));
                        term_tail++;
                }
                else if(*term_tail == '\n')
                {
                        str_v.push_back(atoi(os.c_str()));
                        return;
                }
                else if(*term_tail == '\0')
                {
                        str_v.push_back(atoi(os.c_str()));
                        return;
                }
                else
                        return;
        }
};

int main(int argc, char** argv)
{
        FILE * fp;
        char * line = NULL;
        size_t len = 0;
        ssize_t read;


        fp = fopen(argv[1], "r");
        if (fp == NULL)
                exit(EXIT_FAILURE);
        vector< vector<uint32_t> > map;
        while ((read = getline(&line, &len, fp)) != -1) {
                line[read-1] ='\0';
                vector<uint32_t> u_v;
                split(line,'\t',u_v);
                map.push_back(u_v);
        }
        vector<float> w;
        w.push_back(0);w.push_back(0);w.push_back(0);


        float b[12] = {-1,0,0,0,0,0,0,0,0,0,0,1000000};
        float index[12];
        float tao[12];


        for(int iter = 0; iter<1000000;++iter)
        {
                for(int i = 0;i<map.size();++i)
                {
                        int predict_r = 1;


                        for(int r = 1;r<=11;++r)
                        {
                                if(w[0]*map[i][0] + w[1]*map[i][1] + w[2]*map[i][2] - b[r] < 0)
                                {
                                        predict_r = r;
                                        break;
                                }
 }
                        int real_r = map[i][3];
                        if(real_r != predict_r)
                        {
                                for(int r = 1;r<=10;++r)
                                {
                                        if(real_r<=r)
                                        {
                                                index[r] = -1;
                                        }
                                        else
                                        {
                                                index[r] = 1;
                                        }
                                }
                                float tao_sum = 0.0;
                                for(int r = 1;r<=10;++r)
                                {
                                        if((w[0]*map[i][0] + w[1]*map[i][1] + w[2]*map[i][2] - b[r])*index[r]<=0)
                                        {
                                                tao[r] = index[r];
                                        }
                                        else
                                        {
                                                tao[r] = 0;
                                        }
                                        tao_sum += tao[r];
                                }
                                w[0] = w[0] + tao_sum*map[i][0];
                                w[1] = w[1] + tao_sum*map[i][1];
                                w[2] = w[2] + tao_sum*map[i][2];
                                for(int r=1;r<=10;++r)
                                {
                                        b[r] = b[r] - tao[r];
                                }
                        }
                }
        }


        for(int i = 0;i<map.size();++i)
        {
                int predict_r = 1;
                for(int r = 1;r<=11;++r)
                {
                        if(w[0]*map[i][0] + w[1]*map[i][1] + w[2]*map[i][2] - b[r] < 0)
                        {
                                predict_r = r;
                                break;
                        }
                }
                cout<<predict_r<<endl;
        }
        cout<<b[1]<<endl;
        cout<<b[2]<<endl;
        cout<<b[3]<<endl;


        fclose(fp);
        if (line)
                free(line);
        exit(EXIT_SUCCESS);
}
    

你可能感兴趣的:(主动排序学习算法之PRank)