dycw-utilities 0.109.14__tar.gz → 0.109.16__tar.gz

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.
Files changed (228) hide show
  1. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/PKG-INFO +1 -1
  2. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/pyproject.toml +2 -2
  3. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_numpy.py +31 -0
  4. dycw_utilities-0.109.16/src/tests/test_polars_ols.py +114 -0
  5. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/__init__.py +1 -1
  6. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/numpy.py +48 -2
  7. dycw_utilities-0.109.16/src/utilities/polars_ols.py +171 -0
  8. dycw_utilities-0.109.14/src/tests/test_polars_ols.py +0 -103
  9. dycw_utilities-0.109.14/src/utilities/polars_ols.py +0 -71
  10. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/.gitignore +0 -0
  11. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/LICENSE +0 -0
  12. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/README.md +0 -0
  13. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/__init__.py +0 -0
  14. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/conftest.py +0 -0
  15. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/__init__.py +0 -0
  16. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/package_missing/__init__.py +0 -0
  17. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/package_missing/module.py +0 -0
  18. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/package_with/__init__.py +0 -0
  19. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/package_with/outer_1.py +0 -0
  20. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/package_with/outer_2.py +0 -0
  21. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  22. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  23. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  24. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  25. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/package_without/__init__.py +0 -0
  26. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/package_without/module_1.py +0 -0
  27. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/package_without/module_2.py +0 -0
  28. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/standalone.py +0 -0
  29. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/modules/with_imports.py +0 -0
  30. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  31. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  32. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  33. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  34. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  35. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  36. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  37. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  38. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/scripts/__init__.py +0 -0
  39. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/scripts/test_async_service/__init__.py +0 -0
  40. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/scripts/test_async_service/__main__.py +0 -0
  41. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/scripts/test_async_service/run.sh +0 -0
  42. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
  43. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
  44. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/scripts/test_queue_processor/run.sh +0 -0
  45. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_altair.py +0 -0
  46. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_astor.py +0 -0
  47. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_asyncio.py +0 -0
  48. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_atomicwrites.py +0 -0
  49. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_atools.py +0 -0
  50. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_cachetools.py +0 -0
  51. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_click.py +0 -0
  52. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_concurrent.py +0 -0
  53. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_contextlib.py +0 -0
  54. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_contextvars.py +0 -0
  55. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_cryptography.py +0 -0
  56. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_cvxpy.py +0 -0
  57. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_dataclasses.py +0 -0
  58. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_datetime.py +0 -0
  59. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_enum.py +0 -0
  60. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_errors.py +0 -0
  61. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_eventkit.py +0 -0
  62. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_fastapi.py +0 -0
  63. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_fpdf2.py +0 -0
  64. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_functions.py +0 -0
  65. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_functools.py +0 -0
  66. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_getpass.py +0 -0
  67. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_git.py +0 -0
  68. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_hashlib.py +0 -0
  69. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_http.py +0 -0
  70. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_hypothesis.py +0 -0
  71. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_ipython.py +0 -0
  72. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_iterables.py +0 -0
  73. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_jupyter.py +0 -0
  74. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_lightweight_charts.py +0 -0
  75. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_logging.py +0 -0
  76. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_loguru.py +0 -0
  77. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_luigi.py +0 -0
  78. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_math.py +0 -0
  79. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_memory_profiler.py +0 -0
  80. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_modules.py +0 -0
  81. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_more_itertools.py +0 -0
  82. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_operator.py +0 -0
  83. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_optuna.py +0 -0
  84. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_orjson.py +0 -0
  85. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_os.py +0 -0
  86. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_parse.py +0 -0
  87. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_pathlib.py +0 -0
  88. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_period.py +0 -0
  89. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_pickle.py +0 -0
  90. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_platform.py +0 -0
  91. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_polars.py +0 -0
  92. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_pqdm.py +0 -0
  93. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_pydantic.py +0 -0
  94. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_pyinstrument.py +0 -0
  95. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_pyrsistent.py +0 -0
  96. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_pytest.py +0 -0
  97. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_pytest_regressions.py +0 -0
  98. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_python_dotenv.py +0 -0
  99. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_random.py +0 -0
  100. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_re.py +0 -0
  101. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_redis.py +0 -0
  102. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_reprlib.py +0 -0
  103. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_rich.py +0 -0
  104. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_scipy.py +0 -0
  105. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_sentinel.py +0 -0
  106. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_shelve.py +0 -0
  107. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_slack_sdk.py +0 -0
  108. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_socket.py +0 -0
  109. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_sqlalchemy.py +0 -0
  110. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_sqlalchemy_polars.py +0 -0
  111. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_streamlit.py +0 -0
  112. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_sys.py +0 -0
  113. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_tempfile.py +0 -0
  114. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_tenacity.py +0 -0
  115. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_text.py +0 -0
  116. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_threading.py +0 -0
  117. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_timer.py +0 -0
  118. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_traceback.py +0 -0
  119. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_traceback_funcs/__init__.py +0 -0
  120. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_traceback_funcs/chain.py +0 -0
  121. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  122. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  123. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  124. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_traceback_funcs/many.py +0 -0
  125. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_traceback_funcs/one.py +0 -0
  126. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_traceback_funcs/recursive.py +0 -0
  127. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  128. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  129. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_traceback_funcs/two.py +0 -0
  130. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_traceback_funcs/untraced.py +0 -0
  131. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_types.py +0 -0
  132. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_typing.py +0 -0
  133. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_typing_funcs/__init__.py +0 -0
  134. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_typing_funcs/no_future.py +0 -0
  135. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_typing_funcs/with_future.py +0 -0
  136. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_tzdata.py +0 -0
  137. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_tzlocal.py +0 -0
  138. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_uuid.py +0 -0
  139. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_version.py +0 -0
  140. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_warnings.py +0 -0
  141. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_whenever.py +0 -0
  142. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_zipfile.py +0 -0
  143. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/tests/test_zoneinfo.py +0 -0
  144. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/altair.py +0 -0
  145. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/astor.py +0 -0
  146. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/asyncio.py +0 -0
  147. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/atomicwrites.py +0 -0
  148. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/atools.py +0 -0
  149. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/cachetools.py +0 -0
  150. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/click.py +0 -0
  151. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/concurrent.py +0 -0
  152. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/contextlib.py +0 -0
  153. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/contextvars.py +0 -0
  154. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/cryptography.py +0 -0
  155. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/cvxpy.py +0 -0
  156. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/dataclasses.py +0 -0
  157. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/datetime.py +0 -0
  158. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/enum.py +0 -0
  159. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/errors.py +0 -0
  160. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/eventkit.py +0 -0
  161. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/fastapi.py +0 -0
  162. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/fpdf2.py +0 -0
  163. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/functions.py +0 -0
  164. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/functools.py +0 -0
  165. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/getpass.py +0 -0
  166. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/git.py +0 -0
  167. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/hashlib.py +0 -0
  168. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/http.py +0 -0
  169. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/hypothesis.py +0 -0
  170. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/ipython.py +0 -0
  171. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/iterables.py +0 -0
  172. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/jupyter.py +0 -0
  173. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/lightweight_charts.py +0 -0
  174. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/logging.py +0 -0
  175. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/loguru.py +0 -0
  176. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/luigi.py +0 -0
  177. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/math.py +0 -0
  178. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/memory_profiler.py +0 -0
  179. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/modules.py +0 -0
  180. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/more_itertools.py +0 -0
  181. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/operator.py +0 -0
  182. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/optuna.py +0 -0
  183. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/orjson.py +0 -0
  184. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/os.py +0 -0
  185. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/parse.py +0 -0
  186. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/pathlib.py +0 -0
  187. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/period.py +0 -0
  188. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/pickle.py +0 -0
  189. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/platform.py +0 -0
  190. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/polars.py +0 -0
  191. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/pqdm.py +0 -0
  192. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/py.typed +0 -0
  193. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/pydantic.py +0 -0
  194. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/pyinstrument.py +0 -0
  195. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/pyrsistent.py +0 -0
  196. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/pytest.py +0 -0
  197. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/pytest_regressions.py +0 -0
  198. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/python_dotenv.py +0 -0
  199. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/random.py +0 -0
  200. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/re.py +0 -0
  201. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/redis.py +0 -0
  202. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/reprlib.py +0 -0
  203. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/rich.py +0 -0
  204. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/scipy.py +0 -0
  205. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/sentinel.py +0 -0
  206. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/shelve.py +0 -0
  207. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/slack_sdk.py +0 -0
  208. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/socket.py +0 -0
  209. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/sqlalchemy.py +0 -0
  210. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/sqlalchemy_polars.py +0 -0
  211. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/streamlit.py +0 -0
  212. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/sys.py +0 -0
  213. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/tempfile.py +0 -0
  214. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/tenacity.py +0 -0
  215. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/text.py +0 -0
  216. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/threading.py +0 -0
  217. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/timer.py +0 -0
  218. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/traceback.py +0 -0
  219. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/types.py +0 -0
  220. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/typing.py +0 -0
  221. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/tzdata.py +0 -0
  222. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/tzlocal.py +0 -0
  223. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/uuid.py +0 -0
  224. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/version.py +0 -0
  225. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/warnings.py +0 -0
  226. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/whenever.py +0 -0
  227. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/zipfile.py +0 -0
  228. {dycw_utilities-0.109.14 → dycw_utilities-0.109.16}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.109.14
3
+ Version: 0.109.16
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -92,7 +92,7 @@ dependencies = [
92
92
  name = "dycw-utilities"
93
93
  readme = "README.md"
94
94
  requires-python = ">= 3.12"
95
- version = "0.109.14"
95
+ version = "0.109.16"
96
96
 
97
97
  [project.optional-dependencies]
98
98
  test = [
@@ -335,7 +335,7 @@ zzz-test-zoneinfo = [
335
335
  # bump-my-version
336
336
  [tool.bumpversion]
337
337
  allow_dirty = true
338
- current_version = "0.109.14"
338
+ current_version = "0.109.16"
339
339
 
340
340
  [[tool.bumpversion.files]]
341
341
  filename = "src/utilities/__init__.py"
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from re import escape
4
4
  from typing import TYPE_CHECKING, Any, Literal
5
5
 
6
+ import numpy as np
6
7
  from hypothesis import assume, given
7
8
  from hypothesis.strategies import DataObject, data, floats, integers, none
8
9
  from numpy import (
@@ -12,13 +13,16 @@ from numpy import (
12
13
  full,
13
14
  inf,
14
15
  isclose,
16
+ linspace,
15
17
  median,
16
18
  nan,
17
19
  ndarray,
18
20
  ones,
21
+ pi,
19
22
  zeros,
20
23
  zeros_like,
21
24
  )
25
+ from numpy.fft import fft, fftfreq
22
26
  from numpy.random import Generator
23
27
  from numpy.testing import assert_equal
24
28
  from pytest import mark, param, raises
@@ -36,7 +40,9 @@ from utilities.numpy import (
36
40
  as_int,
37
41
  discretize,
38
42
  fillna,
43
+ filter_frequencies,
39
44
  flatn0,
45
+ get_frequency_spectrum,
40
46
  has_dtype,
41
47
  is_at_least,
42
48
  is_at_least_or_nan,
@@ -268,6 +274,19 @@ class TestFillNa:
268
274
  assert_equal(result, expected)
269
275
 
270
276
 
277
+ class TestFilterFrequencies:
278
+ def test_main(self) -> None:
279
+ n = 1000
280
+ x = linspace(0, 2 * pi, n)
281
+ noise = DEFAULT_RNG.normal(scale=0.25, size=n)
282
+ y = x + noise
283
+ result = filter_frequencies(y, lambda f: np.abs(f) <= 0.02)
284
+ assert result.shape == (n,)
285
+ fft_vals = fft(result)
286
+ freqs = fftfreq(n)
287
+ assert np.allclose(fft_vals[np.abs(freqs) > 0.02], 0.0)
288
+
289
+
271
290
  class TestFlatN0:
272
291
  @given(data=data(), n=integers(1, 10))
273
292
  def test_main(self, *, data: DataObject, n: int) -> None:
@@ -288,6 +307,18 @@ class TestFlatN0:
288
307
  _ = flatn0(ones(2, dtype=bool))
289
308
 
290
309
 
310
+ class TestGetFrequencySpectrum:
311
+ def test_main(self) -> None:
312
+ n = 1000
313
+ x = linspace(0, 2 * pi, n)
314
+ noise = DEFAULT_RNG.normal(scale=0.25, size=n)
315
+ y = x + noise
316
+ y2 = filter_frequencies(y, lambda f: np.abs(f) <= 0.02)
317
+ result = get_frequency_spectrum(y2)
318
+ assert result.shape == (n, 2)
319
+ assert np.allclose(result[result[:, 0] > 0.02, 1], 0.0)
320
+
321
+
291
322
  class TestHasDtype:
292
323
  @mark.parametrize(("dtype", "expected"), [param(float, True), param(int, False)])
293
324
  @mark.parametrize("is_tuple", [param(True), param(False)])
@@ -0,0 +1,114 @@
1
+ from __future__ import annotations
2
+
3
+ from hypothesis import given
4
+ from hypothesis.strategies import sampled_from
5
+ from numpy import isclose
6
+ from polars import DataFrame, Float64, Series, Struct, col
7
+ from polars.testing import assert_frame_equal
8
+ from sklearn.linear_model import LinearRegression
9
+
10
+ from utilities.polars import concat_series, integers, normal
11
+ from utilities.polars_ols import compute_rolling_ols
12
+
13
+
14
+ class TestComputeRollingOLS:
15
+ def test_main_self(self) -> None:
16
+ df = self._df.with_columns(
17
+ compute_rolling_ols(
18
+ "y", "x1", "x2", window_size=5, min_periods=5, add_intercept=True
19
+ )
20
+ )
21
+ self._assert_series(df["ols"])
22
+
23
+ def test_main_series(self) -> None:
24
+ ols = compute_rolling_ols(
25
+ self._df["y"],
26
+ self._df["x1"],
27
+ self._df["x2"],
28
+ window_size=5,
29
+ min_periods=5,
30
+ add_intercept=True,
31
+ )
32
+ self._assert_series(ols)
33
+
34
+ @given(
35
+ case=sampled_from([
36
+ (
37
+ slice(-7, -2),
38
+ [0.3619563208480195, 0.6583229512154678],
39
+ -1.386023798329262,
40
+ 7.434533329394103,
41
+ 0.994253238813284,
42
+ ),
43
+ (
44
+ slice(-6, -1),
45
+ [0.35564162435283264, 0.6656931556738643],
46
+ -0.5626805730005437,
47
+ -51.903154626050124,
48
+ 0.9979752966843768,
49
+ ),
50
+ (
51
+ slice(-5, None),
52
+ [0.3100421300754358, 0.6753578168818635],
53
+ 0.48493124625502837,
54
+ -36.70039604095908,
55
+ 0.9977272526713715,
56
+ ),
57
+ ])
58
+ )
59
+ def test_tail(
60
+ self, *, case: tuple[slice, list[float], float, float, float]
61
+ ) -> None:
62
+ slice_, coeffs, intercept, prediction, r2 = case
63
+ df = self._df[slice_]
64
+ X = df.select("x1", "x2").to_numpy() # noqa: N806
65
+ y = df.select("y").to_numpy()
66
+ model = LinearRegression()
67
+ model = model.fit(X, y)
68
+ assert isclose(model.coef_, coeffs).all()
69
+ assert isclose(model.intercept_, intercept)
70
+ assert isclose(model.predict(X)[-1], prediction).all()
71
+ assert isclose(model.score(X, y), r2)
72
+
73
+ @property
74
+ def _df(self) -> DataFrame:
75
+ n = 20
76
+ return concat_series(
77
+ integers(n, -100, high=100, seed=0).alias("x1"),
78
+ integers(n, -100, high=100, seed=1).alias("x2"),
79
+ ).with_columns(
80
+ ((col("x1") + 2 * col("x2") + normal(n, scale=10.0, seed=2)) / 3).alias("y")
81
+ )
82
+
83
+ def _assert_series(self, series: Series, /) -> None:
84
+ df = series.struct.unnest()
85
+ tail = df[-10:]
86
+ # fmt: off
87
+ data = [
88
+ ({"x1": 0.333396198442681, "x2": 0.6845517746145712, "const": 0.2808021232120448}, 59.921571424913495, 1.67032007883995, 0.9955364659986504),
89
+ ({"x1": 0.322785525889542, "x2": 0.6896341527044252, "const": 0.5401793852579858}, 15.974446064929626, -0.3429678871268038, 0.9961762567103958),
90
+ ({"x1": 0.31042868991153927, "x2": 0.7055685710743383, "const": 1.145326562525439}, -31.310827706894123, -0.45191863996575066, 0.998022262986332),
91
+ ({"x1": 0.33311466967931097, "x2": 0.684137842579758, "const": -0.7961518480794516}, 50.66821598287034, -2.975371834066671, 0.9974533939791341),
92
+ ({"x1": 0.35299385150914864, "x2": 0.6758890569593843, "const": -0.9377907849336107}, -0.8749325340834626, 1.0581261048863142, 0.9973453833170313),
93
+ ({"x1": 0.351300641938209, "x2": 0.6456834722890913, "const": -1.859577387752822}, 1.6809655259738476, 0.3217076349681922, 0.9951571413022856),
94
+ ({"x1": 0.3583378199895871, "x2": 0.6588347796692774, "const": -1.109675446287481}, 26.65448170418155, 2.496480675700724, 0.9933751737130443),
95
+ ({"x1": 0.36195632084801765, "x2": 0.658322951215466, "const": -1.3860237983291754}, 7.43453332939416, -0.791818995629618, 0.9905085882663488),
96
+ ({"x1": 0.35564162435283225, "x2": 0.6656931556738634, "const": -0.562680573000551}, -51.90315462605006, 0.6592474497562932, 0.9973576833556038),
97
+ ({"x1": 0.3100421300754357, "x2": 0.675357816881863, "const": 0.48493124625501927}, -36.70039604095908, -0.6071841038068868, 0.9978541580643828),
98
+ ]
99
+ # fmt: on
100
+ expected = DataFrame(
101
+ data=data,
102
+ schema={
103
+ "coefficients": Struct({
104
+ "x1": Float64,
105
+ "x2": Float64,
106
+ "const": Float64,
107
+ }),
108
+ "predictions": Float64,
109
+ "residuals": Float64,
110
+ "R2": Float64,
111
+ },
112
+ orient="row",
113
+ )
114
+ assert_frame_equal(tail, expected)
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.109.14"
3
+ __version__ = "0.109.16"
@@ -1,19 +1,22 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from functools import reduce
4
+ from functools import partial, reduce
5
5
  from itertools import repeat
6
6
  from typing import TYPE_CHECKING, Any, overload, override
7
7
 
8
8
  import numpy as np
9
9
  from numpy import (
10
+ argsort,
10
11
  array,
11
12
  bool_,
13
+ complex128,
12
14
  digitize,
13
15
  dtype,
14
16
  errstate,
15
17
  flatnonzero,
16
18
  float64,
19
+ floating,
17
20
  full_like,
18
21
  inf,
19
22
  int64,
@@ -30,6 +33,7 @@ from numpy import (
30
33
  roll,
31
34
  where,
32
35
  )
36
+ from numpy.fft import fft, fftfreq, ifft
33
37
  from numpy.linalg import det, eig
34
38
  from numpy.random import default_rng
35
39
  from numpy.typing import NDArray
@@ -37,7 +41,7 @@ from numpy.typing import NDArray
37
41
  from utilities.iterables import is_iterable_not_str
38
42
 
39
43
  if TYPE_CHECKING:
40
- from collections.abc import Iterable
44
+ from collections.abc import Callable, Iterable
41
45
 
42
46
 
43
47
  ##
@@ -160,6 +164,33 @@ def fillna(array: NDArrayF, /, *, value: float = 0.0) -> NDArrayF:
160
164
  ##
161
165
 
162
166
 
167
+ def filter_frequencies(
168
+ array: NDArrayF,
169
+ /,
170
+ *filters: Callable[[NDArray[floating[Any]]], NDArrayB],
171
+ d: int = 1,
172
+ ) -> NDArrayF:
173
+ """Filter an array by the frequencies of its FFT."""
174
+ (n,) = array.shape
175
+ fft_vals = fft(array)
176
+ freqs = fftfreq(n, d=d)
177
+ reduced = reduce(partial(_filter_frequencies_one, freqs=freqs), filters, fft_vals)
178
+ return ifft(reduced).real
179
+
180
+
181
+ def _filter_frequencies_one(
182
+ acc: NDArray[complex128],
183
+ el: Callable[[NDArray[floating[Any]]], NDArrayB],
184
+ /,
185
+ *,
186
+ freqs: NDArray[floating[Any]],
187
+ ) -> NDArray[complex128]:
188
+ return where(el(freqs), acc, 0.0)
189
+
190
+
191
+ ##
192
+
193
+
163
194
  def flatn0(array: NDArrayB, /) -> int:
164
195
  """Return the index of the unique True element."""
165
196
  if not array.any():
@@ -193,6 +224,19 @@ class FlatN0MultipleError(FlatN0Error):
193
224
  ##
194
225
 
195
226
 
227
+ def get_frequency_spectrum(array: NDArrayF, /, *, d: int = 1) -> NDArray[floating[Any]]:
228
+ """Get the frequency spectrum."""
229
+ (n,) = array.shape
230
+ fft_vals = fft(array)
231
+ freqs = fftfreq(n, d=d)
232
+ amplitudes = np.abs(fft_vals)
233
+ data = np.hstack([freqs.reshape(-1, 1), amplitudes.reshape(-1, 1)])
234
+ return data[argsort(data[:, 0])]
235
+
236
+
237
+ ##
238
+
239
+
196
240
  def has_dtype(x: Any, dtype: Any, /) -> bool:
197
241
  """Check if an object has the required dtype."""
198
242
  if is_iterable_not_str(dtype):
@@ -851,7 +895,9 @@ __all__ = [
851
895
  "datetime64us",
852
896
  "discretize",
853
897
  "fillna",
898
+ "filter_frequencies",
854
899
  "flatn0",
900
+ "get_frequency_spectrum",
855
901
  "has_dtype",
856
902
  "is_at_least",
857
903
  "is_at_least_or_nan",
@@ -0,0 +1,171 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, overload
4
+
5
+ from polars import Expr, Series, struct
6
+ from polars_ols import RollingKwargs, compute_rolling_least_squares
7
+
8
+ from utilities.errors import ImpossibleCaseError
9
+ from utilities.functions import is_sequence_of
10
+ from utilities.polars import concat_series, ensure_expr_or_series
11
+
12
+ if TYPE_CHECKING:
13
+ from polars._typing import IntoExprColumn
14
+ from polars_ols import NullPolicy
15
+
16
+ from utilities.polars import ExprLike
17
+
18
+
19
+ @overload
20
+ def compute_rolling_ols(
21
+ target: ExprLike,
22
+ *features: ExprLike,
23
+ sample_weights: ExprLike | None = None,
24
+ add_intercept: bool = False,
25
+ null_policy: NullPolicy = "drop_window",
26
+ window_size: int = 1000000,
27
+ min_periods: int | None = None,
28
+ use_woodbury: bool | None = None,
29
+ alpha: float | None = None,
30
+ ) -> Expr: ...
31
+ @overload
32
+ def compute_rolling_ols(
33
+ target: Series,
34
+ *features: Series,
35
+ sample_weights: Series | None = None,
36
+ add_intercept: bool = False,
37
+ null_policy: NullPolicy = "drop_window",
38
+ window_size: int = 1000000,
39
+ min_periods: int | None = None,
40
+ use_woodbury: bool | None = None,
41
+ alpha: float | None = None,
42
+ ) -> Series: ...
43
+ @overload
44
+ def compute_rolling_ols(
45
+ target: IntoExprColumn,
46
+ *features: IntoExprColumn,
47
+ sample_weights: IntoExprColumn | None = None,
48
+ add_intercept: bool = False,
49
+ null_policy: NullPolicy = "drop_window",
50
+ window_size: int = 1000000,
51
+ min_periods: int | None = None,
52
+ use_woodbury: bool | None = None,
53
+ alpha: float | None = None,
54
+ ) -> Expr | Series: ...
55
+ def compute_rolling_ols(
56
+ target: IntoExprColumn,
57
+ *features: IntoExprColumn,
58
+ sample_weights: IntoExprColumn | None = None,
59
+ add_intercept: bool = False,
60
+ null_policy: NullPolicy = "drop_window",
61
+ window_size: int = 1000000,
62
+ min_periods: int | None = None,
63
+ use_woodbury: bool | None = None,
64
+ alpha: float | None = None,
65
+ ) -> Expr | Series:
66
+ """Compute a rolling OLS."""
67
+ target = ensure_expr_or_series(target)
68
+ features2 = tuple(map(ensure_expr_or_series, features))
69
+ sample_weights = (
70
+ None if sample_weights is None else ensure_expr_or_series(sample_weights)
71
+ )
72
+ if (
73
+ isinstance(target, Expr)
74
+ and is_sequence_of(features2, Expr)
75
+ and ((sample_weights is None) or isinstance(sample_weights, Expr))
76
+ ):
77
+ return _compute_rolling_ols_expr(
78
+ target,
79
+ *features2,
80
+ sample_weights=sample_weights,
81
+ add_intercept=add_intercept,
82
+ null_policy=null_policy,
83
+ window_size=window_size,
84
+ min_periods=min_periods,
85
+ use_woodbury=use_woodbury,
86
+ alpha=alpha,
87
+ )
88
+ if (
89
+ isinstance(target, Series)
90
+ and is_sequence_of(features2, Series)
91
+ and ((sample_weights is None) or isinstance(sample_weights, Series))
92
+ ):
93
+ return concat_series(
94
+ target, *features2, *([] if sample_weights is None else [sample_weights])
95
+ ).with_columns(
96
+ _compute_rolling_ols_expr(
97
+ target.name,
98
+ *(f.name for f in features2),
99
+ sample_weights=None if sample_weights is None else sample_weights.name,
100
+ add_intercept=add_intercept,
101
+ null_policy=null_policy,
102
+ window_size=window_size,
103
+ min_periods=min_periods,
104
+ use_woodbury=use_woodbury,
105
+ alpha=alpha,
106
+ )
107
+ )["ols"]
108
+ raise ImpossibleCaseError( # pragma: no cover
109
+ case=[f"{target=}", f"{features2=}", f"{sample_weights=}"]
110
+ )
111
+
112
+
113
+ def _compute_rolling_ols_expr(
114
+ target: ExprLike,
115
+ *features: ExprLike,
116
+ sample_weights: ExprLike | None = None,
117
+ add_intercept: bool = False,
118
+ null_policy: NullPolicy = "drop_window",
119
+ window_size: int = 1000000,
120
+ min_periods: int | None = None,
121
+ use_woodbury: bool | None = None,
122
+ alpha: float | None = None,
123
+ ) -> Expr:
124
+ """Compute a rolling OLS."""
125
+ target = ensure_expr_or_series(target)
126
+ features2 = tuple(map(ensure_expr_or_series, features))
127
+ sample_weights = (
128
+ None if sample_weights is None else ensure_expr_or_series(sample_weights)
129
+ )
130
+ rolling_kwargs = RollingKwargs(
131
+ null_policy=null_policy,
132
+ window_size=window_size,
133
+ min_periods=min_periods,
134
+ use_woodbury=use_woodbury,
135
+ alpha=alpha,
136
+ )
137
+ coefficients = compute_rolling_least_squares(
138
+ target,
139
+ *features2,
140
+ sample_weights=sample_weights,
141
+ add_intercept=add_intercept,
142
+ mode="coefficients",
143
+ rolling_kwargs=rolling_kwargs,
144
+ ).alias("coefficients")
145
+ predictions = compute_rolling_least_squares(
146
+ target,
147
+ *features2,
148
+ sample_weights=sample_weights,
149
+ add_intercept=add_intercept,
150
+ mode="predictions",
151
+ rolling_kwargs=rolling_kwargs,
152
+ ).alias("predictions")
153
+ residuals = compute_rolling_least_squares(
154
+ target,
155
+ *features2,
156
+ sample_weights=sample_weights,
157
+ add_intercept=add_intercept,
158
+ mode="residuals",
159
+ rolling_kwargs=rolling_kwargs,
160
+ ).alias("residuals")
161
+ ssr = (residuals**2).rolling_sum(window_size, min_samples=min_periods).alias("SSR")
162
+ sst = (
163
+ ((target - target.rolling_mean(window_size, min_samples=min_periods)) ** 2)
164
+ .rolling_sum(window_size, min_samples=min_periods)
165
+ .alias("SST")
166
+ )
167
+ r2 = (1 - ssr / sst).alias("R2")
168
+ return struct(coefficients, predictions, residuals, r2).alias("ols")
169
+
170
+
171
+ __all__ = ["compute_rolling_ols"]
@@ -1,103 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from hypothesis import given
4
- from hypothesis.strategies import sampled_from
5
- from numpy import isclose
6
- from polars import DataFrame, Float64, Struct, UInt32, col
7
- from polars.testing import assert_frame_equal
8
- from sklearn.linear_model import LinearRegression
9
-
10
- from utilities.polars import concat_series, integers, normal
11
- from utilities.polars_ols import compute_rolling_ols
12
-
13
-
14
- class TestComputeRollingOLS:
15
- def test_ols_results(self) -> None:
16
- result = self._df["ols"].struct.unnest().with_row_index()
17
- # fmt: off
18
- exp_values = [
19
- (10, {"x1": 0.333396198442681, "x2": 0.6845517746145712, "const": 0.2808021232120448}, 59.921571424913495, 1.67032007883995, 0.9955364659986504),
20
- (11, {"x1": 0.322785525889542, "x2": 0.6896341527044252, "const": 0.5401793852579858}, 15.974446064929626, -0.3429678871268038, 0.9961762567103958),
21
- (12, {"x1": 0.31042868991153927, "x2": 0.7055685710743383, "const": 1.145326562525439}, -31.310827706894123, -0.45191863996575066, 0.998022262986332),
22
- (13, {"x1": 0.33311466967931097, "x2": 0.684137842579758, "const": -0.7961518480794516}, 50.66821598287034, -2.975371834066671, 0.9974533939791341),
23
- (14, {"x1": 0.35299385150914864, "x2": 0.6758890569593843, "const": -0.9377907849336107}, -0.8749325340834626, 1.0581261048863142, 0.9973453833170313),
24
- (15, {"x1": 0.351300641938209, "x2": 0.6456834722890913, "const": -1.859577387752822}, 1.6809655259738476, 0.3217076349681922, 0.9951571413022856),
25
- (16, {"x1": 0.3583378199895871, "x2": 0.6588347796692774, "const": -1.109675446287481}, 26.65448170418155, 2.496480675700724, 0.9933751737130443),
26
- (17, {"x1": 0.36195632084801765, "x2": 0.658322951215466, "const": -1.3860237983291754}, 7.43453332939416, -0.791818995629618, 0.9905085882663488),
27
- (18, {"x1": 0.35564162435283225, "x2": 0.6656931556738634, "const": -0.562680573000551}, -51.90315462605006, 0.6592474497562932, 0.9973576833556038),
28
- (19, {"x1": 0.3100421300754357, "x2": 0.675357816881863, "const": 0.48493124625501927}, -36.70039604095908, -0.6071841038068868, 0.9978541580643828),
29
- ]
30
- # fmt: on
31
- expected = DataFrame(
32
- data=exp_values,
33
- schema={
34
- "index": UInt32,
35
- "coefficients": Struct({
36
- "x1": Float64,
37
- "x2": Float64,
38
- "const": Float64,
39
- }),
40
- "predictions": Float64,
41
- "residuals": Float64,
42
- "R2": Float64,
43
- },
44
- orient="row",
45
- )
46
- assert_frame_equal(result[-10:], expected)
47
-
48
- @given(
49
- case=sampled_from([
50
- (
51
- slice(-7, -2),
52
- [0.3619563208480195, 0.6583229512154678],
53
- -1.386023798329262,
54
- 7.434533329394103,
55
- 0.994253238813284,
56
- ),
57
- (
58
- slice(-6, -1),
59
- [0.35564162435283264, 0.6656931556738643],
60
- -0.5626805730005437,
61
- -51.903154626050124,
62
- 0.9979752966843768,
63
- ),
64
- (
65
- slice(-5, None),
66
- [0.3100421300754358, 0.6753578168818635],
67
- 0.48493124625502837,
68
- -36.70039604095908,
69
- 0.9977272526713715,
70
- ),
71
- ])
72
- )
73
- def test_tail(
74
- self, *, case: tuple[slice, list[float], float, float, float]
75
- ) -> None:
76
- slice_, coeffs, intercept, prediction, r2 = case
77
- df = self._df[slice_]
78
- X = df.select("x1", "x2").to_numpy() # noqa: N806
79
- y = df.select("y").to_numpy()
80
- model = LinearRegression()
81
- model = model.fit(X, y)
82
- assert isclose(model.coef_, coeffs).all()
83
- assert isclose(model.intercept_, intercept)
84
- assert isclose(model.predict(X)[-1], prediction).all()
85
- assert isclose(model.score(X, y), r2)
86
-
87
- @property
88
- def _df(self) -> DataFrame:
89
- n = 20
90
- return (
91
- concat_series(
92
- integers(n, -100, high=100, seed=0).alias("x1"),
93
- integers(n, -100, high=100, seed=1).alias("x2"),
94
- )
95
- .with_columns(
96
- y=(col("x1") + 2 * col("x2") + normal(n, scale=10.0, seed=2)) / 3
97
- )
98
- .with_columns(
99
- compute_rolling_ols(
100
- "y", "x1", "x2", window_size=5, min_periods=5, add_intercept=True
101
- )
102
- )
103
- )
@@ -1,71 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING
4
-
5
- from polars import struct
6
- from polars_ols import RollingKwargs, compute_rolling_least_squares
7
-
8
- from utilities.polars import ensure_expr_or_series
9
-
10
- if TYPE_CHECKING:
11
- from polars import Expr
12
- from polars_ols import NullPolicy
13
-
14
- from utilities.polars import ExprLike
15
-
16
-
17
- def compute_rolling_ols(
18
- target: ExprLike,
19
- *features: ExprLike,
20
- sample_weights: ExprLike | None = None,
21
- add_intercept: bool = False,
22
- null_policy: NullPolicy = "drop_window",
23
- window_size: int = 1000000,
24
- min_periods: int | None = None,
25
- use_woodbury: bool | None = None,
26
- alpha: float | None = None,
27
- ) -> Expr:
28
- """Compute a rolling OLS."""
29
- target = ensure_expr_or_series(target)
30
- rolling_kwargs = RollingKwargs(
31
- null_policy=null_policy,
32
- window_size=window_size,
33
- min_periods=min_periods,
34
- use_woodbury=use_woodbury,
35
- alpha=alpha,
36
- )
37
- coefficients = compute_rolling_least_squares(
38
- target,
39
- *features,
40
- sample_weights=sample_weights,
41
- add_intercept=add_intercept,
42
- mode="coefficients",
43
- rolling_kwargs=rolling_kwargs,
44
- ).alias("coefficients")
45
- predictions = compute_rolling_least_squares(
46
- target,
47
- *features,
48
- sample_weights=sample_weights,
49
- add_intercept=add_intercept,
50
- mode="predictions",
51
- rolling_kwargs=rolling_kwargs,
52
- ).alias("predictions")
53
- residuals = compute_rolling_least_squares(
54
- target,
55
- *features,
56
- sample_weights=sample_weights,
57
- add_intercept=add_intercept,
58
- mode="residuals",
59
- rolling_kwargs=rolling_kwargs,
60
- ).alias("residuals")
61
- ssr = (residuals**2).rolling_sum(window_size, min_samples=min_periods).alias("SSR")
62
- sst = (
63
- ((target - target.rolling_mean(window_size, min_samples=min_periods)) ** 2)
64
- .rolling_sum(window_size, min_samples=min_periods)
65
- .alias("SST")
66
- )
67
- r2 = (1 - ssr / sst).alias("R2")
68
- return struct(coefficients, predictions, residuals, r2).alias("ols")
69
-
70
-
71
- __all__ = ["compute_rolling_ols"]