# Post on ranked random coefficients logit

**URL:** <https://discourse.mc-stan.org/t/post-on-ranked-random-coefficients-logit/7136>\
**Category:** Modeling\
**Created:** [January 3, 2019, 3:37pm UTC](https://discourse.mc-stan.org/t/post-on-ranked-random-coefficients-logit/7136 "2019-01-03T15:37:32Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![James\_Savage](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.mc-stan.org/james_savage/32/26_2.png) [@James\_Savage](https://discourse.mc-stan.org/u/James_Savage)\
**Post date:** [January 3, 2019, 3:37pm UTC](https://discourse.mc-stan.org/t/post-on-ranked-random-coefficients-logit/7136/1 "2019-01-03T15:37:33Z")

</div>

I put together a post on ranked choice random coefficients logit, which comes up a lot in market research. Filing it here to make it searchable.

[http://khakieconomics.github.io/2018/12/27/Ranked-random-coefficients-logit.html](http://khakieconomics.github.io/2018/12/27/Ranked-random-coefficients-logit.html)

Jim

---

<div class="post-metadata">

**Author:** ![sree\_d](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.mc-stan.org/sree_d/32/6091_2.png) [@sree\_d](https://discourse.mc-stan.org/u/sree_d)\
**Post date:** [January 3, 2019, 6:25pm UTC](https://discourse.mc-stan.org/t/post-on-ranked-random-coefficients-logit/7136/2 "2019-01-03T18:25:49Z")

</div>

Thanks for sharing. Can this be used for MaxDiff? I use Sawtooth and R right now, but will read your post in greater detail and comeback with questions.

Sree.

---

<div class="post-metadata">

**Author:** ![James\_Savage](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.mc-stan.org/james_savage/32/26_2.png) [@James\_Savage](https://discourse.mc-stan.org/u/James_Savage)\
**Post date:** [January 3, 2019, 7:00pm UTC](https://discourse.mc-stan.org/t/post-on-ranked-random-coefficients-logit/7136/3 "2019-01-03T19:00:26Z")

</div>

Yeah, you could implement Sawtooth’s version of MaxDiff by modifying the best choice code. Remember that `softmax(V)` describes the probability each element of the vector `U = V + e` (where `e` is Gumbel distributed) is the maximum. If we want the probability that an element of U is the worst, then you might think that we could take the softmax of the negative of `V`, but that’s actually wrong, because `e` is not symmetrically distributed. In the Sawtooth [whitepaper](https://www.sawtoothsoftware.com/support/technical-papers/maxdiff-best-worst-scaling/maxdiff-technical-paper-2013) they say that it “works well in practice” but I’d be cautious. This little code snippet will show you how wrong it can be.

```
rgumbel <- function(n, mu = 0, beta = 1) mu - beta * log(-log(runif(n)))
V <- rnorm(10)

n_rep <- 10000
U <- sapply(1:n_rep, function(i) V + rgumbel(10))
max_choice <- apply(U, 2, which.max)
min_choice <- apply(U, 2, which.min)
max_proportions <- unlist(lapply(1:10, function(i) sum(max_choice == i)))/n_rep
min_proportions <- unlist(lapply(1:10, function(i) sum(min_choice == i)))/n_rep

softmax <- function(x) exp(x)/sum(exp(x))

# Maximum probabilities 
plot(as.numeric(max_proportions), softmax(V))
abline(0, 1)

# The minimum probabilities given by softmax(-V) versus the (more correct) simulated minimums.
plot(as.numeric(min_proportions), softmax(-V))
abline(0, 1)

```

In any case, to implement the Sawtooth version of MaxDiff, which you shouldn’t, you can do the following. First, add another dummy vector for `worst_choice` describing worst choices in each task, then modify the model chunk:

```
model {
  // create a temporary holding vector
  vector[N] log_prob;
  vector[N] log_prob_worst;
  
  // priors on the parameters
  tau ~ normal(0, .5);
  beta ~ normal(0, .5);
  to_vector(z) ~ normal(0, 1);
  L_Omega ~ lkj_corr_cholesky(4);
  to_vector(Gamma) ~ normal(0, 1);
  
  // log probabilities of each choice in the dataset
  for(t in 1:T) {
    vector[K] utilities; // tmp vector holding the utilities for the task/individual combination

    // add utility from product attributes with individual part-worths/marginal utilities
    utilities = X[start[t]:end[t]]*beta_individual[task_individual[t]]';
    
    log_prob[start[t]:end[t]] = log_softmax(utilities);
    log_prob_worst[start[t]:end[t]] = log_softmax(-utilities);
  }
  
  // use the likelihood derivation on slide 29
  target += log_prob' * choice;
  // increase the log probability for worst choices
  target += log_prob_worst' * worst_choice;
}

```

---

<div class="post-metadata">

**Author:** ![sree\_d](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.mc-stan.org/sree_d/32/6091_2.png) [@sree\_d](https://discourse.mc-stan.org/u/sree_d)\
**Post date:** [January 19, 2019, 12:09pm UTC](https://discourse.mc-stan.org/t/post-on-ranked-random-coefficients-logit/7136/4 "2019-01-19T12:09:22Z")

</div>

@James_Savage

thanks a lot for the detailed response. I will examine and get back with any questions.

---

<div class="post-metadata">

**Author:** ![sonicking](https://avatars.discourse-cdn.com/v4/letter/s/d07c76/32.png) [@sonicking](https://discourse.mc-stan.org/u/sonicking)\
**Post date:** [August 16, 2019, 8:44pm UTC](https://discourse.mc-stan.org/t/post-on-ranked-random-coefficients-logit/7136/5 "2019-08-16T20:44:44Z")

</div>

Hello.

Do you have a better way to model the _worst_ choice, rather than the way Sawtooth does it?

Cheers~
