Closed kdzhang closed 4 months ago
I managed to modify the conditional_logit_model.py
a little bit to allow for outside option. I share it here in case others have a similar need.
First, make the item_index
for outside option to be -1. Recall that the item_index
for actual choices start from 0.
Then I modify the __init__
to add an option called outside
and register it as a field.
Modify forward
function by adding this at the end:
if self.outside:
util_zero = torch.zeros(total_utility.size(0), 1, device=batch.device)
total_utility = torch.cat((util_zero, total_utility), dim=1)
And modify the negative_log_likelihood
function by adding this before the total_utility
calculation:
# if outside option exists, need to adjust y to match the dimension of total_utility
y_new = y.clone()
if self.outside:
# move all actual choices starting from 1
# empty index (outside option) is 0
y_new[y_new<0] = -1
y_new+=1
Then you can get point estimates by estimating as usual. Remember to set outside=True
in model initiation.
To get proper std, we need to change the run
function in run_helper_lightning.py
if isinstance(model, ConditionalLogitModel):
def nll_loss(model):
y_pred = model(dataset_for_std)
# modify item_index to accomodate the outside option
if model.outside:
item_index_new = dataset_for_std.item_index + 1
else:
item_index_new = dataset_for_std.item_index
return F.cross_entropy(y_pred, item_index_new, reduction='sum')
Then you should be able to get the std as well.
This is a hacky solution of course. I would very much appreciate it if the author has a better solution.
Hey Kaida, thank you for your question and awesome solution to it! Your solution looks pretty elegant to me; for other users to utilize what you implemented, shall we make a pull request to integrate your implementation into the main branch? I could make the PR and acknowledge you in the PR, or you could do it if you prefer to have your contribution shown on GitHub.
Thank you for your contribution!
Hi Tianyu, thank you for your kinds words! Feel free to make the PR, I think you are the best person to do it as you know the edges of this package better. I am more than happy to contribute wherever I can. Regarding the feature, I think there is a bit more work left:
outside
option is on, then item_index
must start from -1. Again, thank you for writing this great package!
I have attached a new branch to this thread to implement the outside option for conditional logit models. Kaida's preliminary solution was awesome, and I made a couple of modifications:
total_utility
so that total_utility[:, 0] = 0
. Since the outside option is indicated by item_index = -1
, I have appended the outside option zero utility so that total_utility[:, -1] = 0
in the current implementation. This would make the indexing easier. For example, suppose total_utility
has the shape N*(num_items+1)
, in which the last column corresponds to the zero utility of the outside option. Suppose item_index
has shape N
with some -1
value in it to indicate outside option was chosen; then total_utility[range(item_index), item_index]
could retrieve the utility for both real items and the outside option without modifying the item_index
.I am currently testing the implementation, and @kanodiaayush you can find the latest progress in the pull request here: https://github.com/gsbDBI/torch-choice/pull/42
@kanodiaayush Does this make sense to you?
Here is a demonstration of using the outside option for condition logit models: https://github.com/gsbDBI/torch-choice/blob/41-how-to-model-outside-option/tutorials/outside_option.ipynb
I am working on testing if this works for nested regressions.
I have implemented the outside option for nested logit model as well (see the updated pull request), @kanodiaayush could you please review it?
First, thank you for this great package!
I wonder if there is a way to model outside option in the package? For example, it is possible that the user buys nothing in a visit. One hacky solution I have is to force all
item_obs
anduser_item_obs
to be zero for the outside option. But this approach cannot handlesession_obs
unless we make everysession_obs
to besession_item_obs
.According to the following comment in this issue, it seems that there is a way to formally model outside option. I am good with normalizing it to 0 in each category. I very much appreciate it if you can give me some guidance on how to do this. Thank you!