'''Trying out tree structure for nested logit sum is standing for likelihood calculations should collect and aggregate likelihood contributions bottom up ''' from statsmodels.compat.python import lrange import numpy as np tree = [[0,1],[[2,3],[4,5,6]],[7]] #singleton/degenerate branch needs to be list xb = 2*np.arange(8) testxb = 1 #0 def branch(tree): '''walking a tree bottom-up ''' if not isinstance(tree[0], int): #assumes leaves are int for choice index branchsum = 0 for b in tree: branchsum += branch(b) else: print(tree) print('final branch with', tree, sum(tree)) if testxb: return sum(xb[tree]) else: return sum(tree) print('working on branch', tree, branchsum) return branchsum print(branch(tree)) #new version that also keeps track of branch name and allows V_j for a branch # as in Greene, V_j + lamda * IV does not look the same as including the # explanatory variables in leaf X_j, V_j is linear in X, IV is logsumexp of X, testxb = 0#1#0 def branch2(tree): '''walking a tree bottom-up based on dictionary ''' if isinstance(tree, tuple): #assumes leaves are int for choice index name, subtree = tree print(name, data2[name]) print('subtree', subtree) if testxb: branchsum = data2[name] else: branchsum = name #0 for b in subtree: #branchsum += branch2(b) branchsum = branchsum + branch2(b) else: leavessum = sum(data2[bi] for bi in tree) print('final branch with', tree, ''.join(tree), leavessum) #sum(tree) if testxb: return leavessum #sum(xb[tree]) else: return ''.join(tree) #sum(tree) print('working on branch', tree, branchsum) return branchsum tree = [[0,1],[[2,3],[4,5,6]],[7]] tree2 = ('top', [('B1',['a','b']), ('B2', [('B21',['c', 'd']), ('B22',['e', 'f', 'g']) ] ), ('B3',['h'])] ) data2 = dict([i for i in zip('abcdefgh',lrange(8))]) #data2.update({'top':1000, 'B1':100, 'B2':200, 'B21':300,'B22':400, 'B3':400}) data2.update({'top':1000, 'B1':100, 'B2':200, 'B21':21,'B22':22, 'B3':300}) #data2 #{'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3, 'g': 6, 'f': 5, 'h': 7, #'top': 1000, 'B22': 22, 'B21': 21, 'B1': 100, 'B2': 200, 'B3': 300} print('\n tree with dictionary data') print(branch2(tree2)) # results look correct for testxb=0 and 1 #parameters/coefficients map coefficient names to indices, list of indices into #a 1d params one for each leave and branch #Note: dict looses ordering paramsind = { 'B1': [], 'a': ['consta', 'p'], 'b': ['constb', 'p'], 'B2': ['const2', 'x2'], 'B21': [], 'c': ['consta', 'p', 'time'], 'd': ['consta', 'p', 'time'], 'B22': ['x22'], 'e': ['conste', 'p', 'hince'], 'f': ['constt', 'p', 'hincf'], 'g': [ 'p', 'hincg'], 'B3': [], 'h': ['consth', 'p', 'h'], 'top': []} #unique, parameter array names, #sorted alphabetically, order is/should be only internal paramsnames = sorted({i for j in paramsind.values() for i in j}) #mapping coefficient names to indices to unique/parameter array paramsidx = {name: idx for (idx,name) in enumerate(paramsnames)} #mapping branch and leaf names to index in parameter array inddict = {k:[paramsidx[j] for j in v] for k,v in paramsind.items()} ''' >>> paramsnames ['const2', 'consta', 'constb', 'conste', 'consth', 'constt', 'h', 'hince', 'hincf', 'hincg', 'p', 'time', 'x2', 'x22'] >>> parmasidx {'conste': 3, 'consta': 1, 'constb': 2, 'h': 6, 'time': 11, 'consth': 4, 'p': 10, 'constt': 5, 'const2': 0, 'x2': 12, 'x22': 13, 'hince': 7, 'hincg': 9, 'hincf': 8} >>> inddict {'a': [1, 10], 'c': [1, 10, 11], 'b': [2, 10], 'e': [3, 10, 7], 'd': [1, 10, 11], 'g': [10, 9], 'f': [5, 10, 8], 'h': [4, 10, 6], 'top': [], 'B22': [13], 'B21': [], 'B1': [], 'B2': [0, 12], 'B3': []} >>> paramsind {'a': ['consta', 'p'], 'c': ['consta', 'p', 'time'], 'b': ['constb', 'p'], 'e': ['conste', 'p', 'hince'], 'd': ['consta', 'p', 'time'], 'g': ['p', 'hincg'], 'f': ['constt', 'p', 'hincf'], 'h': ['consth', 'p', 'h'], 'top': [], 'B22': ['x22'], 'B21': [], 'B1': [], 'B2': ['const2', 'x2'], 'B3': []} '''