We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
EHN: let pipeline support return `Series`
<!--
Thanks for contributing a pull request!

Please follow these standard acronyms to start the commit message:

- ENH: enhancement
- BUG: bug fix
- DOC: documentation
- TYP: type annotations
- TST: addition or modification of tests
- MAINT: maintenance commit (refactoring, typos, etc.)
- BLD: change related to building
- REL: related to releasing
- API: an (incompatible) API change
- DEP: deprecate something, or remove a deprecated object
- DEV: development tool or utility
- REV: revert an earlier commit
- PERF: performance improvement
- BOT: always commit via a bot
- CI: related to CI or CD
- CLN: Code cleanup
-->

- [x] closes #380
- [x] whatsnew entry

The transformer is in charge of the specific transforming method.
The pipeline is in charge of connecting results from each transformer.

I don't want to rewrite every transformer, let them support dataframe or series data structure. 
So pipeline should be rebuilt. If the inputting of a transformer from the last transformer is dataframe or series, its outputting should be dataframe or series too.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `dtoolkit/transformer/sklearn.py`
Content:
```
1 from __future__ import annotations
2 
3 from textwrap import dedent
4 from typing import TYPE_CHECKING
5 
6 import numpy as np
7 import pandas as pd
8 from pandas.util._decorators import doc
9 from sklearn.preprocessing import MinMaxScaler as SKMinMaxScaler
10 from sklearn.preprocessing import OneHotEncoder as SKOneHotEncoder
11 
12 from dtoolkit.accessor.dataframe import cols  # noqa
13 from dtoolkit.accessor.series import cols  # noqa
14 from dtoolkit.transformer._util import transform_array_to_frame
15 from dtoolkit.transformer._util import transform_frame_to_series
16 from dtoolkit.transformer._util import transform_series_to_frame
17 
18 if TYPE_CHECKING:
19     from scipy.sparse import csr_matrix
20 
21     from dtoolkit._typing import SeriesOrFrame
22     from dtoolkit._typing import TwoDimArray
23 
24 
25 class MinMaxScaler(SKMinMaxScaler):
26     """
27     Transform features by scaling each feature to a given range.
28 
29     The transformation is given by::
30 
31         X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
32         X_scaled = X_std * (max - min) + min
33 
34     where :exc:`min, max = feature_range`.
35 
36     Examples
37     --------
38     >>> from dtoolkit.transformer import MinMaxScaler
39     >>> data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
40     >>> scaler = MinMaxScaler()
41     >>> scaler.fit(data)
42     MinMaxScaler()
43     >>> scaler.data_max_
44     array([ 1., 18.])
45     >>> scaler.transform(data)
46     array([[0.  , 0.  ],
47            [0.25, 0.25],
48            [0.5 , 0.5 ],
49            [1.  , 1.  ]])
50     >>> scaler.transform([[2, 2]])
51     array([[1.5, 0. ]])
52 
53     Notes
54     -----
55     Different to :obj:`sklearn.preprocessing.MinMaxScaler`.
56     This would let :obj:`~pandas.DataFrame` in and
57     :obj:`~pandas.DataFrame` out.
58     """
59 
60     @doc(SKMinMaxScaler.fit)
61     def fit(self, X, y=None):
62         X = transform_series_to_frame(X)
63 
64         return super().fit(X, y)
65 
66     def transform(self, X: TwoDimArray) -> TwoDimArray:
67         """
68         Scale features of X according to feature_range.
69 
70         Parameters
71         ----------
72         X : DataFrame or array-like of shape `(n_samples, n_features)`
73             Input data that will be transformed.
74 
75         Returns
76         -------
77         DataFrame or ndarray of shape `(n_samples, n_features)`
78             Transformed data.
79 
80         Notes
81         -----
82         This would let :obj:`~pandas.DataFrame` in and
83         :obj:`~pandas.DataFrame` out.
84         """
85 
86         X = transform_series_to_frame(X)
87         Xt = super().transform(X)
88         Xt = transform_array_to_frame(Xt, X)
89 
90         return transform_frame_to_series(Xt)
91 
92     def inverse_transform(self, X: SeriesOrFrame | np.ndarray) -> TwoDimArray:
93         """
94         Undo the scaling of X according to feature_range.
95 
96         Parameters
97         ----------
98         X : Series, DataFrame or array-like of shape `(n_samples, n_features)`
99             Input data that will be transformed. It cannot be sparse.
100 
101         Returns
102         -------
103         DataFrame or ndarray of shape (n_samples, n_features)
104             Transformed data.
105 
106         Notes
107         -----
108         This would let :obj:`~pandas.DataFrame` in and
109         :obj:`~pandas.DataFrame` out.
110         """
111 
112         X = transform_series_to_frame(X)
113         Xt = super().inverse_transform(X)
114         Xt = transform_array_to_frame(Xt, X)
115 
116         return transform_frame_to_series(Xt)
117 
118 
119 class OneHotEncoder(SKOneHotEncoder):
120     """
121     Encode categorical features as a one-hot numeric array.
122 
123     Parameters
124     ----------
125     categories_with_parent : bool, default False
126         Returned column would hook parent labels if ``True`` else
127         would be ``categories``.
128 
129     sparse : bool, default False
130         Will return sparse matrix if ``True`` else will return an array.
131 
132     kwargs
133         See :obj:`sklearn.preprocessing.OneHotEncoder`.
134 
135     Notes
136     -----
137     Different to :obj:`sklearn.preprocessing.OneHotEncoder`.
138     The result would return a :obj:`~pandas.DataFrame` which uses categories
139     as columns.
140 
141     Examples
142     --------
143     Given a dataset with two features, we let the encoder find the unique
144     values per feature and transform the data to a binary one-hot encoding.
145 
146     :obj:`~pandas.DataFrame` in, :obj:`~pandas.DataFrame` out with categories
147     as columns.
148 
149     >>> from dtoolkit.transformer import OneHotEncoder
150     >>> import pandas as pd
151     >>> X = [['Male', 1], ['Female', 3], ['Female', 2]]
152     >>> df = pd.DataFrame(X, columns=['gender', 'number'])
153     >>> df
154         gender  number
155     0    Male       1
156     1  Female       3
157     2  Female       2
158     >>> enc = OneHotEncoder()
159     >>> enc.fit_transform(df)
160        Female  Male    1    2    3
161     0     0.0   1.0  1.0  0.0  0.0
162     1     1.0   0.0  0.0  0.0  1.0
163     2     1.0   0.0  0.0  1.0  0.0
164 
165     The encoded data also could hook parent labels.
166 
167     >>> enc = OneHotEncoder(categories_with_parent=True)
168     >>> enc.fit_transform(df)
169        gender_Female  gender_Male  number_1  number_2  number_3
170     0            0.0          1.0       1.0       0.0       0.0
171     1            1.0          0.0       0.0       0.0       1.0
172     2            1.0          0.0       0.0       1.0       0.0
173     """
174 
175     @doc(SKOneHotEncoder.__init__)
176     def __init__(
177         self,
178         categories_with_parent: bool = False,
179         sparse: bool = False,
180         **kwargs,
181     ):
182         super().__init__(sparse=sparse, **kwargs)
183         self.categories_with_parent = categories_with_parent
184 
185     @doc(
186         SKOneHotEncoder.transform,
187         dedent(
188             """
189         Notes
190         -----
191         This would let :obj:`~pandas.DataFrame` out.
192         """,
193         ),
194     )
195     def transform(self, X: TwoDimArray) -> TwoDimArray | csr_matrix:
196         from itertools import chain
197 
198         Xt = super().transform(X)
199 
200         if self.sparse is False:
201             categories = (
202                 self.get_feature_names_out(X.cols())
203                 if self.categories_with_parent
204                 else chain.from_iterable(self.categories_)
205             )
206 
207             return pd.DataFrame(Xt, columns=categories)
208 
209         return Xt
210
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/dtoolkit/transformer/sklearn.py b/dtoolkit/transformer/sklearn.py
--- a/dtoolkit/transformer/sklearn.py
+++ b/dtoolkit/transformer/sklearn.py
@@ -26,6 +26,12 @@
     """
     Transform features by scaling each feature to a given range.
 
+    .. warning::
+        Transformer :class:`dtoolkit.transformer.MinMaxScaler` is deprecated and
+        will be removed in 0.0.13.
+        Please use :class:`sklearn.preprocessing.MinMaxScaler` instead.
+        (Warning added DToolKit 0.0.12)
+
     The transformation is given by::
 
         X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
@@ -57,6 +63,24 @@
     :obj:`~pandas.DataFrame` out.
     """
 
+    @doc(SKMinMaxScaler.__init__)
+    def __init__(self, feature_range=(0, 1), *, copy=True, clip=False):
+        from warnings import warn
+
+        warn(
+            "Transformer 'dtoolkit.transformer.MinMaxScaler' is deprecated and "
+            "will be removed in 0.0.13. "
+            "Please use 'sklearn.preprocessing.MinMaxScaler' instead. "
+            "(Warning added DToolKit 0.0.12)",
+            DeprecationWarning,
+        )
+
+        super().__init__(
+            feature_range=feature_range,
+            copy=copy,
+            clip=clip,
+        )
+
     @doc(SKMinMaxScaler.fit)
     def fit(self, X, y=None):
         X = transform_series_to_frame(X)

{"golden_diff": "diff --git a/dtoolkit/transformer/sklearn.py b/dtoolkit/transformer/sklearn.py\n--- a/dtoolkit/transformer/sklearn.py\n+++ b/dtoolkit/transformer/sklearn.py\n@@ -26,6 +26,12 @@\n     \"\"\"\n     Transform features by scaling each feature to a given range.\n \n+    .. warning::\n+        Transformer :class:`dtoolkit.transformer.MinMaxScaler` is deprecated and\n+        will be removed in 0.0.13.\n+        Please use :class:`sklearn.preprocessing.MinMaxScaler` instead.\n+        (Warning added DToolKit 0.0.12)\n+\n     The transformation is given by::\n \n         X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))\n@@ -57,6 +63,24 @@\n     :obj:`~pandas.DataFrame` out.\n     \"\"\"\n \n+    @doc(SKMinMaxScaler.__init__)\n+    def __init__(self, feature_range=(0, 1), *, copy=True, clip=False):\n+        from warnings import warn\n+\n+        warn(\n+            \"Transformer 'dtoolkit.transformer.MinMaxScaler' is deprecated and \"\n+            \"will be removed in 0.0.13. \"\n+            \"Please use 'sklearn.preprocessing.MinMaxScaler' instead. \"\n+            \"(Warning added DToolKit 0.0.12)\",\n+            DeprecationWarning,\n+        )\n+\n+        super().__init__(\n+            feature_range=feature_range,\n+            copy=copy,\n+            clip=clip,\n+        )\n+\n     @doc(SKMinMaxScaler.fit)\n     def fit(self, X, y=None):\n         X = transform_series_to_frame(X)\n", "issue": "EHN: let pipeline support return `Series`\n<!--\r\nThanks for contributing a pull request!\r\n\r\nPlease follow these standard acronyms to start the commit message:\r\n\r\n- ENH: enhancement\r\n- BUG: bug fix\r\n- DOC: documentation\r\n- TYP: type annotations\r\n- TST: addition or modification of tests\r\n- MAINT: maintenance commit (refactoring, typos, etc.)\r\n- BLD: change related to building\r\n- REL: related to releasing\r\n- API: an (incompatible) API change\r\n- DEP: deprecate something, or remove a deprecated object\r\n- DEV: development tool or utility\r\n- REV: revert an earlier commit\r\n- PERF: performance improvement\r\n- BOT: always commit via a bot\r\n- CI: related to CI or CD\r\n- CLN: Code cleanup\r\n-->\r\n\r\n- [x] closes #380\r\n- [x] whatsnew entry\r\n\r\nThe transformer is in charge of the specific transforming method.\r\nThe pipeline is in charge of connecting results from each transformer.\r\n\r\nI don't want to rewrite every transformer, let them support dataframe or series data structure. \r\nSo pipeline should be rebuilt. If the inputting of a transformer from the last transformer is dataframe or series, its outputting should be dataframe or series too.\n", "before_files": [{"content": "from __future__ import annotations\n\nfrom textwrap import dedent\nfrom typing import TYPE_CHECKING\n\nimport numpy as np\nimport pandas as pd\nfrom pandas.util._decorators import doc\nfrom sklearn.preprocessing import MinMaxScaler as SKMinMaxScaler\nfrom sklearn.preprocessing import OneHotEncoder as SKOneHotEncoder\n\nfrom dtoolkit.accessor.dataframe import cols  # noqa\nfrom dtoolkit.accessor.series import cols  # noqa\nfrom dtoolkit.transformer._util import transform_array_to_frame\nfrom dtoolkit.transformer._util import transform_frame_to_series\nfrom dtoolkit.transformer._util import transform_series_to_frame\n\nif TYPE_CHECKING:\n    from scipy.sparse import csr_matrix\n\n    from dtoolkit._typing import SeriesOrFrame\n    from dtoolkit._typing import TwoDimArray\n\n\nclass MinMaxScaler(SKMinMaxScaler):\n    \"\"\"\n    Transform features by scaling each feature to a given range.\n\n    The transformation is given by::\n\n        X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))\n        X_scaled = X_std * (max - min) + min\n\n    where :exc:`min, max = feature_range`.\n\n    Examples\n    --------\n    >>> from dtoolkit.transformer import MinMaxScaler\n    >>> data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]\n    >>> scaler = MinMaxScaler()\n    >>> scaler.fit(data)\n    MinMaxScaler()\n    >>> scaler.data_max_\n    array([ 1., 18.])\n    >>> scaler.transform(data)\n    array([[0.  , 0.  ],\n           [0.25, 0.25],\n           [0.5 , 0.5 ],\n           [1.  , 1.  ]])\n    >>> scaler.transform([[2, 2]])\n    array([[1.5, 0. ]])\n\n    Notes\n    -----\n    Different to :obj:`sklearn.preprocessing.MinMaxScaler`.\n    This would let :obj:`~pandas.DataFrame` in and\n    :obj:`~pandas.DataFrame` out.\n    \"\"\"\n\n    @doc(SKMinMaxScaler.fit)\n    def fit(self, X, y=None):\n        X = transform_series_to_frame(X)\n\n        return super().fit(X, y)\n\n    def transform(self, X: TwoDimArray) -> TwoDimArray:\n        \"\"\"\n        Scale features of X according to feature_range.\n\n        Parameters\n        ----------\n        X : DataFrame or array-like of shape `(n_samples, n_features)`\n            Input data that will be transformed.\n\n        Returns\n        -------\n        DataFrame or ndarray of shape `(n_samples, n_features)`\n            Transformed data.\n\n        Notes\n        -----\n        This would let :obj:`~pandas.DataFrame` in and\n        :obj:`~pandas.DataFrame` out.\n        \"\"\"\n\n        X = transform_series_to_frame(X)\n        Xt = super().transform(X)\n        Xt = transform_array_to_frame(Xt, X)\n\n        return transform_frame_to_series(Xt)\n\n    def inverse_transform(self, X: SeriesOrFrame | np.ndarray) -> TwoDimArray:\n        \"\"\"\n        Undo the scaling of X according to feature_range.\n\n        Parameters\n        ----------\n        X : Series, DataFrame or array-like of shape `(n_samples, n_features)`\n            Input data that will be transformed. It cannot be sparse.\n\n        Returns\n        -------\n        DataFrame or ndarray of shape (n_samples, n_features)\n            Transformed data.\n\n        Notes\n        -----\n        This would let :obj:`~pandas.DataFrame` in and\n        :obj:`~pandas.DataFrame` out.\n        \"\"\"\n\n        X = transform_series_to_frame(X)\n        Xt = super().inverse_transform(X)\n        Xt = transform_array_to_frame(Xt, X)\n\n        return transform_frame_to_series(Xt)\n\n\nclass OneHotEncoder(SKOneHotEncoder):\n    \"\"\"\n    Encode categorical features as a one-hot numeric array.\n\n    Parameters\n    ----------\n    categories_with_parent : bool, default False\n        Returned column would hook parent labels if ``True`` else\n        would be ``categories``.\n\n    sparse : bool, default False\n        Will return sparse matrix if ``True`` else will return an array.\n\n    kwargs\n        See :obj:`sklearn.preprocessing.OneHotEncoder`.\n\n    Notes\n    -----\n    Different to :obj:`sklearn.preprocessing.OneHotEncoder`.\n    The result would return a :obj:`~pandas.DataFrame` which uses categories\n    as columns.\n\n    Examples\n    --------\n    Given a dataset with two features, we let the encoder find the unique\n    values per feature and transform the data to a binary one-hot encoding.\n\n    :obj:`~pandas.DataFrame` in, :obj:`~pandas.DataFrame` out with categories\n    as columns.\n\n    >>> from dtoolkit.transformer import OneHotEncoder\n    >>> import pandas as pd\n    >>> X = [['Male', 1], ['Female', 3], ['Female', 2]]\n    >>> df = pd.DataFrame(X, columns=['gender', 'number'])\n    >>> df\n        gender  number\n    0    Male       1\n    1  Female       3\n    2  Female       2\n    >>> enc = OneHotEncoder()\n    >>> enc.fit_transform(df)\n       Female  Male    1    2    3\n    0     0.0   1.0  1.0  0.0  0.0\n    1     1.0   0.0  0.0  0.0  1.0\n    2     1.0   0.0  0.0  1.0  0.0\n\n    The encoded data also could hook parent labels.\n\n    >>> enc = OneHotEncoder(categories_with_parent=True)\n    >>> enc.fit_transform(df)\n       gender_Female  gender_Male  number_1  number_2  number_3\n    0            0.0          1.0       1.0       0.0       0.0\n    1            1.0          0.0       0.0       0.0       1.0\n    2            1.0          0.0       0.0       1.0       0.0\n    \"\"\"\n\n    @doc(SKOneHotEncoder.__init__)\n    def __init__(\n        self,\n        categories_with_parent: bool = False,\n        sparse: bool = False,\n        **kwargs,\n    ):\n        super().__init__(sparse=sparse, **kwargs)\n        self.categories_with_parent = categories_with_parent\n\n    @doc(\n        SKOneHotEncoder.transform,\n        dedent(\n            \"\"\"\n        Notes\n        -----\n        This would let :obj:`~pandas.DataFrame` out.\n        \"\"\",\n        ),\n    )\n    def transform(self, X: TwoDimArray) -> TwoDimArray | csr_matrix:\n        from itertools import chain\n\n        Xt = super().transform(X)\n\n        if self.sparse is False:\n            categories = (\n                self.get_feature_names_out(X.cols())\n                if self.categories_with_parent\n                else chain.from_iterable(self.categories_)\n            )\n\n            return pd.DataFrame(Xt, columns=categories)\n\n        return Xt\n", "path": "dtoolkit/transformer/sklearn.py"}], "after_files": [{"content": "from __future__ import annotations\n\nfrom textwrap import dedent\nfrom typing import TYPE_CHECKING\n\nimport numpy as np\nimport pandas as pd\nfrom pandas.util._decorators import doc\nfrom sklearn.preprocessing import MinMaxScaler as SKMinMaxScaler\nfrom sklearn.preprocessing import OneHotEncoder as SKOneHotEncoder\n\nfrom dtoolkit.accessor.dataframe import cols  # noqa\nfrom dtoolkit.accessor.series import cols  # noqa\nfrom dtoolkit.transformer._util import transform_array_to_frame\nfrom dtoolkit.transformer._util import transform_frame_to_series\nfrom dtoolkit.transformer._util import transform_series_to_frame\n\nif TYPE_CHECKING:\n    from scipy.sparse import csr_matrix\n\n    from dtoolkit._typing import SeriesOrFrame\n    from dtoolkit._typing import TwoDimArray\n\n\nclass MinMaxScaler(SKMinMaxScaler):\n    \"\"\"\n    Transform features by scaling each feature to a given range.\n\n    .. warning::\n        Transformer :class:`dtoolkit.transformer.MinMaxScaler` is deprecated and\n        will be removed in 0.0.13.\n        Please use :class:`sklearn.preprocessing.MinMaxScaler` instead.\n        (Warning added DToolKit 0.0.12)\n\n    The transformation is given by::\n\n        X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))\n        X_scaled = X_std * (max - min) + min\n\n    where :exc:`min, max = feature_range`.\n\n    Examples\n    --------\n    >>> from dtoolkit.transformer import MinMaxScaler\n    >>> data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]\n    >>> scaler = MinMaxScaler()\n    >>> scaler.fit(data)\n    MinMaxScaler()\n    >>> scaler.data_max_\n    array([ 1., 18.])\n    >>> scaler.transform(data)\n    array([[0.  , 0.  ],\n           [0.25, 0.25],\n           [0.5 , 0.5 ],\n           [1.  , 1.  ]])\n    >>> scaler.transform([[2, 2]])\n    array([[1.5, 0. ]])\n\n    Notes\n    -----\n    Different to :obj:`sklearn.preprocessing.MinMaxScaler`.\n    This would let :obj:`~pandas.DataFrame` in and\n    :obj:`~pandas.DataFrame` out.\n    \"\"\"\n\n    @doc(SKMinMaxScaler.__init__)\n    def __init__(self, feature_range=(0, 1), *, copy=True, clip=False):\n        from warnings import warn\n\n        warn(\n            \"Transformer 'dtoolkit.transformer.MinMaxScaler' is deprecated and \"\n            \"will be removed in 0.0.13. \"\n            \"Please use 'sklearn.preprocessing.MinMaxScaler' instead. \"\n            \"(Warning added DToolKit 0.0.12)\",\n            DeprecationWarning,\n        )\n\n        super().__init__(\n            feature_range=feature_range,\n            copy=copy,\n            clip=clip,\n        )\n\n    @doc(SKMinMaxScaler.fit)\n    def fit(self, X, y=None):\n        X = transform_series_to_frame(X)\n\n        return super().fit(X, y)\n\n    def transform(self, X: TwoDimArray) -> TwoDimArray:\n        \"\"\"\n        Scale features of X according to feature_range.\n\n        Parameters\n        ----------\n        X : DataFrame or array-like of shape `(n_samples, n_features)`\n            Input data that will be transformed.\n\n        Returns\n        -------\n        DataFrame or ndarray of shape `(n_samples, n_features)`\n            Transformed data.\n\n        Notes\n        -----\n        This would let :obj:`~pandas.DataFrame` in and\n        :obj:`~pandas.DataFrame` out.\n        \"\"\"\n\n        X = transform_series_to_frame(X)\n        Xt = super().transform(X)\n        Xt = transform_array_to_frame(Xt, X)\n\n        return transform_frame_to_series(Xt)\n\n    def inverse_transform(self, X: SeriesOrFrame | np.ndarray) -> TwoDimArray:\n        \"\"\"\n        Undo the scaling of X according to feature_range.\n\n        Parameters\n        ----------\n        X : Series, DataFrame or array-like of shape `(n_samples, n_features)`\n            Input data that will be transformed. It cannot be sparse.\n\n        Returns\n        -------\n        DataFrame or ndarray of shape (n_samples, n_features)\n            Transformed data.\n\n        Notes\n        -----\n        This would let :obj:`~pandas.DataFrame` in and\n        :obj:`~pandas.DataFrame` out.\n        \"\"\"\n\n        X = transform_series_to_frame(X)\n        Xt = super().inverse_transform(X)\n        Xt = transform_array_to_frame(Xt, X)\n\n        return transform_frame_to_series(Xt)\n\n\nclass OneHotEncoder(SKOneHotEncoder):\n    \"\"\"\n    Encode categorical features as a one-hot numeric array.\n\n    Parameters\n    ----------\n    categories_with_parent : bool, default False\n        Returned column would hook parent labels if ``True`` else\n        would be ``categories``.\n\n    sparse : bool, default False\n        Will return sparse matrix if ``True`` else will return an array.\n\n    kwargs\n        See :obj:`sklearn.preprocessing.OneHotEncoder`.\n\n    Notes\n    -----\n    Different to :obj:`sklearn.preprocessing.OneHotEncoder`.\n    The result would return a :obj:`~pandas.DataFrame` which uses categories\n    as columns.\n\n    Examples\n    --------\n    Given a dataset with two features, we let the encoder find the unique\n    values per feature and transform the data to a binary one-hot encoding.\n\n    :obj:`~pandas.DataFrame` in, :obj:`~pandas.DataFrame` out with categories\n    as columns.\n\n    >>> from dtoolkit.transformer import OneHotEncoder\n    >>> import pandas as pd\n    >>> X = [['Male', 1], ['Female', 3], ['Female', 2]]\n    >>> df = pd.DataFrame(X, columns=['gender', 'number'])\n    >>> df\n        gender  number\n    0    Male       1\n    1  Female       3\n    2  Female       2\n    >>> enc = OneHotEncoder()\n    >>> enc.fit_transform(df)\n       Female  Male    1    2    3\n    0     0.0   1.0  1.0  0.0  0.0\n    1     1.0   0.0  0.0  0.0  1.0\n    2     1.0   0.0  0.0  1.0  0.0\n\n    The encoded data also could hook parent labels.\n\n    >>> enc = OneHotEncoder(categories_with_parent=True)\n    >>> enc.fit_transform(df)\n       gender_Female  gender_Male  number_1  number_2  number_3\n    0            0.0          1.0       1.0       0.0       0.0\n    1            1.0          0.0       0.0       0.0       1.0\n    2            1.0          0.0       0.0       1.0       0.0\n    \"\"\"\n\n    @doc(SKOneHotEncoder.__init__)\n    def __init__(\n        self,\n        categories_with_parent: bool = False,\n        sparse: bool = False,\n        **kwargs,\n    ):\n        super().__init__(sparse=sparse, **kwargs)\n        self.categories_with_parent = categories_with_parent\n\n    @doc(\n        SKOneHotEncoder.transform,\n        dedent(\n            \"\"\"\n        Notes\n        -----\n        This would let :obj:`~pandas.DataFrame` out.\n        \"\"\",\n        ),\n    )\n    def transform(self, X: TwoDimArray) -> TwoDimArray | csr_matrix:\n        from itertools import chain\n\n        Xt = super().transform(X)\n\n        if self.sparse is False:\n            categories = (\n                self.get_feature_names_out(X.cols())\n                if self.categories_with_parent\n                else chain.from_iterable(self.categories_)\n            )\n\n            return pd.DataFrame(Xt, columns=categories)\n\n        return Xt\n", "path": "dtoolkit/transformer/sklearn.py"}]}