Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More user-friendly way to construct LeftTruncatedModel, etc. #27

Open
21ch216 opened this issue Feb 17, 2025 · 1 comment
Open

More user-friendly way to construct LeftTruncatedModel, etc. #27

21ch216 opened this issue Feb 17, 2025 · 1 comment
Assignees

Comments

@21ch216
Copy link
Collaborator

21ch216 commented Feb 17, 2025

Currently, LeftTruncatedModel and AgeReplacementModel from relife.core.nested_model are used internally in the Policy objects, depending on the arguments passed by the user.

While these classes are not part of the user API, it could be beneficial to make them more accessible in a user-friendly way.
At present, composing the constructor like AgeReplacementModel(Weibull(...)) is the only way to create an AgeReplacementModel object. However, this composition approach can be unintuitive for users. For instance, while AFT(Weibull(...)) aligns well with the concept of function composition in mathematics, constructing AgeReplacementModel(Weibull(...)) feels more like a model transformation rather than composition, which can be confusing.

To address this, I propose the following improvement for better usability:

model = Weibull(..., left_truncated=True)  # In the backend, this would construct LeftTruncatedModel(Weibull(...))

Or

model = Weibull(..., age_replacement=True)  # In the backend, this would construct AgeReplacementModel(Weibull(...))

This behavior could be implemented by overriding the __new__ method in LifetimeModel, allowing for seamless configuration of nested models while keeping the syntax simple and intuitive for users.

@21ch216
Copy link
Collaborator Author

21ch216 commented Feb 20, 2025

One idea I had is to use the fluent interface. Here's an example:

class LifetimeModel:
    ...

    @property
    def left_truncated(self):
        return LeftTruncatedModel(self)

    @property
    def replace_at_age(self):
        return AgeReplacementModel(self)

This implementation improves code readability and simplifies its usage. For instance:

weibull = Weibull(7.0, 0.05)
weibull.left_truncated.sf(np.linspace(0, 10), 5)

In comparison, without this approach, the user would need to have explicit knowledge of the LeftTruncatedModel class and work with it directly, which is less intuitive and less concise:

weibull = LeftTruncatedModel(Weibull(7.0, 0.05))
weibull.sf(np.linspace(0, 10), 5)

By adopting the fluent interface, we encapsulate and abstract away the complexity while maintaining a clean and seamless interface.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants