time-split 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
time_split/settings.py ADDED
@@ -0,0 +1,172 @@
1
+ """Global settings for the splitting logic."""
2
+
3
+ import typing as _t
4
+
5
+ from . import types as _tst
6
+
7
+
8
+ class auto_flex: # noqa: N801
9
+ """Configuration for the `'auto'` :attr:`~time_split.types.Flex` logic.
10
+
11
+ This class determines how ``(lo, hi)``-tuples are expanded when flexible bounds are enabled.
12
+ """
13
+
14
+ SANITY_CHECK: bool = True
15
+ """If ``True``, use original limits if flexed limits do not pass sanity checks."""
16
+
17
+ @classmethod
18
+ def set_level(
19
+ cls,
20
+ level: _t.Literal["hour", "day"],
21
+ *,
22
+ start_at: _tst.TimedeltaTypes,
23
+ round_to: _tst.TimedeltaTypes,
24
+ tolerance: _tst.TimedeltaTypes,
25
+ ) -> None:
26
+ """Set a :class:`Level` used by the auto-flex logic.
27
+
28
+ Inputs are not verified until an actual split is made.
29
+
30
+ Args:
31
+ level: The level to set; `'hour'` or `'day'`.
32
+ start_at: Span size at which this level starts.
33
+ round_to: Frequency to round the range limits to.
34
+ tolerance: Maximum amount by which to alter limits.
35
+
36
+ Raises:
37
+ AttributeError: For unknown `level` names.
38
+
39
+ """
40
+ if level not in {"hour", "day"}:
41
+ raise AttributeError(f"Bad {level=}: Expected one of ('hour', 'day').")
42
+ level_tuple = (start_at, round_to, tolerance)
43
+ setattr(cls, level, level_tuple)
44
+
45
+ class Level(_t.NamedTuple):
46
+ """Level type used by :attr:`auto_flex`."""
47
+
48
+ start_at: _tst.TimedeltaTypes
49
+ """Span size at which this level starts."""
50
+
51
+ round_to: _tst.TimedeltaTypes
52
+ """Frequency to round the range limits to."""
53
+
54
+ tolerance: _tst.TimedeltaTypes
55
+ """Maximum amount by which to alter limits."""
56
+
57
+ hour: Level = Level("6 hours", "hour", "15 min")
58
+ """Conditions under which bounds are rounded to the nearest hour.
59
+
60
+ Default setting:
61
+ Round to hour if the total range is at least 6 hours, but do not move the bounds more than 15 minutes.
62
+ """
63
+
64
+ day: Level = Level("2 days", "day", "3 hours")
65
+ """Conditions under which bounds are rounded to the nearest day.
66
+
67
+ Default setting:
68
+ Round to day if the total range is at least 2 days, but do not move the bounds more than 3 hours.
69
+ """
70
+
71
+
72
+ class plot: # noqa: N801
73
+ """Global settings for the :func:`.time_split.plot`-function."""
74
+
75
+ THOUSANDS_SEPARATOR: str = "'"
76
+ """Separator to use when printing `bar_labels`."""
77
+ THOUSANDS_SEPARATOR_CUTOFF: int = 10_000
78
+ """Minimum value before `bar_labels` include a :attr:`THOUSANDS_SEPARATOR`."""
79
+ ROW_UNIT: str = "rows"
80
+ """Unit to append to the count when displaying number of rows on the bars."""
81
+
82
+ DATA_LABEL: str = "Data"
83
+ """Label of the blue bar; data in the the [:attr:`~.DatetimeSplitBounds.start`, :attr:`~.types.DatetimeSplitBounds.mid`)-range."""
84
+ FUTURE_DATA_LABEL: str = "Future data"
85
+ """Label of the red bar; data in the the [:attr:`~.DatetimeSplitBounds.mid`, :attr:`~.types.DatetimeSplitBounds.end`)-range."""
86
+
87
+ DEFAULT_TIME_UNIT: str = "h"
88
+ """Time unit to use by default when ``bar_labels=True`` and ``available=None``."""
89
+
90
+ REMOVED_FOLD_STYLE: _t.ClassVar[dict[str, _t.Any]] = {
91
+ "alpha": 0.35,
92
+ "height": 0.6,
93
+ }
94
+ """Keyword arguments used to distinguish filtered folds when plotting with ``show_removed=True``.
95
+
96
+ See :func:`matplotlib.pyplot.bar` for details.
97
+ """
98
+
99
+
100
+ class log_split_progress: # noqa: N801
101
+ """Global settings for the :func:`.log_split_progress`-function."""
102
+
103
+ FOLD_FORMAT: str = "'{start.auto}' <= [schedule: '{mid.auto}' ({mid:%A})] < '{end.auto}'"
104
+ """Pretty-printed `fold`-key for other messages.
105
+
106
+ * Only the ``start``, ``mid``, and ``end`` keys are available (see
107
+ :attr:`~time_split.types.DatetimeSplitBounds`). You may use ``<key>.auto`` to format as a date when
108
+ time is zero (this is the default).
109
+
110
+ .. code-block:: python
111
+ :caption: Sample output.
112
+
113
+ '2021-12-30' <= [schedule: '2022-01-04' (Tuesday)] < '2022-01-04 18:00:00'
114
+ """
115
+
116
+ SECONDS_FORMATTER: str | _t.Callable[[float], str] = "rics.performance.format_seconds"
117
+ """A callable ``(seconds) -> formatted_seconds``.
118
+
119
+ Both ``seconds`` and ``formatted_seconds`` will be available to the :attr:`END_MESSAGE` message. If a string is
120
+ given, the actual callable will be resolved using :func:`rics.misc.get_by_full_name`.
121
+ """
122
+
123
+ START_MESSAGE: str = "Begin fold {n}/{n_splits}: {fold}."
124
+ """Message indicating that the current fold has been yielded to the user.
125
+
126
+ Has access to all keys from the previous section, as well as:
127
+
128
+ * The ``fold`` key (see :attr:`FOLD_FORMAT`), and
129
+ * The ``n`` key, which is the 1-based position of the fold in `splits`, and
130
+ * The ``n_folds`` key, which is just ``len(splits)``.
131
+
132
+ .. code-block:: python
133
+ :caption: Sample output.
134
+
135
+ Begin fold 5/7: '2021-12-30' <= [schedule: '2022-01-04' (Tuesday)] < '2022-01-04 18:00:00'.
136
+ """
137
+
138
+ END_MESSAGE: str = "Finished fold {n}/{n_splits}: [schedule: '{mid.auto}' ({mid:%A})] after {formatted_seconds}."
139
+ """Message indicating that the user is done with the current fold.
140
+
141
+ Has access to all keys from the previous sections, as well as:
142
+
143
+ * The ``seconds`` key, which is the (fractional) time the user spent in the fold, and
144
+ * The ``formatted_seconds`` key, obtained using the :attr:`SECONDS_FORMATTER`.
145
+
146
+ The value of ``seconds`` is obtained using :py:func:`time.perf_counter`.
147
+
148
+ .. code-block:: python
149
+ :caption: Sample output.
150
+
151
+ Finished fold 5/7: [schedule: '2022-01-04' (Tuesday)] after 5m 21s.
152
+ """
153
+
154
+ AUTO_DATE_FORMAT = "%Y-%m-%d"
155
+ """Short-form timestamp format_spec used by ``<key>.auto``."""
156
+ AUTO_DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
157
+ """Long-form timestamp format_spec used by ``<key>.auto``."""
158
+
159
+
160
+ class misc: # noqa: N801
161
+ """Miscellaneous settings that don't fit in any other namespace."""
162
+
163
+ snap_to_end: bool = True
164
+ """Controls alignment of timedelta-based splits.
165
+
166
+ .. note::
167
+
168
+ Active only when both `schedule` and `after` are :attr:`~time_split.types.TimedeltaTypes`.
169
+
170
+ If ``True``, ensure that the `Future data` of the final fold ends at the rightmost edge of the available data range.
171
+ Otherwise, alignment is determined by :func:`pandas.date_range`.
172
+ """
@@ -0,0 +1,21 @@
1
+ """Supporting functions.
2
+
3
+ These functions are used internally, but are exposed here as well so that user may create their own logic using the
4
+ internal logic, or just to test things out.
5
+
6
+ .. warning::
7
+
8
+ Not part of the stable API.
9
+
10
+ This module may change without notice. Stick to the top-level :mod:`time_split`-module, or lock down your
11
+ dependencies if you need to use the ``support`` module.
12
+ """
13
+
14
+ from .._backend import expand_limits
15
+ from .._frontend import fold_weight, to_string
16
+
17
+ __all__ = [
18
+ "expand_limits",
19
+ "fold_weight",
20
+ "to_string",
21
+ ]
time_split/types.py ADDED
@@ -0,0 +1,61 @@
1
+ """Types related to splitting data."""
2
+
3
+ import datetime as _dt
4
+ import typing as _t
5
+
6
+ import numpy as _np
7
+ import pandas as _pd
8
+
9
+ DatetimeTypes: _t.TypeAlias = str | _pd.Timestamp | _dt.datetime | _dt.date | _np.datetime64
10
+ """Types that may be cast to :class:`pandas.Timestamp`."""
11
+ DatetimeIterable = _t.Iterable[DatetimeTypes]
12
+ """Iterable that may be cast to :class:`pandas.DatetimeIndex`."""
13
+ TimedeltaTypes: _t.TypeAlias = str | _pd.Timedelta | _dt.timedelta | _np.timedelta64
14
+ """Types that may be cast to :class:`pandas.Timedelta`."""
15
+
16
+ Schedule: _t.TypeAlias = _pd.DatetimeIndex | DatetimeIterable | TimedeltaTypes
17
+ """User schedule type."""
18
+ Span = int | _t.Literal["all"] | TimedeltaTypes
19
+ """User span type. Used to determine limits from the timestamps given by a :attr:`Schedule`."""
20
+ Flex = bool | _t.Literal["auto"] | str
21
+ """Flexibility frequency string for ``floor/ceil``. Pass ``False`` to disable."""
22
+
23
+
24
+ class DatetimeSplitBounds(_t.NamedTuple):
25
+ """A 3-tuple which denotes two adjacent datetime ranges."""
26
+
27
+ start: _pd.Timestamp
28
+ """Left (inclusive) limit of the `data` range."""
29
+ mid: _pd.Timestamp
30
+ """Schedule timestamp.
31
+
32
+ Right (exclusive) limit of the `data` range, left (inclusive) limit of the `future_data` range.
33
+ """
34
+ end: _pd.Timestamp
35
+ """Right (exclusive) limit of the `future_data` range."""
36
+
37
+
38
+ DatetimeSplits = list[DatetimeSplitBounds]
39
+ """A list of bounds."""
40
+
41
+
42
+ class DatetimeSplitCounts(_t.NamedTuple):
43
+ """Relative importance of `data` and `future_data`."""
44
+
45
+ data: int
46
+ future_data: int
47
+
48
+
49
+ class DatetimeIndexSplitterKwargs(_t.TypedDict, total=False):
50
+ """Keyword arguments for creating a ``DatetimeIndexSplitter``.
51
+
52
+ The ``DatetimeIndexSplitter`` is the backing type for all splitting logic. It is not exposed directly to users. See
53
+ :func:`.split` or one of the related functions for user-facing APIs.
54
+ """
55
+
56
+ schedule: _t.Required[Schedule]
57
+ before: Span
58
+ after: Span
59
+ step: int
60
+ n_splits: int | None
61
+ flex: Flex
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2024, Richard Sundqvist
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,97 @@
1
+ Metadata-Version: 2.1
2
+ Name: time-split
3
+ Version: 0.1.0
4
+ Summary: My personal little ML engineering library.
5
+ Home-page: https://github.com/rsundqvist/time-split
6
+ Author: Richard Sundqvist
7
+ Author-email: richard.sundqvist@live.se
8
+ Requires-Python: >=3.11
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Natural Language :: English
14
+ Classifier: Operating System :: MacOS
15
+ Classifier: Operating System :: Microsoft :: Windows
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Provides-Extra: plotting
22
+ Requires-Dist: matplotlib ; extra == "plotting"
23
+ Requires-Dist: pandas (>=2.0.3)
24
+ Requires-Dist: rics (>=3.1.0)
25
+ Requires-Dist: seaborn ; extra == "plotting"
26
+ Project-URL: Bug Tracker, https://github.com/rsundqvist/time-split/issues
27
+ Project-URL: Changelog, https://github.com/rsundqvist/time-split/blob/master/CHANGELOG.md
28
+ Project-URL: Documentation, https://time-split.readthedocs.io
29
+ Project-URL: Repository, https://github.com/rsundqvist/time-split
30
+ Description-Content-Type: text/markdown
31
+
32
+ # Time Split <!-- omit in toc -->
33
+ Flexible k-fold validation splits for heterogeneous data.
34
+
35
+ -----------------
36
+ [![PyPI - Version](https://img.shields.io/pypi/v/time-split.svg)](https://pypi.python.org/pypi/time-split)
37
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/time-split.svg)](https://pypi.python.org/pypi/time-split)
38
+ [![Tests](https://github.com/rsundqvist/time-split/workflows/tests/badge.svg)](https://github.com/rsundqvist/time-split/actions?workflow=tests)
39
+ [![Codecov](https://codecov.io/gh/rsundqvist/time-split/branch/master/graph/badge.svg)](https://codecov.io/gh/rsundqvist/time-split)
40
+ [![Read the Docs](https://readthedocs.org/projects/time-split/badge/)](https://time-split.readthedocs.io/)
41
+ [![PyPI - License](https://img.shields.io/pypi/l/time-split.svg)](https://pypi.python.org/pypi/time-split)
42
+
43
+ <div align="center">
44
+ <img alt="Plotted folds on a two-by-two grid."
45
+ title="Examples" height="300" width="1200"
46
+ src="https://raw.githubusercontent.com/rsundqvist/time-split/master/docs/2x2-examples.jpg"><br>
47
+ </div>
48
+
49
+ Plotted folds on a two-by-two grid. See the
50
+ [examples](https://time-split.readthedocs.io/en/stable/auto_examples/index.html) page for more.
51
+
52
+ ## What is it?
53
+ A library for creating cross-validation splits of _heterogeneous_ data, such as raw transaction data with strong
54
+ non-stationary characteristics.
55
+
56
+ ## Highlighted Features
57
+ - [Splitting schedules](https://time-split.readthedocs.io/en/stable/guide/schedules.html) based on a fixed interval,
58
+ a CRON-expression, or a pre-defined list.
59
+ - [Data selection](https://time-split.readthedocs.io/en/stable/guide/spans.html) based on a timedelta, or the splitting
60
+ schedule itself.
61
+ - Automatically extract and [normalize](https://time-split.readthedocs.io/en/stable/guide/flex.html) data limits for
62
+ supported data types.
63
+ - [Plotting function](https://time-split.readthedocs.io/en/stable/generated/time_split.html#time_split.plot) for
64
+ visualization of folds. Display fold sizes (hour/row count), or
65
+ [use custom text](https://time-split.readthedocs.io/en/stable/auto_examples/plotting_with_metrics.html).
66
+ - [Integrations](https://time-split.readthedocs.io/en/stable/generated/time_split.integration.html) for popular
67
+ libraries such as `pandas`, `polars` and `scikit-learn`.
68
+
69
+ ## Installation
70
+ The package is published through the [Python Package Index (PyPI)]. Source code
71
+ is available on GitHub: https://github.com/rsundqvist/time-split
72
+
73
+ ```sh
74
+ pip install -U time-split
75
+ ```
76
+
77
+ This is the preferred method to install ``time-split``, as it will always install the
78
+ most recent stable release.
79
+
80
+ If you don't have [pip] installed, this [Python installation guide] can guide
81
+ you through the process.
82
+
83
+ ## License
84
+ [MIT](LICENSE.md)
85
+
86
+ ## Documentation
87
+ Hosted on Read the Docs: https://time-split.readthedocs.io
88
+
89
+ ## Contributing
90
+
91
+ All contributions, bug reports, bug fixes, documentation improvements, enhancements, and ideas are welcome. To get
92
+ started, see the [Contributing Guide](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md).
93
+
94
+ [Python Package Index (PyPI)]: https://pypi.org/project/time-split
95
+ [pip]: https://pip.pypa.io
96
+ [Python installation guide]: http://docs.python-guide.org/en/stable/starting/installation/
97
+
@@ -0,0 +1,34 @@
1
+ time_split/__init__.py,sha256=YIxnXXfGGTQaxqfCEOn4wD_jUS8PO2JWte62VZCkmao,352
2
+ time_split/_backend/__init__.py,sha256=OBFqNCcJgiDzumVbpY0nxLuxPGnWiKbW02O8Ha-7U8E,134
3
+ time_split/_backend/_available.py,sha256=S-IrxxMI6y9r3gke0wqTW2p22b8mgJrmfVGS8LFdZnw,2204
4
+ time_split/_backend/_datetime_index_like.py,sha256=vFG49rURPFR72RufIjE-uzu3EuJzGsMooTcx7cNI_0U,487
5
+ time_split/_backend/_limits.py,sha256=DY28rOcs5zsvZib-4pAKb43DsOtudiESvBya5NuxK-8,4930
6
+ time_split/_backend/_schedule.py,sha256=cQ6wesTqBd6-Qz8HRChaec0EAQmRvPslJy-l_ZDTYf4,2643
7
+ time_split/_backend/_span.py,sha256=Sdug-PBgbxupYQ57yfIAgu7oM2I41ySfbLuZjFsDDB8,3744
8
+ time_split/_backend/_splitter.py,sha256=NtZAeLQEjwErjINMshx_xDWbIUSz2PNG-ALqW_NP7es,5654
9
+ time_split/_docstrings.py,sha256=v2pZFgUTFvN0ulo6SnW8oiqMJDXBTVnzPwCB_g58dpo,1506
10
+ time_split/_frontend/__init__.py,sha256=ncT_tl17smoSLbtwS61uDpNrHZ7KuwGz0_8hJn5Y-tY,261
11
+ time_split/_frontend/_plot.py,sha256=5QqqGlBKBRDO5jQlU3K_G8rYOp_ccU374jlaYqN_Hb4,11885
12
+ time_split/_frontend/_progress.py,sha256=ApCLHWfHgbEvfdhuV35TdqEzOlO4UqpWO_xKap1JlI8,5087
13
+ time_split/_frontend/_split.py,sha256=zQbfj_kYdrmZVQoL3Ft7_H7IzUtX7A-I-J5y66P-Gx8,1099
14
+ time_split/_frontend/_to_string.py,sha256=7j2Z8fTHaytHyBDE5nh5Mv-WB-nYGg2DHqSwgX0f2kM,3001
15
+ time_split/_frontend/_weight.py,sha256=fMdPGyoa_CA5rm57IRyiZfOQLLMQEcdvumDtABwjdIA,2163
16
+ time_split/_support.py,sha256=gWrcpDrP56g-fVixk7Y8hxDmtDh-VGSLFAAus3tIuQ4,420
17
+ time_split/integration/__init__.py,sha256=adBO6ilCz0sw4mdtMroaMeLY9eXE-uN1dCloI3R8f5I,62
18
+ time_split/integration/_log_progress.py,sha256=B82bV0RfS5QIHz1B_aUfqXu7DTKSWtBdvaQDBsgATX8,953
19
+ time_split/integration/pandas/__init__.py,sha256=3QTqzKhfITgeKnU-Tv0RTM_oHYFr4YoRoSZCu6Z4uYI,1808
20
+ time_split/integration/pandas/_impl.py,sha256=o2Gc1xi1GguyvWFM8hhdYM22sfbqDu9M_2qmG6wahdk,2800
21
+ time_split/integration/polars/__init__.py,sha256=bxt_RPoGhIR6G8ODuf3vcDc0PL58OqBnvMRX74co7dY,2424
22
+ time_split/integration/polars/_impl.py,sha256=eflPt9OD0U5hW4DWl4qZYb73kucR_XGFTS3Skz-JxcM,1890
23
+ time_split/integration/sklearn/__init__.py,sha256=mwnC9QeV1byp4ZGQ2ser_4v-IbIyUhwzufGev6M5U64,131
24
+ time_split/integration/sklearn/_impl.py,sha256=CKINnKf8ejoTBqRFWnRdEYAX59OtY4UI8mWuuz3bibg,5721
25
+ time_split/integration/split_data.py,sha256=flwoJlckiBHbJBqTvCsnQDHJojUNuyeAiS61QkIjogo,2550
26
+ time_split/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ time_split/settings.py,sha256=4JJ6BcMzxFe1Qf4igIhYzE-y_Dx4As4cS1xbjiDQkg8,6331
28
+ time_split/support/__init__.py,sha256=a9-Zej4r3RDFGXNwwguHVFMvlxRv2ns0f-iiFic7zWs,556
29
+ time_split/types.py,sha256=AHnF3wXx1jixKXxZ83i6p5iZKdp12W7ftSqWl4SSd4A,2002
30
+ time_split-0.1.0.dist-info/LICENSE.md,sha256=HZP0m1lF3DaHOdzWCEVmWW9QWIIdS7Gne8j2ApIq19c,1077
31
+ time_split-0.1.0.dist-info/METADATA,sha256=Yf9F5TC8t4VQsxETxZQauZcK0vBvu6fY1G4Hddm4xiI,4569
32
+ time_split-0.1.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
33
+ time_split-0.1.0.dist-info/entry_points.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ time_split-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 1.9.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
File without changes