casact / chainladder-python

Actuarial reserving in Python
https://chainladder-python.readthedocs.io/en/latest/
Mozilla Public License 2.0
191 stars 71 forks source link

[BUG] Incorrect origin periods in non-standard Quarterly Triangles #529

Open cmds2k opened 5 months ago

cmds2k commented 5 months ago

Describe the bug The origin periods are incorrect when creating a quarterly triangle object with non-standard Quarter periods (Feb-Apr, May-Jul, Aug-Oct, Nov-Jan). IN my example below, I have non-standard quarter periods and when I try to create a Triangle object from the data, I get incorrect origin periods. The amounts seem to lagging. Compare the below image with the pandas dataframe.

image

To Reproduce Steps to reproduce the behavior. Code should be self-contained and runnable against publicly available data. For example:

import chainladder as cl
import pandas as pd
data= pd.DataFrame([
    ["5/1/2023", 12, '4/30/2024', 100],
    ["8/1/2023", 9, "4/30/2024", 130],
    ["11/1/2023", 6, "4/30/2024", 160],
    ["2/1/2024", 3, "4/30/2024", 140]], 
    columns = ['origin', 'development', 'valuation', 'EarnedPremium'])
triangle = cl.Triangle(
data, origin='origin', origin_format='%Y-%m-%d', development='valuation', columns='EarnedPremium', trailing=True, cumulative=True
)
data_from_tri = triangle.to_frame(origin_as_datetime=True)

Expected behavior: The periods seem to not match with the original data. The expected result should look something like this: image

Desktop (please complete the following information):

jbogaardt commented 5 months ago

Fantastic bug report! Thanks for finding this. Will fix in next release.

cdietrich215 commented 3 months ago

If it helps - I notice this occurs frequently when changing the grain to quarterly with the grain method, with trailing=True. Also thevaluations are potentially off as shown below. Sometimes this only occurs when the triangle HTML is displayed but the underlying dataframe is correct. Though in this example, both are incorrect:

import chainladder as cl
import pandas as pd
monthly_triangle = cl.load_sample('prism')['Incurred'].sum()
monthly_triangle = monthly_triangle[monthly_triangle.valuation<pd.to_datetime('2009-06-01')]
print( 'Monthly Triangle')
display(monthly_triangle)
print( 'Quarterly Triangle displayed as triangle object')
quarterly_triangle = monthly_triangle.grain('OQDQ',trailing=True)
display(quarterly_triangle)
display(quarterly_triangle.valuation.unique())
print( 'Quarterly Triangle displayed as dataframe')
display(quarterly_triangle.to_frame())