diff --git a/docs/news.md b/docs/news.md index 2353c8bf..837a65d6 100644 --- a/docs/news.md +++ b/docs/news.md @@ -1,5 +1,9 @@ # News +## PyFixest `0.10.10` + +Fixes a bug with variable interactions via `i(var)` syntax. See [issue #221](https://github.com/s3alfisc/pyfixest/issues/211). + ## PyFixest `0.10.9` Makes `etable()` prettier and more informative. diff --git a/figures/event_study.svg b/figures/event_study.svg index 9f14e12d..8c3687a1 100644 --- a/figures/event_study.svg +++ b/figures/event_study.svg @@ -1,4 +1,4 @@ - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - C(rel_year)[T.-20.0] + C(rel_year,contr.tre.. - + - + - + - + - + - + - + - + - + + + + + - C(rel_year)[T.-11.0] + C(rel_year,contr.tre.. - - - - - + - + - + - + - + - + - + - - - C(rel_year)[T.-3.0] - - - + - + - + + + + C(rel_year,contr.tre.. + + - + - + - + - + - + - - - C(rel_year)[T.6.0] - - - + - + - + - + - + + + + C(rel_year,contr.tre.. + + - + - + - + - - - C(rel_year)[T.14.0] - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + -0.5 - + 0.0 - + 0.5 - + 1.0 - + 1.5 - + 2.0 - + 2.5 - + 3.0 @@ -465,735 +462,744 @@ text { - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1203,17 +1209,17 @@ text { TWFE vs DID2S - + Estimate and 95% Confidence Interval - + Coefficient - + @@ -1248,7 +1254,7 @@ text { - dep_var_hat~i(rel_year)+0 + dep_var_hat~i(rel_year) @@ -1284,9 +1290,9 @@ text { - + - + \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 20b969a7..53ffe0e1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -577,14 +577,14 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs [[package]] name = "importlib-resources" -version = "6.1.0" +version = "6.1.1" description = "Read resources from Python packages" category = "main" optional = true python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.0-py3-none-any.whl", hash = "sha256:aa50258bbfa56d4e33fbd8aa3ef48ded10d1735f11532b8df95388cc6bdb7e83"}, - {file = "importlib_resources-6.1.0.tar.gz", hash = "sha256:9d48dcccc213325e810fd723e7fbb45ccb39f6cf5c31f00cf2b965f5f10f3cb9"}, + {file = "importlib_resources-6.1.1-py3-none-any.whl", hash = "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6"}, + {file = "importlib_resources-6.1.1.tar.gz", hash = "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a"}, ] [package.dependencies] @@ -1145,39 +1145,37 @@ files = [ [[package]] name = "pandas" -version = "1.5.3" +version = "2.0.3" description = "Powerful data structures for data analysis, time series, and statistics" category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406"}, - {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572"}, - {file = "pandas-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996"}, - {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ac844a0fe00bfaeb2c9b51ab1424e5c8744f89860b138434a363b1f620f354"}, - {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0a56cef15fd1586726dace5616db75ebcfec9179a3a55e78f72c5639fa2a23"}, - {file = "pandas-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:478ff646ca42b20376e4ed3fa2e8d7341e8a63105586efe54fa2508ee087f328"}, - {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc"}, - {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d"}, - {file = "pandas-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc"}, - {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae"}, - {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6"}, - {file = "pandas-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003"}, - {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14e45300521902689a81f3f41386dc86f19b8ba8dd5ac5a3c7010ef8d2932813"}, - {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9842b6f4b8479e41968eced654487258ed81df7d1c9b7b870ceea24ed9459b31"}, - {file = "pandas-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26d9c71772c7afb9d5046e6e9cf42d83dd147b5cf5bcb9d97252077118543792"}, - {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fbcb19d6fceb9e946b3e23258757c7b225ba450990d9ed63ccceeb8cae609f7"}, - {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:565fa34a5434d38e9d250af3c12ff931abaf88050551d9fbcdfafca50d62babf"}, - {file = "pandas-1.5.3-cp38-cp38-win32.whl", hash = "sha256:87bd9c03da1ac870a6d2c8902a0e1fd4267ca00f13bc494c9e5a9020920e1d51"}, - {file = "pandas-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:41179ce559943d83a9b4bbacb736b04c928b095b5f25dd2b7389eda08f46f373"}, - {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c74a62747864ed568f5a82a49a23a8d7fe171d0c69038b38cedf0976831296fa"}, - {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c4c00e0b0597c8e4f59e8d461f797e5d70b4d025880516a8261b2817c47759ee"}, - {file = "pandas-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a50d9a4336a9621cab7b8eb3fb11adb82de58f9b91d84c2cd526576b881a0c5a"}, - {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd05f7783b3274aa206a1af06f0ceed3f9b412cf665b7247eacd83be41cf7bf0"}, - {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5"}, - {file = "pandas-1.5.3-cp39-cp39-win32.whl", hash = "sha256:7cec0bee9f294e5de5bbfc14d0573f65526071029d036b753ee6507d2a21480a"}, - {file = "pandas-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfd681c5dc216037e0b0a2c821f5ed99ba9f03ebcf119c7dac0e9a7b960b9ec9"}, - {file = "pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1"}, + {file = "pandas-2.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e4c7c9f27a4185304c7caf96dc7d91bc60bc162221152de697c98eb0b2648dd8"}, + {file = "pandas-2.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f167beed68918d62bffb6ec64f2e1d8a7d297a038f86d4aed056b9493fca407f"}, + {file = "pandas-2.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce0c6f76a0f1ba361551f3e6dceaff06bde7514a374aa43e33b588ec10420183"}, + {file = "pandas-2.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba619e410a21d8c387a1ea6e8a0e49bb42216474436245718d7f2e88a2f8d7c0"}, + {file = "pandas-2.0.3-cp310-cp310-win32.whl", hash = "sha256:3ef285093b4fe5058eefd756100a367f27029913760773c8bf1d2d8bebe5d210"}, + {file = "pandas-2.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:9ee1a69328d5c36c98d8e74db06f4ad518a1840e8ccb94a4ba86920986bb617e"}, + {file = "pandas-2.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b084b91d8d66ab19f5bb3256cbd5ea661848338301940e17f4492b2ce0801fe8"}, + {file = "pandas-2.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37673e3bdf1551b95bf5d4ce372b37770f9529743d2498032439371fc7b7eb26"}, + {file = "pandas-2.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9cb1e14fdb546396b7e1b923ffaeeac24e4cedd14266c3497216dd4448e4f2d"}, + {file = "pandas-2.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9cd88488cceb7635aebb84809d087468eb33551097d600c6dad13602029c2df"}, + {file = "pandas-2.0.3-cp311-cp311-win32.whl", hash = "sha256:694888a81198786f0e164ee3a581df7d505024fbb1f15202fc7db88a71d84ebd"}, + {file = "pandas-2.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:6a21ab5c89dcbd57f78d0ae16630b090eec626360085a4148693def5452d8a6b"}, + {file = "pandas-2.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9e4da0d45e7f34c069fe4d522359df7d23badf83abc1d1cef398895822d11061"}, + {file = "pandas-2.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:32fca2ee1b0d93dd71d979726b12b61faa06aeb93cf77468776287f41ff8fdc5"}, + {file = "pandas-2.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:258d3624b3ae734490e4d63c430256e716f488c4fcb7c8e9bde2d3aa46c29089"}, + {file = "pandas-2.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eae3dc34fa1aa7772dd3fc60270d13ced7346fcbcfee017d3132ec625e23bb0"}, + {file = "pandas-2.0.3-cp38-cp38-win32.whl", hash = "sha256:f3421a7afb1a43f7e38e82e844e2bca9a6d793d66c1a7f9f0ff39a795bbc5e02"}, + {file = "pandas-2.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:69d7f3884c95da3a31ef82b7618af5710dba95bb885ffab339aad925c3e8ce78"}, + {file = "pandas-2.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5247fb1ba347c1261cbbf0fcfba4a3121fbb4029d95d9ef4dc45406620b25c8b"}, + {file = "pandas-2.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:81af086f4543c9d8bb128328b5d32e9986e0c84d3ee673a2ac6fb57fd14f755e"}, + {file = "pandas-2.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1994c789bf12a7c5098277fb43836ce090f1073858c10f9220998ac74f37c69b"}, + {file = "pandas-2.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ec591c48e29226bcbb316e0c1e9423622bc7a4eaf1ef7c3c9fa1a3981f89641"}, + {file = "pandas-2.0.3-cp39-cp39-win32.whl", hash = "sha256:04dbdbaf2e4d46ca8da896e1805bc04eb85caa9a82e259e8eed00254d5e0c682"}, + {file = "pandas-2.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:1168574b036cd8b93abc746171c9b4f1b83467438a5e45909fed645cf8692dbc"}, + {file = "pandas-2.0.3.tar.gz", hash = "sha256:c02f372a88e0d17f36d3093a644c73cfc1788e876a7c4bcb4020a77512e2043c"}, ] [package.dependencies] @@ -1186,11 +1184,32 @@ numpy = [ {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, ] -python-dateutil = ">=2.8.1" +python-dateutil = ">=2.8.2" pytz = ">=2020.1" +tzdata = ">=2022.1" [package.extras] -test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] +all = ["PyQt5 (>=5.15.1)", "SQLAlchemy (>=1.4.16)", "beautifulsoup4 (>=4.9.3)", "bottleneck (>=1.3.2)", "brotlipy (>=0.7.0)", "fastparquet (>=0.6.3)", "fsspec (>=2021.07.0)", "gcsfs (>=2021.07.0)", "html5lib (>=1.1)", "hypothesis (>=6.34.2)", "jinja2 (>=3.0.0)", "lxml (>=4.6.3)", "matplotlib (>=3.6.1)", "numba (>=0.53.1)", "numexpr (>=2.7.3)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pandas-gbq (>=0.15.0)", "psycopg2 (>=2.8.6)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.2)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "python-snappy (>=0.6.0)", "pyxlsb (>=1.0.8)", "qtpy (>=2.2.0)", "s3fs (>=2021.08.0)", "scipy (>=1.7.1)", "tables (>=3.6.1)", "tabulate (>=0.8.9)", "xarray (>=0.21.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)", "zstandard (>=0.15.2)"] +aws = ["s3fs (>=2021.08.0)"] +clipboard = ["PyQt5 (>=5.15.1)", "qtpy (>=2.2.0)"] +compression = ["brotlipy (>=0.7.0)", "python-snappy (>=0.6.0)", "zstandard (>=0.15.2)"] +computation = ["scipy (>=1.7.1)", "xarray (>=0.21.0)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pyxlsb (>=1.0.8)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)"] +feather = ["pyarrow (>=7.0.0)"] +fss = ["fsspec (>=2021.07.0)"] +gcp = ["gcsfs (>=2021.07.0)", "pandas-gbq (>=0.15.0)"] +hdf5 = ["tables (>=3.6.1)"] +html = ["beautifulsoup4 (>=4.9.3)", "html5lib (>=1.1)", "lxml (>=4.6.3)"] +mysql = ["SQLAlchemy (>=1.4.16)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.0.0)", "tabulate (>=0.8.9)"] +parquet = ["pyarrow (>=7.0.0)"] +performance = ["bottleneck (>=1.3.2)", "numba (>=0.53.1)", "numexpr (>=2.7.1)"] +plot = ["matplotlib (>=3.6.1)"] +postgresql = ["SQLAlchemy (>=1.4.16)", "psycopg2 (>=2.8.6)"] +spss = ["pyreadstat (>=1.1.2)"] +sql-other = ["SQLAlchemy (>=1.4.16)"] +test = ["hypothesis (>=6.34.2)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.6.3)"] [[package]] name = "pathspec" @@ -1726,38 +1745,6 @@ files = [ [package.dependencies] requests = ">=2.0.1,<3.0.0" -[[package]] -name = "scipy" -version = "1.6.1" -description = "SciPy: Scientific Library for Python" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "scipy-1.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a15a1f3fc0abff33e792d6049161b7795909b40b97c6cc2934ed54384017ab76"}, - {file = "scipy-1.6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e79570979ccdc3d165456dd62041d9556fb9733b86b4b6d818af7a0afc15f092"}, - {file = "scipy-1.6.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a423533c55fec61456dedee7b6ee7dce0bb6bfa395424ea374d25afa262be261"}, - {file = "scipy-1.6.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:33d6b7df40d197bdd3049d64e8e680227151673465e5d85723b3b8f6b15a6ced"}, - {file = "scipy-1.6.1-cp37-cp37m-win32.whl", hash = "sha256:6725e3fbb47da428794f243864f2297462e9ee448297c93ed1dcbc44335feb78"}, - {file = "scipy-1.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:5fa9c6530b1661f1370bcd332a1e62ca7881785cc0f80c0d559b636567fab63c"}, - {file = "scipy-1.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bd50daf727f7c195e26f27467c85ce653d41df4358a25b32434a50d8870fc519"}, - {file = "scipy-1.6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:f46dd15335e8a320b0fb4685f58b7471702234cba8bb3442b69a3e1dc329c345"}, - {file = "scipy-1.6.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0e5b0ccf63155d90da576edd2768b66fb276446c371b73841e3503be1d63fb5d"}, - {file = "scipy-1.6.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2481efbb3740977e3c831edfd0bd9867be26387cacf24eb5e366a6a374d3d00d"}, - {file = "scipy-1.6.1-cp38-cp38-win32.whl", hash = "sha256:68cb4c424112cd4be886b4d979c5497fba190714085f46b8ae67a5e4416c32b4"}, - {file = "scipy-1.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:5f331eeed0297232d2e6eea51b54e8278ed8bb10b099f69c44e2558c090d06bf"}, - {file = "scipy-1.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0c8a51d33556bf70367452d4d601d1742c0e806cd0194785914daf19775f0e67"}, - {file = "scipy-1.6.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:83bf7c16245c15bc58ee76c5418e46ea1811edcc2e2b03041b804e46084ab627"}, - {file = "scipy-1.6.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:794e768cc5f779736593046c9714e0f3a5940bc6dcc1dba885ad64cbfb28e9f0"}, - {file = "scipy-1.6.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5da5471aed911fe7e52b86bf9ea32fb55ae93e2f0fac66c32e58897cfb02fa07"}, - {file = "scipy-1.6.1-cp39-cp39-win32.whl", hash = "sha256:8e403a337749ed40af60e537cc4d4c03febddcc56cd26e774c9b1b600a70d3e4"}, - {file = "scipy-1.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:a5193a098ae9f29af283dcf0041f762601faf2e595c0db1da929875b7570353f"}, - {file = "scipy-1.6.1.tar.gz", hash = "sha256:c4fceb864890b6168e79b0e714c585dbe2fd4222768ee90bc1aa0f8218691b11"}, -] - -[package.dependencies] -numpy = ">=1.16.5" - [[package]] name = "scipy" version = "1.9.3" @@ -1839,55 +1826,56 @@ files = [ [[package]] name = "statsmodels" -version = "0.13.5" +version = "0.14.0" description = "Statistical computations and models for Python" category = "main" optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "statsmodels-0.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c75319fddded9507cc310fc3980e4ae4d64e3ff37b322ad5e203a84f89d85203"}, - {file = "statsmodels-0.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f148920ef27c7ba69a5735724f65de9422c0c8bcef71b50c846b823ceab8840"}, - {file = "statsmodels-0.13.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cc4d3e866bfe0c4f804bca362d0e7e29d24b840aaba8d35a754387e16d2a119"}, - {file = "statsmodels-0.13.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:072950d6f7820a6b0bd6a27b2d792a6d6f952a1d2f62f0dcf8dd808799475855"}, - {file = "statsmodels-0.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:159ae9962c61b31dcffe6356d72ae3d074bc597ad9273ec93ae653fe607b8516"}, - {file = "statsmodels-0.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9061c0d5ee4f3038b590afedd527a925e5de27195dc342381bac7675b2c5efe4"}, - {file = "statsmodels-0.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e1d89cba5fafc1bf8e75296fdfad0b619de2bfb5e6c132913991d207f3ead675"}, - {file = "statsmodels-0.13.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01bc16e7c66acb30cd3dda6004c43212c758223d1966131226024a5c99ec5a7e"}, - {file = "statsmodels-0.13.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d5cd9ab5de2c7489b890213cba2aec3d6468eaaec547041c2dfcb1e03411f7e"}, - {file = "statsmodels-0.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:857d5c0564a68a7ef77dc2252bb43c994c0699919b4e1f06a9852c2fbb588765"}, - {file = "statsmodels-0.13.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5a5348b2757ab31c5c31b498f25eff2ea3c42086bef3d3b88847c25a30bdab9c"}, - {file = "statsmodels-0.13.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b21648e3a8e7514839ba000a48e495cdd8bb55f1b71c608cf314b05541e283b"}, - {file = "statsmodels-0.13.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b829eada6cec07990f5e6820a152af4871c601fd458f76a896fb79ae2114985"}, - {file = "statsmodels-0.13.5-cp37-cp37m-win_amd64.whl", hash = "sha256:872b3a8186ef20f647c7ab5ace512a8fc050148f3c2f366460ab359eec3d9695"}, - {file = "statsmodels-0.13.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc1abb81d24f56425febd5a22bb852a1b98e53b80c4a67f50938f9512f154141"}, - {file = "statsmodels-0.13.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a2c46f1b0811a9736db37badeb102c0903f33bec80145ced3aa54df61aee5c2b"}, - {file = "statsmodels-0.13.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:947f79ba9662359f1cfa6e943851f17f72b06e55f4a7c7a2928ed3bc57ed6cb8"}, - {file = "statsmodels-0.13.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:046251c939c51e7632bcc8c6d6f31b8ca0eaffdf726d2498463f8de3735c9a82"}, - {file = "statsmodels-0.13.5-cp38-cp38-win_amd64.whl", hash = "sha256:84f720e8d611ef8f297e6d2ffa7248764e223ef7221a3fc136e47ae089609611"}, - {file = "statsmodels-0.13.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b0d1d24e4adf96ec3c64d9a027dcee2c5d5096bb0dad33b4d91034c0a3c40371"}, - {file = "statsmodels-0.13.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0f0e5c9c58fb6cba41db01504ec8dd018c96a95152266b7d5d67e0de98840474"}, - {file = "statsmodels-0.13.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b034aa4b9ad4f4d21abc4dd4841be0809a446db14c7aa5c8a65090aea9f1143"}, - {file = "statsmodels-0.13.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73f97565c29241e839ffcef74fa995afdfe781910ccc27c189e5890193085958"}, - {file = "statsmodels-0.13.5-cp39-cp39-win_amd64.whl", hash = "sha256:2ff331e508f2d1a53d3a188305477f4cf05cd8c52beb6483885eb3d51c8be3ad"}, - {file = "statsmodels-0.13.5.tar.gz", hash = "sha256:593526acae1c0fda0ea6c48439f67c3943094c542fe769f8b90fe9e6c6cc4871"}, + {file = "statsmodels-0.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:16bfe0c96a53b20fa19067e3b6bd2f1d39e30d4891ea0d7bc20734a0ae95942d"}, + {file = "statsmodels-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5a6a0a1a06ff79be8aa89c8494b33903442859add133f0dda1daf37c3c71682e"}, + {file = "statsmodels-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77b3cd3a5268ef966a0a08582c591bd29c09c88b4566c892a7c087935234f285"}, + {file = "statsmodels-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c64ebe9cf376cba0c31aed138e15ed179a1d128612dd241cdf299d159e5e882"}, + {file = "statsmodels-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:229b2f676b4a45cb62d132a105c9c06ca8a09ffba060abe34935391eb5d9ba87"}, + {file = "statsmodels-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb471f757fc45102a87e5d86e87dc2c8c78b34ad4f203679a46520f1d863b9da"}, + {file = "statsmodels-0.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:582f9e41092e342aaa04920d17cc3f97240e3ee198672f194719b5a3d08657d6"}, + {file = "statsmodels-0.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7ebe885ccaa64b4bc5ad49ac781c246e7a594b491f08ab4cfd5aa456c363a6f6"}, + {file = "statsmodels-0.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b587ee5d23369a0e881da6e37f78371dce4238cf7638a455db4b633a1a1c62d6"}, + {file = "statsmodels-0.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ef7fa4813c7a73b0d8a0c830250f021c102c71c95e9fe0d6877bcfb56d38b8c"}, + {file = "statsmodels-0.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:afe80544ef46730ea1b11cc655da27038bbaa7159dc5af4bc35bbc32982262f2"}, + {file = "statsmodels-0.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:a6ad7b8aadccd4e4dd7f315a07bef1bca41d194eeaf4ec600d20dea02d242fce"}, + {file = "statsmodels-0.14.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0eea4a0b761aebf0c355b726ac5616b9a8b618bd6e81a96b9f998a61f4fd7484"}, + {file = "statsmodels-0.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4c815ce7a699047727c65a7c179bff4031cff9ae90c78ca730cfd5200eb025dd"}, + {file = "statsmodels-0.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:575f61337c8e406ae5fa074d34bc6eb77b5a57c544b2d4ee9bc3da6a0a084cf1"}, + {file = "statsmodels-0.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8be53cdeb82f49c4cb0fda6d7eeeb2d67dbd50179b3e1033510e061863720d93"}, + {file = "statsmodels-0.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6f7d762df4e04d1dde8127d07e91aff230eae643aa7078543e60e83e7d5b40db"}, + {file = "statsmodels-0.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:fc2c7931008a911e3060c77ea8933f63f7367c0f3af04f82db3a04808ad2cd2c"}, + {file = "statsmodels-0.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3757542c95247e4ab025291a740efa5da91dc11a05990c033d40fce31c450dc9"}, + {file = "statsmodels-0.14.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:de489e3ed315bdba55c9d1554a2e89faa65d212e365ab81bc323fa52681fc60e"}, + {file = "statsmodels-0.14.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76e290f4718177bffa8823a780f3b882d56dd64ad1c18cfb4bc8b5558f3f5757"}, + {file = "statsmodels-0.14.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71054f9dbcead56def14e3c9db6f66f943110fdfb19713caf0eb0f08c1ec03fd"}, + {file = "statsmodels-0.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:d7fda067837df94e0a614d93d3a38fb6868958d37f7f50afe2a534524f2660cb"}, + {file = "statsmodels-0.14.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1c7724ad573af26139a98393ae64bc318d1b19762b13442d96c7a3e793f495c3"}, + {file = "statsmodels-0.14.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3b0a135f3bfdeec987e36e3b3b4c53e0bb87a8d91464d2fcc4d169d176f46fdb"}, + {file = "statsmodels-0.14.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce28eb1c397dba437ec39b9ab18f2101806f388c7a0cf9cdfd8f09294ad1c799"}, + {file = "statsmodels-0.14.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68b1c768dd94cc5ba8398121a632b673c625491aa7ed627b82cb4c880a25563f"}, + {file = "statsmodels-0.14.0-cp39-cp39-win_amd64.whl", hash = "sha256:8d1e3e10dfbfcd58119ba5a4d3c7d519182b970a2aebaf0b6f539f55ae16058d"}, + {file = "statsmodels-0.14.0.tar.gz", hash = "sha256:6875c7d689e966d948f15eb816ab5616f4928706b180cf470fd5907ab6f647a4"}, ] [package.dependencies] numpy = [ - {version = ">=1.17", markers = "python_version != \"3.10\" or platform_system != \"Windows\" or platform_python_implementation == \"PyPy\""}, + {version = ">=1.18", markers = "python_version != \"3.10\" or platform_system != \"Windows\" or platform_python_implementation == \"PyPy\""}, {version = ">=1.22.3", markers = "python_version == \"3.10\" and platform_system == \"Windows\" and platform_python_implementation != \"PyPy\""}, ] packaging = ">=21.3" -pandas = ">=0.25" +pandas = ">=1.0" patsy = ">=0.5.2" -scipy = [ - {version = ">=1.3", markers = "python_version > \"3.9\" and python_version < \"3.12\" or platform_system != \"Windows\" and python_version < \"3.12\" or platform_machine != \"x86\" and python_version < \"3.12\""}, - {version = ">=1.3,<1.9", markers = "python_version == \"3.8\" and platform_system == \"Windows\" and platform_machine == \"x86\" or python_version == \"3.9\" and platform_system == \"Windows\" and platform_machine == \"x86\""}, -] +scipy = ">=1.4,<1.9.2 || >1.9.2" [package.extras] -build = ["cython (>=0.29.32)"] -develop = ["Jinja2", "colorama", "cython (>=0.29.32)", "cython (>=0.29.32,<3.0.0)", "flake8", "isort", "joblib", "matplotlib (>=3)", "oldest-supported-numpy (>=2022.4.18)", "pytest (>=7.0.1,<7.1.0)", "pytest-randomly", "pytest-xdist", "pywinpty", "setuptools-scm[toml] (>=7.0.0,<7.1.0)"] +build = ["cython (>=0.29.26)"] +develop = ["colorama", "cython (>=0.29.26)", "cython (>=0.29.28,<3.0.0)", "flake8", "isort", "joblib", "matplotlib (>=3)", "oldest-supported-numpy (>=2022.4.18)", "pytest (>=7.0.1,<7.1.0)", "pytest-randomly", "pytest-xdist", "pywinpty", "setuptools-scm[toml] (>=7.0.0,<7.1.0)"] docs = ["ipykernel", "jupyter-client", "matplotlib", "nbconvert", "nbformat", "numpydoc", "pandas-datareader", "sphinx"] [[package]] @@ -1931,14 +1919,14 @@ files = [ [[package]] name = "trove-classifiers" -version = "2023.10.18" +version = "2023.11.9" description = "Canonical source for classifiers on PyPI (pypi.org)." category = "main" optional = true python-versions = "*" files = [ - {file = "trove-classifiers-2023.10.18.tar.gz", hash = "sha256:2cdfcc7f31f7ffdd57666a9957296089ac72daad4d11ab5005060e5cd7e29939"}, - {file = "trove_classifiers-2023.10.18-py3-none-any.whl", hash = "sha256:20a3da8e3cb65587cc9f5d5b837bf74edeb480bba9bd8cd4f03ab056d6b06c4c"}, + {file = "trove-classifiers-2023.11.9.tar.gz", hash = "sha256:0542bc03d151f8af84f0eb0e74aa931b374b6f9c8ed8fbf7ee41989fb9d40f1d"}, + {file = "trove_classifiers-2023.11.9-py3-none-any.whl", hash = "sha256:f9784ab55054bb327d0c8d33931fb2555b81e5b4868832490ab7959ae3ea9186"}, ] [[package]] @@ -1953,6 +1941,18 @@ files = [ {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, ] +[[package]] +name = "tzdata" +version = "2023.3" +description = "Provider of IANA time zone data" +category = "main" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, + {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, +] + [[package]] name = "urllib3" version = "2.0.7" @@ -2049,108 +2049,103 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [[package]] name = "wildboottest" -version = "0.2.0" +version = "0.3.0" description = "Wild Cluster Bootstrap Inference for Linear Models in Python" category = "main" optional = true python-versions = ">=3.8,<4.0" files = [ - {file = "wildboottest-0.2.0-py3-none-any.whl", hash = "sha256:856f60ae5dd30c7a0d1dc2767afd543d4ea2b995b014cc014022490be2a40f8b"}, - {file = "wildboottest-0.2.0.tar.gz", hash = "sha256:5d996bc22e16d8c6fcdcd5abb4111cb5761a4afa5ee400a1972a1f1743037594"}, + {file = "wildboottest-0.3.0-py3-none-any.whl", hash = "sha256:c9709ff9d48711c6bec5b919f0a782e747d2be1a76eba9ff8df804b4829e1983"}, + {file = "wildboottest-0.3.0.tar.gz", hash = "sha256:4acce091423ccf802bf106709fcd39cd48641ecca87ce3d213c43cd162cf7727"}, ] [package.dependencies] numba = ">=0.57" numpy = ">=1.18" -pandas = ">=1.4,<2.0" +pandas = ">=1.4" poetry = ">=1.4.2,<2.0.0" pytest = ">=7.2.0,<8.0.0" -statsmodels = ">=0.13,<0.14" +statsmodels = ">=0.13" tabulate = ">=0.9.0,<0.10.0" [[package]] name = "wrapt" -version = "1.15.0" +version = "1.16.0" description = "Module for decorators, wrappers and monkey patching." category = "main" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -files = [ - {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"}, - {file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"}, - {file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"}, - {file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"}, - {file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"}, - {file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"}, - {file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"}, - {file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"}, - {file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"}, - {file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"}, - {file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"}, - {file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"}, - {file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"}, - {file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"}, - {file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"}, - {file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"}, - {file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"}, - {file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"}, - {file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"}, - {file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"}, - {file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"}, - {file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"}, - {file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"}, - {file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"}, - {file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"}, - {file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"}, - {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"}, +python-versions = ">=3.6" +files = [ + {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, + {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, + {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, + {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, + {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, + {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, + {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, + {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, + {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, + {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, + {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, + {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, + {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, + {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, + {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, ] [[package]] diff --git a/pyfixest/FixestMulti.py b/pyfixest/FixestMulti.py index 5727efd4..d0cb799c 100644 --- a/pyfixest/FixestMulti.py +++ b/pyfixest/FixestMulti.py @@ -56,6 +56,7 @@ def _prepare_estimation( vcov: Union[None, str, Dict[str, str]] = None, ssc: Dict[str, str] = {}, fixef_rm: str = "none", + drop_intercept: bool = False, i_ref1: Optional[Union[List, str]] = None, i_ref2: Optional[Union[List, str]] = None, ) -> None: @@ -70,6 +71,7 @@ def _prepare_estimation( ssc (Dict[str, str], optional): A dictionary specifying the type of standard errors to use for inference. See `feols()` or `fepois()`. fixef_rm (str, optional): A string specifying whether singleton fixed effects should be dropped. Options are "none" (default) and "singleton". If "singleton", singleton fixed effects are dropped. + drop_intercept (bool, optional): Whether to drop the intercept. Default is False. i_ref1 (Optional[Union[List, str]], optional): A list or string specifying the reference category for the first interaction variable. i_ref2 (Optional[Union[List, str]], optional): A list or string specifying the reference category for the second interaction variable. @@ -85,6 +87,9 @@ def _prepare_estimation( self._drop_singletons = None self._fixef_keys = None self._is_multiple_estimation = None + self._i_ref1 = None + self._i_ref2 = None + self._drop_intercept = None # set i_ref1 and i_ref2 to list if not None if i_ref1 is not None: @@ -110,8 +115,10 @@ def _prepare_estimation( self._ssc_dict = ssc self._drop_singletons = _drop_singletons(fixef_rm) self._fixef_keys = list(self._fml_dict.keys()) + self._i_ref1 = i_ref1 self._i_ref2 = i_ref2 + self._drop_intercept = drop_intercept def _estimate_all_models( self, @@ -147,6 +154,7 @@ def _estimate_all_models( _method = self._method _drop_singletons = self._drop_singletons _ssc_dict = self._ssc_dict + _drop_intercept = self._drop_intercept _i_ref1 = self._i_ref1 _i_ref2 = self._i_ref2 @@ -184,7 +192,11 @@ def _estimate_all_models( _icovars, X_is_empty, ) = model_matrix_fixest( - fml=fml, data=_data, i_ref1=_i_ref1, i_ref2=_i_ref2 + fml=fml, + data=_data, + drop_intercept=_drop_intercept, + i_ref1=_i_ref1, + i_ref2=_i_ref2, ) weights = np.ones((Y.shape[0], 1)) diff --git a/pyfixest/estimation.py b/pyfixest/estimation.py index 58c01d34..07e79dbc 100644 --- a/pyfixest/estimation.py +++ b/pyfixest/estimation.py @@ -13,6 +13,7 @@ def feols( ssc=ssc(), fixef_rm: str = "none", collin_tol: float = 1e-10, + drop_intercept: bool = False, i_ref1: Optional[Union[list, str]] = None, i_ref2: Optional[Union[list, str]] = None, ) -> Union[Feols, FixestMulti]: @@ -70,6 +71,9 @@ def feols( via the diagonal cholesky decomposition of the correlation matrix of the variables. If the tolerance is higher, more variables will be dropped. + drop_intercept (bool): Whether to drop the intercept from the model. False by default. If True, the intercept will be dropped **after** creating the model matrix via formulaic. + This implies that reference levels for categorical variables will be dropped as well and are not recovered. + i_ref1 (Optional[Union[list, str]]): A list of strings or a string specifying the reference category for the first set of categorical variables in the formula, interacted via "i()". i_ref2 (Optional[Union[list, str]]): A list of strings or a string specifying the reference category for the second set of categorical variables in the formula, interacted via "i()". @@ -135,7 +139,9 @@ def feols( _estimation_input_checks(fml, data, vcov, ssc, fixef_rm, collin_tol, i_ref1) fixest = FixestMulti(data=data) - fixest._prepare_estimation("feols", fml, vcov, ssc, fixef_rm, i_ref1, i_ref2) + fixest._prepare_estimation( + "feols", fml, vcov, ssc, fixef_rm, drop_intercept, i_ref1, i_ref2 + ) # demean all models: based on fixed effects x split x missing value combinations fixest._estimate_all_models(vcov, fixest._fixef_keys, collin_tol=collin_tol) @@ -155,6 +161,7 @@ def fepois( iwls_tol: float = 1e-08, iwls_maxiter: int = 25, collin_tol: float = 1e-10, + drop_intercept: bool = False, i_ref1: Optional[Union[list, str]] = None, i_ref2: Optional[Union[list, str]] = None, ) -> Union[Fepois, FixestMulti]: @@ -210,6 +217,10 @@ def fepois( collin_tol (float): tolerance for collinearity check. 1e-06 by default. If collinear variables are detected, they will be dropped from the model. The performed check is via the diagonal cholesky decomposition of the correlation matrix of the variables. If the tolerance is higher, more variables will be dropped. + + drop_intercept (bool): Whether to drop the intercept from the model. False by default. If True, the intercept will be dropped **after** creating the model matrix via formulaic. + This implies that reference levels for categorical variables will be dropped as well and are not recovered. + i_ref1 (Optional[Union[list, str]]): A list of strings or a string specifying the reference category for the first set of categorical variables in the formula, interacted via "i()". i_ref2 (Optional[Union[list, str]]): A list of strings or a string specifying the reference category for the second set of categorical variables in the formula, interacted via "i()". @@ -264,7 +275,9 @@ def fepois( fixest = FixestMulti(data=data) - fixest._prepare_estimation("fepois", fml, vcov, ssc, fixef_rm, i_ref1, i_ref2) + fixest._prepare_estimation( + "fepois", fml, vcov, ssc, fixef_rm, drop_intercept, i_ref1, i_ref2 + ) if fixest._is_iv: raise NotImplementedError( "IV Estimation is not supported for Poisson Regression" diff --git a/pyfixest/experimental/did.py b/pyfixest/experimental/did.py index 7ec40ecf..b213f871 100644 --- a/pyfixest/experimental/did.py +++ b/pyfixest/experimental/did.py @@ -355,7 +355,7 @@ def _did2s_estimate( """ _first_stage_full = f"{yname} {_first_stage}" - _second_stage_full = f"{yname}_hat {_second_stage} + 0" + _second_stage_full = f"{yname}_hat {_second_stage}" if treatment is not None: if treatment not in data.columns: @@ -382,6 +382,13 @@ def _did2s_estimate( else: _not_yet_treated_data = data[data["ATT"] == False] + # check if first stage formulas has fixed effects + if "|" not in _first_stage: + raise ValueError("First stage formula must contain fixed effects.") + # check if second stage formulas has fixed effects + if "|" in _second_stage: + raise ValueError("Second stage formula must not contain fixed effects.") + # estimate first stage fit1 = feols( fml=_first_stage_full, @@ -399,8 +406,14 @@ def _did2s_estimate( _first_u = data[f"{yname}"].to_numpy().flatten() - Y_hat data[f"{yname}_hat"] = _first_u + # intercept needs to be dropped by hand due to the presence of fixed effects in the first stage fit2 = feols( - _second_stage_full, data=data, vcov="iid", i_ref1=i_ref1, i_ref2=i_ref2 + _second_stage_full, + data=data, + vcov="iid", + drop_intercept=True, + i_ref1=i_ref1, + i_ref2=i_ref2, ) _second_u = fit2.resid() @@ -447,13 +460,23 @@ def _did2s_vcov( first_stage_fe = "+".join(first_stage_fe) first_stage = f"{first_stage_x}+{first_stage_fe}" - second_stage = f"{second_stage} + 0" + second_stage = f"{second_stage}" + # note for future Alex: intercept needs to be dropped! it is not as fixed effects are converted to + # dummies, hence has_fixed checks are False _, X1, _, _, _, _, _, _, _ = model_matrix_fixest( - fml=f"{yname} {first_stage}", data=data, i_ref1=i_ref1, i_ref2=i_ref2 + fml=f"{yname} {first_stage}", + data=data, + drop_intercept=False, + i_ref1=i_ref1, + i_ref2=i_ref2, ) _, X2, _, _, _, _, _, _, _ = model_matrix_fixest( - fml=f"{yname} {second_stage}", data=data, i_ref1=i_ref1, i_ref2=i_ref2 + fml=f"{yname} {second_stage}", + data=data, + drop_intercept=True, + i_ref1=i_ref1, + i_ref2=i_ref2, ) # reference values not dropped, multicollinearity error X1 = csr_matrix(X1.values) @@ -540,6 +563,12 @@ def did2s( assert first_stage[0] == "~", "First stage must start with ~" assert second_stage[0] == "~", "Second stage must start with ~" + # assert that there is no 0, -1 or - 1 in the second stage formula + if "0" in second_stage or "-1" in second_stage: + raise ValueError( + "The second stage formula should not contain '0' or '-1'. Note that the intercept is dropped automatically due to the presence of fixed effects in the first stage." + ) + data = data.copy() fit, first_u, second_u = _did2s_estimate( diff --git a/pyfixest/model_matrix_fixest.py b/pyfixest/model_matrix_fixest.py index cb51ad72..7f81491a 100644 --- a/pyfixest/model_matrix_fixest.py +++ b/pyfixest/model_matrix_fixest.py @@ -12,6 +12,7 @@ def model_matrix_fixest( fml: str, data: pd.DataFrame, weights: Optional[str] = None, + drop_intercept=False, i_ref1: Optional[Union[List, str, int]] = None, i_ref2: Optional[Union[List, str, int]] = None, ) -> Tuple[ @@ -37,6 +38,8 @@ def model_matrix_fixest( fml (str): A two-sided formula string using fixest formula syntax. weights (str or None): Weights as a string if provided, or None if no weights, e.g., "weights". data (pd.DataFrame): The input DataFrame containing the data. + drop_intercept (bool): Whether to drop the intercept from the model matrix. Default is False. If True, the intercept is dropped ex post from the model matrix + created by formulaic. i_ref1 (str or list): The reference level for the first variable in the i() syntax. i_ref2 (str or list): The reference level for the second variable in the i() syntax. @@ -76,6 +79,12 @@ def model_matrix_fixest( _ivars = _find_ivars(fml)[0] + if _ivars: + if len(_ivars) == 2: + warnings.warn( + "The use of two interaction variables via i(var1, var2) is currently not allowed. I will fix this with the next release. Please just interact the two variables via `:` syntax." + ) + # step 1: deparse formula fml_parts = fml.split("|") depvar, covar = fml_parts[0].split("~") @@ -84,10 +93,15 @@ def model_matrix_fixest( for x in covar.split("+"): is_ivar = _find_ivars(x) if is_ivar[1]: + if i_ref1: + inner_C = f"C({_ivars[0]},contr.treatment(base={i_ref1[0]}))" + else: + inner_C = f"C({_ivars[0]})" + if len(_ivars) == 2: - interact_vars = f"C({_ivars[0]}):{_ivars[1]}" + interact_vars = f"{inner_C}:{_ivars[1]}" elif len(_ivars) == 1: - interact_vars = f"C({_ivars[0]})" + interact_vars = f"{inner_C}" else: raise ValueError( "Something went wrong with the i() syntax. Please report this issue to the package author via github." @@ -98,7 +112,6 @@ def model_matrix_fixest( # should any variables be dropped from the model matrix # (e.g., reference level dummies, if specified) _check_i_refs(_ivars, i_ref1, i_ref2, data) - _drop_ref = _get_drop_ref(_ivars, i_ref1, i_ref2) if len(fml_parts) == 3: fval, fml_iv = fml_parts[1], fml_parts[2] @@ -186,20 +199,26 @@ def model_matrix_fixest( # now drop variables before collecting variable names if _ivars is not None: - if _drop_ref: - if len(_drop_ref) == 1: - columns_to_drop = [col for col in X.columns if _drop_ref[0] in col] - else: - columns_to_drop = [ - col - for col in X.columns - if _drop_ref[0] in col or _drop_ref[1] in col - ] + if i_ref1 is not None: + if len(i_ref1) > 1: + if len(_ivars) == 1: + columns_to_drop = [ + col for col in X.columns if f"{inner_C}[T.{i_ref1[1]}]" in col + ] + if not columns_to_drop: + raise ValueError( + f"The reference level {i_ref1[1]} is not present in the data. Maybe you are using an incorrect data type?" + ) - if not X_is_empty: - X.drop(columns_to_drop, axis=1, inplace=True) - if _is_iv: - Z.drop(columns_to_drop, axis=1, inplace=True) + else: + raise ValueError( + "Currently, setting levels via the 'i_ref1' argument is only supported for one interaction variable, i.e. it fails for specifications like i(var1, var2)." + ) + + if not X_is_empty: + X.drop(columns_to_drop, axis=1, inplace=True) + if _is_iv: + Z.drop(columns_to_drop, axis=1, inplace=True) # drop reference level, if specified # ivars are needed for plotting of all interacted variables via iplot() @@ -210,11 +229,12 @@ def model_matrix_fixest( fe.drop(na_index, axis=0, inplace=True) # drop intercept if not X_is_empty: - X.drop("Intercept", axis=1, inplace=True) - # x_names.remove("Intercept") + # drop intercept. intercept is present unless there is i() interaction AND a reference level is set, in which case a "0" was added to the fml above + if "Intercept" in X.columns: + X.drop("Intercept", axis=1, inplace=True) if _is_iv: - Z.drop("Intercept", axis=1, inplace=True) - # z_names.remove("Intercept") + if "Intercept" in Z.columns: + Z.drop("Intercept", axis=1, inplace=True) # drop NaNs in fixed effects (not yet dropped via na_index) fe_na_remaining = list(set(fe_na) - set(na_index)) @@ -229,6 +249,14 @@ def model_matrix_fixest( na_index += fe_na_remaining na_index = list(set(na_index)) + # drop intercept if specified in feols() call - mostly handy for did2s() + if drop_intercept: + if "Intercept" in X.columns: + X.drop("Intercept", axis=1, inplace=True) + if _is_iv: + if "Intercept" in Z.columns: + Z.drop("Intercept", axis=1, inplace=True) + na_index_str = ",".join(str(x) for x in na_index) return Y, X, fe, endogvar, Z, na_index, na_index_str, _icovars, X_is_empty @@ -345,68 +373,6 @@ def _get_icovars(_ivars: List[str], X: pd.DataFrame) -> Optional[List[str]]: return _icovars -def _get_drop_ref( - _ivars: List[str], - i_ref1: Optional[Union[List, str, int]] = None, - i_ref2: Optional[Union[List, str, int]] = None, -) -> Optional[List[str]]: - """ - Get the name of reference level dummies to be dropped from the model matrix. - Args: - _ivars (list): A list of interaction variables. - i_ref1 (str or list): The reference level for the first variable in the i() syntax. - i_ref2 (str or list): The reference level for the second variable in the i() syntax. - Returns: - _drop_ref (list): A list of reference level dummies to be dropped from the model matrix. If no reference level is specified, None is returned. - Examples: - >>> _get_drop_ref(_ivars = ["f2", "X1"], i_ref1 = [1.0, 2.0]) - >>> ['C(f2)[T.1.0]:', 'C(f2)[T.2.0]:'] - """ - - _drop_ref = ( - None # default: if no _ivar, or if _ivar but no i_ref1, i_ref2 specified - ) - if _ivars: - _ivar1 = _ivars[0] - if i_ref1 is not None: - len_i_ref1 = len(i_ref1) - if len_i_ref1 not in [1, 2]: - raise ValueError( - f"i_ref1 must be a string or list of length 1 or 2, but it is a list of length {len_i_ref1}." - ) - if len(_ivars) == 2: - _drop_ref = [f"C({_ivar1})[T.{x}]:" for x in i_ref1] - else: # len(_ivars) == 1: - _drop_ref = [f"C({_ivar1})[T.{x}]" for x in i_ref1] - - if len(_ivars) == 2: - if i_ref2 is not None: - _ivar2 = _ivars[1] - len_i_ref2 = len(i_ref2) - if len_i_ref2 not in [1, 2]: - raise ValueError( - f"i_ref2 must be a string or list of length 1 or 2, but it is a list of length {len_i_ref2}." - ) - if len(_ivars) == 2: - _drop_ref += [f":{_ivar2}[T.{x}]" for x in i_ref2] - else: # len(_ivars) == 1: - _drop_ref += [f"{_ivar2}[T.{x}]" for x in i_ref2] - - else: - if i_ref2 is not None: - warnings.warn( - f"i_ref2 is not used because there is only one variable in the i() syntax, i({_ivar1})." - ) - - else: - if i_ref1 is not None: - warnings.warn(f"i_ref1 is not used because i() syntax is not used.") - if i_ref2 is not None: - warnings.warn(f"i_ref2 is not used because i() syntax is not used.") - - return _drop_ref - - def _check_i_refs(ivars, i_ref1, i_ref2, data): if ivars: ivar1 = ivars[0] diff --git a/pyproject.toml b/pyproject.toml index a848358d..c7824180 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pyfixest" -version = "0.10.9.0" +version = "0.10.10.0" description = "Fast high dimensional fixed effect estimation following syntax of the fixest R package. Supports OLS, IV and Poisson regression and a range of inference procedures. Additionally, experimentally supports (some of) the regression based new Difference-in-Differences Estimators (Did2s)." diff --git a/readme.md b/readme.md index b4037d81..b53add4a 100644 --- a/readme.md +++ b/readme.md @@ -24,11 +24,11 @@ At the moment, `PyFixest` supports `PyFixest` 0.10.8 adds experimental support for Gardner's two stage "DID2s" estimator: ```py +import pandas as pd +import numpy as np from pyfixest.experimental.did import did2s from pyfixest.estimation import feols from pyfixest.visualize import iplot -import pandas as pd -import numpy as np # download csv from this repo df_het = pd.read_csv("https://raw.githubusercontent.com/s3alfisc/pyfixest/master/pyfixest/experimental/data/df_het.csv") diff --git a/tests/test_did.py b/tests/test_did.py index 948d2e0e..a3a56f9d 100644 --- a/tests/test_did.py +++ b/tests/test_did.py @@ -54,13 +54,14 @@ def test_did2s(): """ df_het = pd.read_csv("pyfixest/experimental/data/df_het.csv") + df_het["X"] = np.random.normal(size=len(df_het)) # ATT, no covariates fit_did2s = did2s_pyfixest( data=df_het, yname="dep_var", first_stage="~ 0 | state + year", - second_stage="~ 0 + treat", + second_stage="~ treat", treatment="treat", cluster="state", ) @@ -80,98 +81,100 @@ def test_did2s(): np.testing.assert_allclose(fit_did2s.coef(), stats.coef(fit_did2s_r)) np.testing.assert_allclose(fit_did2s.se(), float(did2s_df[2])) - # ATT, event study - - fit = did2s_pyfixest( - df_het, - yname="dep_var", - first_stage="~ 0 | state + year", - second_stage="~i(rel_year)", - treatment="treat", - cluster="state", - i_ref1=[-1.0, np.inf], - ) + if True: + # ATT, event study - fit_r = did2s.did2s( - data=df_het, - yname="dep_var", - first_stage=ro.Formula("~ 0 | state + year"), - second_stage=ro.Formula("~ i(rel_year, ref = c(-1, Inf))"), - treatment="treat", - cluster_var="state", - ) + fit = did2s_pyfixest( + df_het, + yname="dep_var", + first_stage="~ 0 | state + year", + second_stage="~i(rel_year)", + treatment="treat", + cluster="state", + i_ref1=[-1.0, np.inf], + ) - did2s_df = broom.tidy_fixest(fit_r, conf_int=ro.BoolVector([True])) - did2s_df = pd.DataFrame(did2s_df).T + fit_r = did2s.did2s( + data=df_het, + yname="dep_var", + first_stage=ro.Formula("~ 0 | state + year"), + second_stage=ro.Formula("~ i(rel_year, ref = c(-1, Inf))"), + treatment="treat", + cluster_var="state", + ) - np.testing.assert_allclose(fit.coef(), stats.coef(fit_r)) - np.testing.assert_allclose(fit.se(), did2s_df[2].values.astype(float)) + did2s_df = broom.tidy_fixest(fit_r, conf_int=ro.BoolVector([True])) + did2s_df = pd.DataFrame(did2s_df).T - df_het["X"] = np.random.normal(size=len(df_het)) + np.testing.assert_allclose(fit.coef(), stats.coef(fit_r)) + np.testing.assert_allclose(fit.se(), did2s_df[2].values.astype(float)) - # test event study with covariate in first stage - fit = did2s_pyfixest( - df_het, - yname="dep_var", - first_stage="~ X | state + year", - second_stage="~i(rel_year)", - treatment="treat", - cluster="state", - i_ref1=[-1.0, np.inf], - ) + if True: + # test event study with covariate in first stage + fit = did2s_pyfixest( + df_het, + yname="dep_var", + first_stage="~ X | state + year", + second_stage="~i(rel_year)", + treatment="treat", + cluster="state", + i_ref1=[-1.0, np.inf], + ) - fit_r = did2s.did2s( - data=df_het, - yname="dep_var", - first_stage=ro.Formula("~ X | state + year"), - second_stage=ro.Formula("~ i(rel_year, ref = c(-1, Inf))"), - treatment="treat", - cluster_var="state", - ) + fit_r = did2s.did2s( + data=df_het, + yname="dep_var", + first_stage=ro.Formula("~ X | state + year"), + second_stage=ro.Formula("~ i(rel_year, ref = c(-1, Inf))"), + treatment="treat", + cluster_var="state", + ) - did2s_df = broom.tidy_fixest(fit_r, conf_int=ro.BoolVector([True])) - did2s_df = pd.DataFrame(did2s_df).T + did2s_df = broom.tidy_fixest(fit_r, conf_int=ro.BoolVector([True])) + did2s_df = pd.DataFrame(did2s_df).T - np.testing.assert_allclose(fit.coef(), stats.coef(fit_r)) - np.testing.assert_allclose(fit.se(), did2s_df[2].values.astype(float)) + np.testing.assert_allclose(fit.coef(), stats.coef(fit_r)) + np.testing.assert_allclose(fit.se(), did2s_df[2].values.astype(float)) - # test event study with covariate in first stage and second stage - fit = did2s_pyfixest( - df_het, - yname="dep_var", - first_stage="~ X | state + year", - second_stage="~ X + i(rel_year)", - treatment="treat", - cluster="state", - i_ref1=[-1.0, np.inf], - ) + if True: + # test event study with covariate in first stage and second stage + fit = did2s_pyfixest( + df_het, + yname="dep_var", + first_stage="~ X | state + year", + second_stage="~ X + i(rel_year)", + treatment="treat", + cluster="state", + i_ref1=[-1.0, np.inf], + ) - fit_r = did2s.did2s( - data=df_het, - yname="dep_var", - first_stage=ro.Formula("~ X | state + year"), - second_stage=ro.Formula("~ X + i(rel_year, ref = c(-1, Inf))"), - treatment="treat", - cluster_var="state", - ) + fit_r = did2s.did2s( + data=df_het, + yname="dep_var", + first_stage=ro.Formula("~ X | state + year"), + second_stage=ro.Formula("~ X + i(rel_year, ref = c(-1, Inf))"), + treatment="treat", + cluster_var="state", + ) - did2s_df = broom.tidy_fixest(fit_r, conf_int=ro.BoolVector([True])) - did2s_df = pd.DataFrame(did2s_df).T + did2s_df = broom.tidy_fixest(fit_r, conf_int=ro.BoolVector([True])) + did2s_df = pd.DataFrame(did2s_df).T - np.testing.assert_allclose(fit.coef(), stats.coef(fit_r)) - np.testing.assert_allclose(fit.se(), did2s_df[2].values.astype(float)) + np.testing.assert_allclose(fit.coef(), stats.coef(fit_r)) + np.testing.assert_allclose(fit.se(), did2s_df[2].values.astype(float)) - # binary non boolean treatment variable - df_het["treat"] = df_het["treat"].astype(int) - fit = did2s_pyfixest( - df_het, - yname="dep_var", - first_stage="~ X | state + year", - second_stage="~ X + i(rel_year)", - treatment="treat", - cluster="state", - i_ref1=[-1.0, np.inf], - ) + if True: + # binary non boolean treatment variable, just check that it runs + df_het["treat"] = df_het["treat"].astype(int) + fit = did2s_pyfixest( + df_het, + yname="dep_var", + first_stage="~ X | state + year", + second_stage="~ X + i(rel_year)", + treatment="treat", + cluster="state", + i_ref1=[-1.0, np.inf], + ) def test_errors(): diff --git a/tests/test_i.py b/tests/test_i.py index 89aecc26..297a7884 100644 --- a/tests/test_i.py +++ b/tests/test_i.py @@ -4,6 +4,17 @@ from pyfixest.estimation import feols from pyfixest.exceptions import InvalidReferenceLevelError +# rpy2 imports +from rpy2.robjects.packages import importr +import rpy2.robjects as ro +from rpy2.robjects import pandas2ri + +pandas2ri.activate() + +fixest = importr("fixest") +stats = importr("stats") +broom = importr("broom") + def test_i(): df_het = pd.read_csv("pyfixest/experimental/data/df_het.csv") @@ -30,44 +41,121 @@ def test_i(): ): raise AssertionError("C(rel_year)[T.2.0] should not be in the column names.") - if ( - "C(rel_year)[T.1.0]:treat" - in feols("dep_var~i(rel_year, treat)", df_het, i_ref1=1.0)._coefnames - ): - raise AssertionError( - "C(rel_year)[T.1.0]:treat should not be in the column names." - ) - if ( - "C(rel_year)[T.-2.0]:treat" - in feols("dep_var~i(rel_year, treat)", df_het, i_ref1=-2.0)._coefnames - ): - raise AssertionError( - "C(rel_year)[T.-2.0]:treat should not be in the column names." - ) - if ( - "C(rel_year)[T.1.0]:treat" - in feols("dep_var~i(rel_year, treat)", df_het, i_ref1=[1.0, 2.0])._coefnames - ): - raise AssertionError( - "C(rel_year)[T.1.0]:treat should not be in the column names." - ) - if ( - "C(rel_year)[T.2.0]:treat" - in feols("dep_var~i(rel_year, treat)", df_het, i_ref1=[1.0, 2.0])._coefnames - ): - raise AssertionError( - "C(rel_year)[T.2.0]:treat should not be in the column names." - ) + # if ( + # "C(rel_year)[T.1.0]:treat" + # in feols("dep_var~i(rel_year, treat)", df_het, i_ref1=1.0)._coefnames + # ): + # raise AssertionError( + # "C(rel_year)[T.1.0]:treat should not be in the column names." + # ) + # if ( + # "C(rel_year)[T.-2.0]:treat" + # in feols("dep_var~i(rel_year, treat)", df_het, i_ref1=-2.0)._coefnames + # ): + # raise AssertionError( + # "C(rel_year)[T.-2.0]:treat should not be in the column names." + # ) + # if ( + # "C(rel_year)[T.1.0]:treat" + # in feols("dep_var~i(rel_year, treat)", df_het, i_ref1=[1.0, 2.0])._coefnames + # ): + # raise AssertionError( + # "C(rel_year)[T.1.0]:treat should not be in the column names." + # ) + # if ( + # "C(rel_year)[T.2.0]:treat" + # in feols("dep_var~i(rel_year, treat)", df_het, i_ref1=[1.0, 2.0])._coefnames + # ): + # raise AssertionError( + # "C(rel_year)[T.2.0]:treat should not be in the column names." + # ) with pytest.raises(InvalidReferenceLevelError): - feols("dep_var~i(rel_year, treat)", df_het, i_ref1="1.0") + feols("dep_var~i(rel_year)", df_het, i_ref1="1.0") with pytest.raises(InvalidReferenceLevelError): - feols("dep_var~i(rel_year, treat)", df_het, i_ref1=[1]) + feols("dep_var~i(rel_year)", df_het, i_ref1=[1]) with pytest.raises(InvalidReferenceLevelError): - feols("dep_var~i(rel_year, X)", df_het, i_ref1=[1, 2]) + feols("dep_var~i(rel_year)", df_het, i_ref1=[1, 2]) with pytest.raises(AssertionError): - feols("dep_var~i(rel_year, X)", df_het, i_ref1=[1.0, "a"]) + feols("dep_var~i(rel_year)", df_het, i_ref1=[1.0, "a"]) # i_ref2 currently not supported with pytest.raises(AssertionError): feols("dep_var~i(rel_year, treat)", df_het, i_ref2="1.0") + + # with pytest.raises(ValueError): + # feols("dep_var~i(rel_year, treat)", df_het, i_ref1=1.0) + + +def test_i_vs_fixest(): + df_het = pd.read_csv("pyfixest/experimental/data/df_het.csv") + + # ---------------------------------------------------------------------------------------# + # no fixed effects + + # no references + fit_py = feols("dep_var~i(treat)", df_het) + fit_r = fixest.feols(ro.Formula("dep_var~i(treat)"), df_het) + np.testing.assert_allclose( + fit_py.coef().values, np.array(fit_r.rx2("coefficients")) + ) + + fit_py = feols("dep_var~i(rel_year)", df_het) + fit_r = fixest.feols(ro.Formula("dep_var~i(rel_year)"), df_het) + np.testing.assert_allclose( + fit_py.coef().values, np.array(fit_r.rx2("coefficients")) + ) + + # with references + fit_py = feols("dep_var~i(treat)", df_het, i_ref1=False) + fit_r = fixest.feols(ro.Formula("dep_var~i(treat, ref = FALSE)"), df_het) + np.testing.assert_allclose( + fit_py.coef().values, np.array(fit_r.rx2("coefficients")) + ) + + fit_py = feols("dep_var~i(rel_year)", df_het, i_ref1=1.0) + fit_r = fixest.feols(ro.Formula("dep_var~i(rel_year, ref = c(1))"), df_het) + np.testing.assert_allclose( + fit_py.coef().values, np.array(fit_r.rx2("coefficients")) + ) + + fit_py = feols("dep_var~i(rel_year)", df_het, i_ref1=[1.0, 2.0]) + fit_r = fixest.feols(ro.Formula("dep_var~i(rel_year, ref = c(1, 2))"), df_het) + np.testing.assert_allclose( + fit_py.coef().values, np.array(fit_r.rx2("coefficients")) + ) + + # ---------------------------------------------------------------------------------------# + # with fixed effects + + # no references + fit_py = feols("dep_var~i(treat) | year", df_het) + fit_r = fixest.feols(ro.Formula("dep_var~i(treat)|year"), df_het) + np.testing.assert_allclose( + fit_py.coef().values, np.array(fit_r.rx2("coefficients")) + ) + + fit_py = feols("dep_var~i(rel_year) | year", df_het) + fit_r = fixest.feols(ro.Formula("dep_var~i(rel_year)|year"), df_het) + np.testing.assert_allclose( + fit_py.coef().values, np.array(fit_r.rx2("coefficients")) + ) + + # with references + fit_py = feols("dep_var~i(treat) | year", df_het, i_ref1=False) + fit_r = fixest.feols(ro.Formula("dep_var~i(treat, ref = FALSE)|year"), df_het) + np.testing.assert_allclose( + fit_py.coef().values, np.array(fit_r.rx2("coefficients")) + ) + + fit_py = feols("dep_var~i(rel_year) | year", df_het, i_ref1=1.0) + fit_r = fixest.feols(ro.Formula("dep_var~i(rel_year, ref = c(1))|year"), df_het) + np.testing.assert_allclose( + fit_py.coef().values, np.array(fit_r.rx2("coefficients")) + ) + + fit_py = feols("dep_var~i(rel_year) | year", df_het, i_ref1=[1.0, 2.0]) + fit_r = fixest.feols(ro.Formula("dep_var~i(rel_year, ref = c(1, 2))|year"), df_het) + np.testing.assert_allclose( + fit_py.coef().values, np.array(fit_r.rx2("coefficients")) + ) diff --git a/tests/test_vs_fixest.py b/tests/test_vs_fixest.py index da3ba88a..521cd85e 100644 --- a/tests/test_vs_fixest.py +++ b/tests/test_vs_fixest.py @@ -63,10 +63,10 @@ # ("log(Y) ~ X1:X2 | f3 + f1"), # currently, causes big problems for Fepois (takes a long time) # ("log(Y) ~ log(X1):X2 | f3 + f1"), # currently, causes big problems for Fepois (takes a long time) # ("Y ~ X2 + exp(X1) | f3 + f1"), # currently, causes big problems for Fepois (takes a long time) - ("Y ~ X1 + i(f1,X2)"), - ("Y ~ X1 + i(f2,X2)"), - ("Y ~ X1 + i(f1,X2) | f2"), - ("Y ~ X1 + i(f1,X2) | f2 + f3"), + ("Y ~ X1 + i(f1,X2)"), # temporarily non-supported feature + ("Y ~ X1 + i(f2,X2)"), # temporarily non-supported feature + ("Y ~ X1 + i(f1,X2) | f2"), # temporarily non-supported feature + ("Y ~ X1 + i(f1,X2) | f2 + f3"), # temporarily non-supported feature # ("Y ~ i(f1,X2, ref='1.0')"), # currently does not work # ("Y ~ i(f2,X2, ref='2.0')"), # currently does not work # ("Y ~ i(f1,X2, ref='3.0') | f2"), # currently does not work @@ -571,6 +571,7 @@ def get_data_r(fml, data): return data_r +@pytest.mark.skip("Currently not supported.") def test_i_interaction(): """ Test that interaction syntax via the `i()` operator works as in fixest @@ -580,9 +581,9 @@ def test_i_interaction(): fit1 = feols("Y ~ i(f1, X2)", data=data) fit2 = feols("Y ~ X1 + i(f1, X2) | f2", data=data) - fit3 = feols("Y ~ X1 + i(f1, X2) | f2", data=data, i_ref1=1.0) - fit4 = feols("Y ~ X1 + i(f1, X2) | f2", data=data, i_ref1=[2.0]) - fit5 = feols("Y ~ X1 + i(f1, X2) | f2", data=data, i_ref1=[2.0, 3.0]) + # fit3 = feols("Y ~ X1 + i(f1, X2) | f2", data=data, i_ref1=1.0) + # fit4 = feols("Y ~ X1 + i(f1, X2) | f2", data=data, i_ref1=[2.0]) + # fit5 = feols("Y ~ X1 + i(f1, X2) | f2", data=data, i_ref1=[2.0, 3.0]) fit1_r = fixest.feols( ro.Formula("Y ~ i(f1, X2)"), @@ -594,29 +595,29 @@ def test_i_interaction(): data=data, ssc=fixest.ssc(True, "none", True, "min", "min", False), ) - fit3_r = fixest.feols( - ro.Formula("Y ~ X1 + i(f1, X2, ref = 1.0) | f2"), - data=data, - ssc=fixest.ssc(True, "none", True, "min", "min", False), - ) - fit4_r = fixest.feols( - ro.Formula("Y ~ X1 + i(f1, X2, ref = 2.0) | f2"), - data=data, - ssc=fixest.ssc(True, "none", True, "min", "min", False), - ) - fit5_r = fixest.feols( - ro.Formula("Y ~ X1 + i(f1, X2, ref = c(2.0, 3.0)) | f2"), - data=data, - ssc=fixest.ssc(True, "none", True, "min", "min", False), - ) + # fit3_r = fixest.feols( + # ro.Formula("Y ~ X1 + i(f1, X2, ref = 1.0) | f2"), + # data=data, + # ssc=fixest.ssc(True, "none", True, "min", "min", False), + # ) + # fit4_r = fixest.feols( + # ro.Formula("Y ~ X1 + i(f1, X2, ref = 2.0) | f2"), + # data=data, + # ssc=fixest.ssc(True, "none", True, "min", "min", False), + # ) + # fit5_r = fixest.feols( + # ro.Formula("Y ~ X1 + i(f1, X2, ref = c(2.0, 3.0)) | f2"), + # data=data, + # ssc=fixest.ssc(True, "none", True, "min", "min", False), + # ) # create tuples: (pyfixest, fixest) fits = [ (fit1, fit1_r), (fit2, fit2_r), - (fit3, fit3_r), - (fit4, fit4_r), - (fit5, fit5_r), + # (fit3, fit3_r), + # (fit4, fit4_r), + # (fit5, fit5_r), ] for fit in fits: