All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.expleague.ml.models.gpf.GPFModel Maven / Gradle / Ivy

package com.expleague.ml.models.gpf;

import com.expleague.commons.math.vectors.Mx;
import com.expleague.commons.math.vectors.MxTools;
import com.expleague.ml.models.gpf.weblogmodel.BlockV1;
import com.expleague.commons.math.vectors.impl.mx.VecBasedMx;

/**
 * Created with IntelliJ IDEA.
 * User: irlab
 * Date: 08.07.14
 * Time: 13:31
 * To change this template use File | Settings | File Templates.
 */
public interface GPFModel extends AttractivenessModel {
  String explainTheta();

  String explainSessionProb(Session ses);

  double getClickGivenViewProbability(Blk b);

  /**
   * @param ses - session
   * @return transmx_0[(i, click_i), (j, click_j)] - вероятность перехода за один шаг из состояния (i, click_i) в (j, click_j)
   */
  VecBasedMx evalSessionTransitionProbs(Session ses);

  /**
   * for each block in ses.getBlocks(), evaluates probability that a user has one or more clicks on the block, given the behavior model
   * @param ses - viewport structure
   * @return double[ses.getBlocks().length] - array of probabilities
   */
  double[] evalHasClickProbabilities(Session ses);

  /**
   * for each block in ses.getBlocks(), evaluates probability that a user has one or more views on the block, given the behavior model
   * @param ses - viewport structure
   * @return double[ses.getBlocks().length] - array of probabilities
   */
  double[] evalHasViewProbabilities(Session ses);

  /**
   * for each block in ses.getBlocks(), evaluates expected number of steps when a user looks at the block, given the behavior model
   * this is not distribution, sum of values is not equal to 1
   * @param ses - viewport structure
   * @return double[ses.getBlocks().length] - array of expected number of steps
   */
  double[] evalExpectedAttention(Session ses);

  /**
   * evaluates expected number of clicks on the SERP, given the behavior model
   * @param ses - viewport structure
   * @return double - array of expected number of steps
   */
  double evalExpectedNumberOfClicks(Session ses);

  abstract class Stub implements GPFModel {
    public int MAX_PATH_LENGTH = 15;

    /**
     * @param ses - session
     * @return transmx_0[(i, click_i), (j, click_j)] - вероятность перехода за один шаг из состояния (i, click_i) в (j, click_j)
     */
    @Override
    public VecBasedMx evalSessionTransitionProbs(final Session ses) {
      final Blk[] blocks = ses.getBlocks();

      // 1 & для каждой пары блоков $i$, $j$ вычислить $f(i,j)$; третья координата - наличие клика c_i
      final Tensor3 f = new Tensor3(blocks.length, blocks.length, 2);
      for (int i = 0; i < blocks.length; i++) {
        for (final int j: ses.getEdgesFrom(i)) {
          for (int click_i = 0; click_i < 2; click_i++) {
            f.set(i, j, click_i, eval_f(ses, i, j, click_i));
          }
        }
      }
      f.set(Session.E_INDEX, Session.E_INDEX, 0, 1.);
      f.set(Session.E_INDEX, Session.E_INDEX, 1, 1.);

      // transmx[(i, click_i), (j, click_j)] - вероятность перехода за один шаг из состояния (i, click_i) в (j, click_j)
      final VecBasedMx transmx_0 = new VecBasedMx(blocks.length * 2, blocks.length * 2);
      for (int i = 0; i < blocks.length; i++) {
        for (int click_i = 0; click_i < 2; click_i++) {
          double sum_f_i_j = 0.;
          for (final int j: ses.getEdgesFrom(i))
            sum_f_i_j += f.get(i, j, click_i);

          for (final int j: ses.getEdgesFrom(i)) {
            final double trans_prob = f.get(i, j, click_i) / sum_f_i_j;
            final double click_prob = getClickGivenViewProbability(blocks[j]);
            transmx_0.set(click_i * blocks.length + i, 0 * blocks.length + j, trans_prob * (1. - click_prob));
            transmx_0.set(click_i * blocks.length + i, 1 * blocks.length + j, trans_prob * click_prob);
          }
        }
      }
      return transmx_0;
    }

    /**
     * for each block in ses.getBlocks(), evaluates probability that a user has one or more clicks on the block, given the behavior model
     * @param ses - viewport structure
     * @return double[ses.getBlocks().length] - array of probabilities
     */
    @Override
    public double[] evalHasClickProbabilities(final Session ses) {
      final Session.Block[] blocks = ses.getBlocks();
      // transmx_0[(i, click_i), (j, click_j)] - вероятность перехода за один шаг из состояния (i, click_i) в (j, click_j)
      final VecBasedMx transmx_0 = evalSessionTransitionProbs(ses);

      final double[] hasClickProbabilities = new double[blocks.length];
      for (int ci = Session.R0_INDEX; ci < blocks.length; ci++) {
        final VecBasedMx transmx_ci = new VecBasedMx(transmx_0);
        // модифицируем стохастическую матрицу transmx_ci так, чтобы после клика на ci пользователь оставался в том же состоянии
        for (int j = 0; j < transmx_ci.columns; j++)
          transmx_ci.set(1 * blocks.length + ci, j, 0.);
        transmx_ci.set(1 * blocks.length + ci, 1 * blocks.length + ci, 1.);

        // сначала пользователь в состоянии (Q, no_click)
        Mx state_probabilities = new VecBasedMx(1, transmx_0.columns);
        state_probabilities.set(0, Session.Q_INDEX, 1.);

        for (int t = 0; t < MAX_PATH_LENGTH; t++)
          state_probabilities = MxTools.multiply(state_probabilities, transmx_ci);

        // вероятность через MAX_PATH_LENGTH шагов остаться в состоянии (ci, click)
        hasClickProbabilities[ci] = state_probabilities.get(1 * blocks.length + ci);
      }

      return hasClickProbabilities;
    }

    /**
     * for each block in ses.getBlocks(), evaluates probability that a user has one or more views on the block, given the behavior model
     * @param ses - viewport structure
     * @return double[ses.getBlocks().length] - array of probabilities
     */
    @Override
    public double[] evalHasViewProbabilities(final Session ses) {
      final Session.Block[] blocks = ses.getBlocks();
      // transmx_0[(i, click_i), (j, click_j)] - вероятность перехода за один шаг из состояния (i, click_i) в (j, click_j)
      final VecBasedMx transmx_0 = evalSessionTransitionProbs(ses);

      final double[] hasViewProbabilities = new double[blocks.length];
      for (int ci = Session.R0_INDEX; ci < blocks.length; ci++) {
        final VecBasedMx transmx_ci = new VecBasedMx(transmx_0);
        // модифицируем стохастическую матрицу transmx_ci так, чтобы после view на ci пользователь оставался в том же состоянии
        for (int j = 0; j < transmx_ci.columns; j++) {
          transmx_ci.set(0 * blocks.length + ci, j, 0.);
          transmx_ci.set(1 * blocks.length + ci, j, 0.);
        }
        transmx_ci.set(0 * blocks.length + ci, 0 * blocks.length + ci, 1.);
        transmx_ci.set(1 * blocks.length + ci, 1 * blocks.length + ci, 1.);

        // сначала пользователь в состоянии (Q, no_click)
        Mx state_probabilities = new VecBasedMx(1, transmx_0.columns);
        state_probabilities.set(0, Session.Q_INDEX, 1.);

        for (int t = 0; t < MAX_PATH_LENGTH; t++)
          state_probabilities = MxTools.multiply(state_probabilities, transmx_ci);

        // вероятность через MAX_PATH_LENGTH шагов остаться в состоянии (ci, click) или (ci, noclick)
        hasViewProbabilities[ci] = state_probabilities.get(0 * blocks.length + ci) + state_probabilities.get(1 * blocks.length + ci);
      }

      return hasViewProbabilities;
    }

    /**
     * for each block in ses.getBlocks(), evaluates expected number of steps when a user looks at the block, given the behavior model
     * this is not distribution, sum of values is not equal to 1
     * @param ses - viewport structure
     * @return double[ses.getBlocks().length] - array of expected number of steps
     */
    @Override
    public double[] evalExpectedAttention(final Session ses) {
      final Session.Block[] blocks = ses.getBlocks();
      // transmx_0[(i, click_i), (j, click_j)] - вероятность перехода за один шаг из состояния (i, click_i) в (j, click_j)
      final VecBasedMx transmx_0 = evalSessionTransitionProbs(ses);

      final double[] expectedAttention = new double[blocks.length];
      // сначала пользователь в состоянии (Q, no_click)
      Mx state_probabilities = new VecBasedMx(1, transmx_0.columns);
      state_probabilities.set(0, Session.Q_INDEX, 1.);

      for (int t = 0; t < MAX_PATH_LENGTH; t++) {
        state_probabilities = MxTools.multiply(state_probabilities, transmx_0);
        for (int i = Session.R0_INDEX; i < blocks.length; i++)
          expectedAttention[i] += state_probabilities.get(0 * blocks.length + i) + state_probabilities.get(1 * blocks.length + i);
      }

      return expectedAttention;
    }

    /**
     * for each block in ses.getBlocks(), evaluates expected number of steps when a user looks at the block, given the behavior model
     * this is not distribution, sum of values is not equal to 1
     * @param ses - viewport structure
     * @return double[ses.getBlocks().length] - array of expected number of steps
     */
    @Override
    public double evalExpectedNumberOfClicks(final Session ses) {
      final Session.Block[] blocks = ses.getBlocks();
      // transmx_0[(i, click_i), (j, click_j)] - вероятность перехода за один шаг из состояния (i, click_i) в (j, click_j)
      final VecBasedMx transmx_0 = evalSessionTransitionProbs(ses);

      double expectedNumberOfClicks = 0.;
      // сначала пользователь в состоянии (Q, no_click)
      Mx state_probabilities = new VecBasedMx(1, transmx_0.columns);
      state_probabilities.set(0, Session.Q_INDEX, 1.);

      for (int t = 0; t < MAX_PATH_LENGTH; t++) {
        state_probabilities = MxTools.multiply(state_probabilities, transmx_0);
        for (int i = Session.R0_INDEX; i < blocks.length; i++)
          expectedNumberOfClicks += state_probabilities.get(blocks.length + i);
      }

      return expectedNumberOfClicks;
    }

    @Override
    public String explainSessionProb(final Session ses) {
      final VecBasedMx sum_f = new VecBasedMx(ses.getBlocks().length, 2);
      for (int i = 0; i < ses.getBlocks().length; i++) {
        for (final int j: ses.getEdgesFrom(i)) {
          sum_f.adjust(i, 0, eval_f(ses, i, j, 0));
          sum_f.adjust(i, 1, eval_f(ses, i, j, 1));
        }
      }
      final double[] hasClickProbabilities = evalHasClickProbabilities(ses);
      final double[] hasViewProbabilities = evalHasViewProbabilities(ses);
      final double[] attentionExpectation = evalExpectedAttention(ses);
//    ArrayVec attentionDistribution = new ArrayVec(attentionExpectation);
//    attentionDistribution.scale(1. / VecTools.sum(attentionDistribution));

      final StringBuffer ret = new StringBuffer();
      ret.append("pos\tsntype\trel\tclick\t");
      ret.append("P(has_click)\tP(has_view)\tE(Att)\t\t");
      ret.append("P(click|V)\tP(Q->i)\tP(S->i)\t\t");
      ret.append("P(i->i+1|c=0)\tP(i->i-1|c=0)\tP(i->E|c=0)\tP(i->S|c=0)\t\t");
      ret.append("P(i->i+1|c=1)\tP(i->i-1|c=1)\tP(i->E|c=1)\tP(i->S|c=1)\n");

      for (int i = Session.R0_INDEX; i < ses.getBlocks().length; i++) {
        final Blk bi = ses.getBlock(i);
        int click_position = -1;
        for (int ci = 0; ci < ses.getClick_indexes().length; ci++) {
          if (ses.getClick_indexes()[ci] == i) {
            click_position = ci+1;
            break;
          }
        }
        //ret.append("pos\tsntype\trel\tclick\t");
        ret.append("" + bi.position + "\t" +
                   (bi instanceof BlockV1 ? ((BlockV1)bi).resultType.name() : "?") + "\t" +
                   (bi instanceof BlockV1 ? ((BlockV1)bi).resultGrade.name() : "?") + "\t" +
                   (click_position >= 0 ? click_position : "-") + "\t");

        //ret.append("P(has_click)\tP(has_view)\tAtt\t\t");
        ret.append("" + hasClickProbabilities[i] + "\t" + hasViewProbabilities[i] + "\t" + attentionExpectation[i] + "\t\t");

        //ret.append("P(click|V)\tP(Q->i)\tP(S->i)\t\t");
        final double P_Q_i = eval_f(ses, Session.Q_INDEX, i, 0) / sum_f.get(Session.Q_INDEX, 0);
        final double P_S_i = eval_f(ses, Session.S_INDEX, i, 0) / sum_f.get(Session.S_INDEX, 0);
        ret.append("" + getClickGivenViewProbability(bi) + "\t" + P_Q_i + "\t" + P_S_i + "\t\t");

        //ret.append("P(i->i+1|c=0)\tP(i->i-1|c=0)\tP(i->E|c=0)\tP(i->S|c=0)\t\t");
        int click_i = 0;
        double P_down = i + 1 < ses.getBlocks().length ? eval_f(ses, i, i+1, click_i) / sum_f.get(i, click_i) : 0;
        double P_up = i - 1 >= Session.R0_INDEX ? eval_f(ses, i, i-1, click_i) / sum_f.get(i, click_i) : 0;
        double P_i_E = eval_f(ses, i, Session.E_INDEX, click_i) / sum_f.get(i, click_i);
        double P_i_S = eval_f(ses, i, Session.S_INDEX, click_i) / sum_f.get(i, click_i);
        ret.append("" + P_down + "\t" + P_up + "\t" + P_i_E + "\t" + P_i_S + "\t\t");

        //ret.append("P(i->i+1|c=1)\tP(i->i-1|c=1)\tP(i->E|c=1)\tP(i->S|c=1)\n");
        click_i = 1;
        P_down = i + 1 < ses.getBlocks().length ? eval_f(ses, i, i+1, click_i) / sum_f.get(i, click_i) : 0;
        P_up = i - 1 >= Session.R0_INDEX ? eval_f(ses, i, i-1, click_i) / sum_f.get(i, click_i) : 0;
        P_i_E = eval_f(ses, i, Session.E_INDEX, click_i) / sum_f.get(i, click_i);
        P_i_S = eval_f(ses, i, Session.S_INDEX, click_i) / sum_f.get(i, click_i);
        ret.append("" + P_down + "\t" + P_up + "\t" + P_i_E + "\t" + P_i_S + "\n");
      }
      return ret.toString();
    }

  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy