4

The model I'm working on is a multinomial logit choice model. It's a very specific dataset so other existing MNLogit libraries don't fit with my data.

So basically, it's a very complex function which takes 11 parameters and returns a loglikelihood value. Then I need to find the optimal parameter values that can minimize the loglikelihood using scipy.optimize.minimize.

Here are the problems that I encounter with different methods:

'Nelder-Mead’: it works well, and always give me the correct answer. However, it's EXTREMELY slow. For another function with a more complicated setup, it takes 15 hours to get to the optimal point. At the same time, the same function takes only 1 hour on Matlab using fminunc (which uses BFGS by default)

‘BFGS’: This is the method used by Matlab. It works well for any simply functions. However, for the function that I have, it always fails to converge and returns 'Desired error not necessarily achieved due to precision loss.’. I've spent lots of time playing around with the options but still failed to work.

'Powell': It quickly converges successfully but returns a wrong answer. The code is printed below (x0 is the correct answer, Nelder-Mead works for whatever initial value), and you can get the data here: https://www.dropbox.com/s/aap2dhor5jyxy94/data.csv

Thanks!

import pandas as pd
import numpy as np
from scipy.optimize import minimize

# https://www.dropbox.com/s/aap2dhor5jyxy94/data.csv
df = pd.read_csv('data.csv', index_col=0)
dfhh = df.hh
B = df.ix[:,'b0':'b4'].values # NT*5
P = df.ix[:,'p1':'p4'].values # NT*4
F = df.ix[:,'f1':'f4'].values # NT*4
SDV = df.ix[:,'lagb1':'lagb4'].values

def Li(x):
    b1 = x[0] # coeff on prices
    b2 = x[1] # coeff on features
    a = x[2:7] # take first 4 values as alpha
    E = np.exp(a + b1*P + b2*F) # (1*4) + (NT*4) + (NT*4) build matrix (NT*J) for each exp()
    E = np.insert(E, 0, 1, axis=1) # (NT*5)
    denom = E.sum(1)
    return -np.log((B * E).sum(1) / denom).sum()


x0 = np.array([-32.31028223, 0.23965953, 0.84739154, 0.25418215,-3.38757007,-0.38036966])
np.random.seed(0)
x0 = x0 + np.random.rand(6)

 minL = minimize(Li, x0, method='Nelder-Mead',options={'xtol': 1e-8, 'disp': True})
# minL = minimize(Li, x0, method='BFGS')
# minL = minimize(Li, x0, method='Powell', options={'xtol': 1e-12, 'ftol': 1e-12})
print minL

Update: 03/07/14 Simpler Version of the Code Now Powell works well with very small tolerance, however the speed of Powell is slower than Nelder-Mead in this case. BFGS still fails to work.

Titanic
  • 557
  • 1
  • 8
  • 21
  • Try to run BFGS with a less strict tolerance, say `1e-6` and see what happens. You could also start Powell from several random starting points and pick the best. – Ali Mar 06 '14 at 23:06
  • I tried `options={'gtol':1e-6}` but it still doesn't work. Powell with several random starting points works for this one, but for a larger problem with more parameters would take too much time. – Titanic Mar 07 '14 at 13:26
  • As a last attempt, please try BFGS with `1e-5`. By the way, I believe you would have a better luck at http://scicomp.stackexchange.com – Ali Mar 07 '14 at 13:35
  • Thanks. It won't work even if it's 1e-1. – Titanic Mar 07 '14 at 13:46
  • Sorry to hear. Please post it to http://scicomp.stackexchange.com/ somebody there can probably help. – Ali Mar 07 '14 at 13:48

0 Answers0