From 9b7d6cfb6cdbc381af8a15057bf4529b2f58e07e Mon Sep 17 00:00:00 2001 From: Johannes Alnes Date: Fri, 15 Dec 2023 20:23:39 +0100 Subject: [PATCH 1/4] Added dataframe interchange protocol --- chainladder/core/base.py | 22 +++++++++++++++ chainladder/core/tests/test_triangle.py | 36 +++++++++++++++++++++++++ chainladder/core/triangle.py | 6 +++-- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/chainladder/core/base.py b/chainladder/core/base.py index 4362069e..960fe864 100644 --- a/chainladder/core/base.py +++ b/chainladder/core/base.py @@ -2,6 +2,8 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at https://mozilla.org/MPL/2.0/. import pandas as pd +from packaging import version + import numpy as np from chainladder.utils.cupy import cp from chainladder.utils.sparse import sp @@ -402,7 +404,27 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): return obj else: raise NotImplementedError() + + def _interchange_dataframe(self, data): + """ + Convert an object supporting the __dataframe__ protocol to a pandas DataFrame. + Requires pandas version > 1.5.2. + + Parameters: + data: Dataframe object supporting the __dataframe__ protocol. + Returns: + pd.DataFrame: A pandas DataFrame. + """ + # Check if pandas version is greater than 1.5.2 + if version.parse(pd.__version__) >= version.parse("1.5.2"): + return pd.api.interchange.from_dataframe(data) + + else: + # Raise an error prompting the user to upgrade pandas + raise NotImplementedError("Your version of pandas does not support the DataFrame interchange API. " + "Please upgrade pandas to a version greater than 1.5.2 to use this feature.") + def __array_function__(self, func, types, args, kwargs): from chainladder.utils.utility_functions import concat diff --git a/chainladder/core/tests/test_triangle.py b/chainladder/core/tests/test_triangle.py index 624c09c3..c623ff0d 100644 --- a/chainladder/core/tests/test_triangle.py +++ b/chainladder/core/tests/test_triangle.py @@ -1,5 +1,6 @@ import chainladder as cl import pandas as pd +import polars as pl import numpy as np import copy import pytest @@ -745,6 +746,9 @@ def test_halfyear_development(): ["2012-01-01", "2013-12-31", "incurred", 200.0], ] + df_polars = pl.DataFrame(data) + df_polars.columns = ["origin", "val_date", "idx", "value"] + assert ( type( cl.Triangle( @@ -757,3 +761,35 @@ def test_halfyear_development(): ) ) ) == cl.Triangle + + assert ( + type( + cl.Triangle( + data=df_polars, + index="idx", + columns="value", + origin="origin", + development="val_date", + cumulative=True, + ) + ) + ) == cl.Triangle + + assert ( + cl.Triangle( + data=pd.DataFrame(data, columns=["origin", "val_date", "idx", "value"]), + index="idx", + columns="value", + origin="origin", + development="val_date", + cumulative=True, + ) == + cl.Triangle( + data=df_polars, + index="idx", + columns="value", + origin="origin", + development="val_date", + cumulative=True, + ) + ) \ No newline at end of file diff --git a/chainladder/core/triangle.py b/chainladder/core/triangle.py index 25213529..b9e8cc0b 100644 --- a/chainladder/core/triangle.py +++ b/chainladder/core/triangle.py @@ -123,7 +123,9 @@ def __init__( ): if data is None: return - + elif not isinstance(data, pd.DataFrame) and hasattr(data, "__dataframe__"): + data = self._interchange_dataframe(data) + index, columns, origin, development = self._input_validation( data, index, columns, origin, development ) @@ -270,7 +272,7 @@ def __init__( self.ddims = obj.ddims self.values = obj.values self.valuation_date = pd.Timestamp(options.ULT_VAL) - + @staticmethod def _split_ult(data, index, columns, origin, development): """Deal with triangles with ultimate values""" From c1fc99fad5c88c7e79327ec2e4d35b56fbfc0d12 Mon Sep 17 00:00:00 2001 From: Johannes Alnes Date: Fri, 15 Dec 2023 20:34:22 +0100 Subject: [PATCH 2/4] Wrong docstring format --- chainladder/core/base.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/chainladder/core/base.py b/chainladder/core/base.py index 960fe864..9d8c3109 100644 --- a/chainladder/core/base.py +++ b/chainladder/core/base.py @@ -410,11 +410,14 @@ def _interchange_dataframe(self, data): Convert an object supporting the __dataframe__ protocol to a pandas DataFrame. Requires pandas version > 1.5.2. - Parameters: - data: Dataframe object supporting the __dataframe__ protocol. - - Returns: - pd.DataFrame: A pandas DataFrame. + Parameters + ---------- + data : + Dataframe object supporting the __dataframe__ protocol. + Returns + ------- + out: pd.DataFrame + A pandas DataFrame. """ # Check if pandas version is greater than 1.5.2 if version.parse(pd.__version__) >= version.parse("1.5.2"): From 8e395072145ee20350cd263fa0de38140923b82c Mon Sep 17 00:00:00 2001 From: Johannes Alnes Date: Fri, 15 Dec 2023 20:45:27 +0100 Subject: [PATCH 3/4] Forgot to add Polars as dependecy. Used in tests --- environment-dev.yaml | 1 + environment-docs.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/environment-dev.yaml b/environment-dev.yaml index 271c542f..06b56591 100644 --- a/environment-dev.yaml +++ b/environment-dev.yaml @@ -14,6 +14,7 @@ dependencies: - ipykernel - pandas + - polars - scikit-learn - sparse - numba diff --git a/environment-docs.yaml b/environment-docs.yaml index 031fd654..58e4d26a 100644 --- a/environment-docs.yaml +++ b/environment-docs.yaml @@ -11,6 +11,7 @@ dependencies: - git - pandas + - polars - scikit-learn - sparse - numba From 63cea7f374142551f5d29f13213b0e2b24972ee4 Mon Sep 17 00:00:00 2001 From: Johannes Alnes Date: Fri, 15 Dec 2023 20:59:15 +0100 Subject: [PATCH 4/4] Added polars to CI environments --- ci/environment-latest.yaml | 1 + ci/environment-test.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/ci/environment-latest.yaml b/ci/environment-latest.yaml index 3cdd8095..748ac087 100644 --- a/ci/environment-latest.yaml +++ b/ci/environment-latest.yaml @@ -6,6 +6,7 @@ channels: dependencies: - conda-forge::pandas>=2.0 + - polars - scikit-learn>=0.23 - sparse>=0.9 - numba diff --git a/ci/environment-test.yaml b/ci/environment-test.yaml index 24d3dd07..623492dc 100644 --- a/ci/environment-test.yaml +++ b/ci/environment-test.yaml @@ -7,6 +7,7 @@ channels: dependencies: - pandas>=0.23 + - polars>=0.16.2 - scikit-learn>=0.23 - sparse>=0.9 - numba