dependence-maps 0.1.1__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.
- dependence_maps-0.1.1/LICENSE +21 -0
- dependence_maps-0.1.1/PKG-INFO +183 -0
- dependence_maps-0.1.1/README.md +154 -0
- dependence_maps-0.1.1/pyproject.toml +36 -0
- dependence_maps-0.1.1/setup.cfg +4 -0
- dependence_maps-0.1.1/src/dependence_maps.egg-info/PKG-INFO +183 -0
- dependence_maps-0.1.1/src/dependence_maps.egg-info/SOURCES.txt +14 -0
- dependence_maps-0.1.1/src/dependence_maps.egg-info/dependency_links.txt +1 -0
- dependence_maps-0.1.1/src/dependence_maps.egg-info/requires.txt +10 -0
- dependence_maps-0.1.1/src/dependence_maps.egg-info/top_level.txt +1 -0
- dependence_maps-0.1.1/src/depmaps/__init__.py +21 -0
- dependence_maps-0.1.1/src/depmaps/core.py +381 -0
- dependence_maps-0.1.1/src/depmaps/inference.py +165 -0
- dependence_maps-0.1.1/src/depmaps/plotting.py +162 -0
- dependence_maps-0.1.1/src/depmaps/simulate.py +34 -0
- dependence_maps-0.1.1/tests/test_depmaps.py +298 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ivan Medovikov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dependence-maps
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Dependence maps: signed, standardized deviations of the empirical copula from independence
|
|
5
|
+
Author: Ivan Medovikov
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Brainologist/dependence-maps
|
|
8
|
+
Project-URL: Source, https://github.com/Brainologist/dependence-maps
|
|
9
|
+
Project-URL: Issues, https://github.com/Brainologist/dependence-maps/issues
|
|
10
|
+
Keywords: copula,dependence,empirical copula,independence test,nonparametric statistics,visualization,tail dependence
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: numpy>=1.22
|
|
21
|
+
Requires-Dist: scipy>=1.8
|
|
22
|
+
Requires-Dist: matplotlib>=3.5
|
|
23
|
+
Provides-Extra: pandas
|
|
24
|
+
Requires-Dist: pandas>=1.4; extra == "pandas"
|
|
25
|
+
Provides-Extra: test
|
|
26
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
27
|
+
Requires-Dist: pandas>=1.4; extra == "test"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# dependence-maps
|
|
31
|
+
|
|
32
|
+
Dependence maps: a graphical tool for visualizing dependence between two scalar random variables.
|
|
33
|
+
|
|
34
|
+
A dependence map shows, on a grid of quantile levels (u, v), the signed and standardized deviation of the empirical copula from the independence copula. It indicates where in the joint distribution two variables depart from independence: around the median, in the joint upper or lower tail, or in the off-diagonal corners. The method was presented at CFE-CMStatistics 2024 ([slides](https://github.com/Brainologist/dependence-maps/blob/main/docs/CFE2024_dependence_maps_slides.pdf)).
|
|
35
|
+
|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install dependence-maps
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The package is imported as `depmaps` (the name `depmap` was already taken on PyPI). It requires Python 3.9 or later, NumPy, SciPy and Matplotlib. pandas is optional and is only needed for `to_frame()` and the `data=` argument:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install "dependence-maps[pandas]"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
For the development version, clone [the repository](https://github.com/Brainologist/dependence-maps) and run `pip install -e ".[test]"`, then `pytest`.
|
|
51
|
+
|
|
52
|
+
## Quickstart
|
|
53
|
+
|
|
54
|
+
The data below follow a Student t copula with zero correlation and three degrees of freedom. The correlation coefficient is close to zero, but the two variables are far from independent.
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
import matplotlib.pyplot as plt
|
|
58
|
+
import depmaps as dpm
|
|
59
|
+
from depmaps.simulate import t_copula
|
|
60
|
+
|
|
61
|
+
uv = t_copula(5000, rho=0.0, df=3, rng=1)
|
|
62
|
+
x, y = uv[:, 0], uv[:, 1]
|
|
63
|
+
|
|
64
|
+
dm = dpm.dependence_map(x, y, grid=19) # quantile levels 0.05, ..., 0.95
|
|
65
|
+
dm.simultaneous_band(alpha=0.05) # critical value for max |Z| over the grid
|
|
66
|
+
print(dm.global_pvalue) # p-value of the test of independence
|
|
67
|
+
|
|
68
|
+
dm.plot() # dots mark cells that are not significant
|
|
69
|
+
plt.show()
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+

|
|
73
|
+
|
|
74
|
+
`x` and `y` can be NumPy arrays, lists or pandas Series of equal length. Pairs with a missing value are dropped. Columns of a DataFrame can be passed by name, as in `dpm.dependence_map("load", "price", data=df)`.
|
|
75
|
+
|
|
76
|
+
## Examples from the CFE 2024 talk
|
|
77
|
+
|
|
78
|
+
[`examples/cfe2024_examples.py`](https://github.com/Brainologist/dependence-maps/blob/main/examples/cfe2024_examples.py) reproduces the examples of the talk with simulated data and writes the figures below. Slide numbers refer to the [slides](https://github.com/Brainologist/dependence-maps/blob/main/docs/CFE2024_dependence_maps_slides.pdf).
|
|
79
|
+
|
|
80
|
+
### Linear dependence (Example 1, slides 3 and 19–20)
|
|
81
|
+
|
|
82
|
+
Gaussian copula with ρ = 0.8. The raw deviation Cₙ(u, v) − uv (middle panel) is largest at the median, but only because it must vanish at the edges of the unit square. The standardized map (right) shows dependence of similar strength along the whole diagonal.
|
|
83
|
+
|
|
84
|
+

|
|
85
|
+
|
|
86
|
+
### Tail dependence without correlation (Example 2, slides 4 and 21–23)
|
|
87
|
+
|
|
88
|
+
Student t copula with ρ = 0 and three degrees of freedom. Joint extremes of the same sign occur more often than under independence (red corners) and extremes of opposite sign less often (blue corners). The centre of the map shows nothing.
|
|
89
|
+
|
|
90
|
+

|
|
91
|
+
|
|
92
|
+
### Independence (slides 16–18)
|
|
93
|
+
|
|
94
|
+
Even under independence the map shows streaks, since neighbouring cells are strongly correlated. Significance is therefore judged against a simultaneous critical value, about 3.5 for a 19×19 grid, rather than the pointwise 1.96.
|
|
95
|
+
|
|
96
|
+

|
|
97
|
+
|
|
98
|
+
### U-shaped dependence in a time series (compare slides 31–33)
|
|
99
|
+
|
|
100
|
+
Simulated hourly temperature and power price, with the price rising in both cold and hot weather, much as in the temperature and day-ahead price application of the talk. The map is blue on the cold side and red on the hot side, whereas a map of absolute deviations would show both sides as a single region of strong dependence. Both series are strongly autocorrelated, so the map is computed with `serial="hac"`. This is the figure at the top of the page.
|
|
101
|
+
|
|
102
|
+
### Lower-tail dependence (compare slides 34–36)
|
|
103
|
+
|
|
104
|
+
Clayton copula with θ = 2, where dependence is strongest in the joint lower tail. The load and day-ahead price application of the talk shows a similar asymmetry.
|
|
105
|
+
|
|
106
|
+

|
|
107
|
+
|
|
108
|
+
## The statistic
|
|
109
|
+
|
|
110
|
+
For a sample (X₁, Y₁), …, (Xₙ, Yₙ) with empirical copula Cₙ, the map is
|
|
111
|
+
|
|
112
|
+
Z(u, v) = √n (Cₙ(u, v) − uv) / √(u(1 − u) v(1 − v)).
|
|
113
|
+
|
|
114
|
+
When there are ties, u and v are replaced by the largest attainable marginal levels not exceeding them, which keeps the statistic exact.
|
|
115
|
+
|
|
116
|
+
The map is intuitive and easy to read since:
|
|
117
|
+
|
|
118
|
+
1. Z(u, v) is a statistic for a 2×2 table. If X is dichotomized at its u-quantile and Y at its v-quantile, then Z(u, v) = √n φ(u, v), where φ is the phi coefficient of the resulting table, and Z² is its Pearson χ² statistic. φ does not depend on the sample size and is available as `dm.phi`. Note, however, that the margins of the table bound |φ| from above. The bound equals 1 on the diagonal u = v but falls quickly away from it, and at (0.1, 0.9) φ cannot exceed 1/9 even under perfect dependence. `dm.phi_rel` = φ/φ_max corrects for this and equals ±1 everywhere under perfect positive or negative dependence.
|
|
119
|
+
2. Under independence and i.i.d. sampling, Z(u, v) is asymptotically N(0, 1) at every point, and the map as a whole converges to a Gaussian field with covariance ρ(u, u′)ρ(v, v′), where ρ(s, t) = (s∧t − st)/√(s(1 − s)t(1 − t)). This covariance contains no unknown quantities, so simultaneous critical values can be obtained by simulation, without resampling. Continuous margins are not required.
|
|
120
|
+
3. The sign carries information. Red cells indicate positive quadrant dependence at (u, v), meaning that the joint lower and joint upper orthants contain more observations than under independence, while blue cells indicate the opposite. A map of |Z| cannot distinguish the two and shows a U-shaped relationship as a single region of strong dependence.
|
|
121
|
+
|
|
122
|
+
The raw deviation Cₙ − uv is also available (`which="raw"`), but we do not recommend using it on its own. By the Fréchet bounds it tends to zero at the edges of the unit square regardless of the strength of dependence, which exaggerates dependence near the median.
|
|
123
|
+
|
|
124
|
+
## Usage
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
import depmaps as dpm
|
|
128
|
+
|
|
129
|
+
dm = dpm.dependence_map(x, y, grid=19) # levels 0.05, ..., 0.95
|
|
130
|
+
dm.simultaneous_band(alpha=0.05) # critical value for max |Z|
|
|
131
|
+
dm.plot() # signed map; dots mark non-significant cells
|
|
132
|
+
dm.plot(which="phi_rel") # effect size relative to its bound
|
|
133
|
+
dm.to_frame() # map as a table (needs pandas)
|
|
134
|
+
dm.global_pvalue # sup-norm test of independence
|
|
135
|
+
|
|
136
|
+
# serially dependent data
|
|
137
|
+
dm = dpm.dependence_map("load", "price", data=df, grid=19,
|
|
138
|
+
serial="hac") # lag by the Andrews (1991) rule
|
|
139
|
+
dm = dpm.dependence_map("load", "price", data=df, grid=19,
|
|
140
|
+
serial="hac", max_lag=168) # or a fixed lag
|
|
141
|
+
dm.simultaneous_band(method="gaussian") # HAC Gaussian null
|
|
142
|
+
dm.simultaneous_band(method="shift") # circular shifts of Y
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Inference
|
|
146
|
+
|
|
147
|
+
Simultaneous critical values can be computed in four ways:
|
|
148
|
+
|
|
149
|
+
| method | null distribution | valid for |
|
|
150
|
+
|---|---|---|
|
|
151
|
+
| `gaussian` | Gaussian field with known covariance | i.i.d. data |
|
|
152
|
+
| `gaussian` with `serial="hac"` | Gaussian field with covariance Σ_h w_h Γ_A(h) ⊗ Γ_B(h), estimated | stationary, weakly dependent series |
|
|
153
|
+
| `permutation` | random permutations of Y | i.i.d. data, exact under ties |
|
|
154
|
+
| `shift` | random circular shifts of Y | stationary series |
|
|
155
|
+
|
|
156
|
+
The HAC Gaussian null uses a dense covariance matrix over all pairs of grid cells and is therefore limited to 2,500 cells (a 49×49 grid). For finer grids, use `shift`.
|
|
157
|
+
|
|
158
|
+
Under serial dependence, the pointwise null variance of √n(Cₙ − uv) equals Σ_h γ_A(h)γ_B(h), where A_t = 1{U_t ≤ u} − u and B_t = 1{V_t ≤ v} − v are centred indicator series. With `serial="hac"`, the ratio κ(u, v) of this long-run variance to its i.i.d. counterpart is estimated with Bartlett weights and the map reports Z/√κ. The truncation lag is chosen by the AR(1) plug-in rule of Andrews (1991) applied to A_t B_t. The Newey–West rule of thumb is available as `max_lag="nw"`, but it is much too short for persistent series such as hourly prices. For persistent and seasonal series κ can be large and may keep growing with the lag, so results should be reported for several lags.
|
|
159
|
+
|
|
160
|
+
## Tests
|
|
161
|
+
|
|
162
|
+
Running `pytest` checks both the code and the underlying theory. Among other things, the tests verify that:
|
|
163
|
+
|
|
164
|
+
- the raw deviation at the centre of the Gaussian copula equals arcsin(ρ)/2π, and Z² equals the χ² statistic of the corresponding 2×2 table;
|
|
165
|
+
- the statistic remains exact under ties and is standard normal under independence;
|
|
166
|
+
- the simultaneous band has the correct size, and Gaussian and permutation critical values agree;
|
|
167
|
+
- the map detects dependence that is confined to the tails;
|
|
168
|
+
- for AR(1) series, the HAC correction restores unit null variance and gives a band of approximately correct size;
|
|
169
|
+
- φ/φ_max equals ±1 under perfect dependence, and the plug-in lag increases with persistence;
|
|
170
|
+
- the copula samplers have uniform margins and the correct Kendall's τ;
|
|
171
|
+
- invalid input (grid and lag arguments, misaligned indexes) is rejected with a clear error.
|
|
172
|
+
|
|
173
|
+
## Citing
|
|
174
|
+
|
|
175
|
+
If you use the package, please cite:
|
|
176
|
+
|
|
177
|
+
> Medovikov, I. (2024). *Dependence Maps: A Graphical Tool for Visualizing Dependence.* 18th International Conference on Computational and Financial Econometrics (CFE-CMStatistics 2024), King's College London, 14–16 December 2024.
|
|
178
|
+
|
|
179
|
+
The repository includes a `CITATION.cff` file, which GitHub uses for its "Cite this repository" button.
|
|
180
|
+
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
MIT; see [`LICENSE`](https://github.com/Brainologist/dependence-maps/blob/main/LICENSE).
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# dependence-maps
|
|
2
|
+
|
|
3
|
+
Dependence maps: a graphical tool for visualizing dependence between two scalar random variables.
|
|
4
|
+
|
|
5
|
+
A dependence map shows, on a grid of quantile levels (u, v), the signed and standardized deviation of the empirical copula from the independence copula. It indicates where in the joint distribution two variables depart from independence: around the median, in the joint upper or lower tail, or in the off-diagonal corners. The method was presented at CFE-CMStatistics 2024 ([slides](https://github.com/Brainologist/dependence-maps/blob/main/docs/CFE2024_dependence_maps_slides.pdf)).
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install dependence-maps
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The package is imported as `depmaps` (the name `depmap` was already taken on PyPI). It requires Python 3.9 or later, NumPy, SciPy and Matplotlib. pandas is optional and is only needed for `to_frame()` and the `data=` argument:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install "dependence-maps[pandas]"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
For the development version, clone [the repository](https://github.com/Brainologist/dependence-maps) and run `pip install -e ".[test]"`, then `pytest`.
|
|
22
|
+
|
|
23
|
+
## Quickstart
|
|
24
|
+
|
|
25
|
+
The data below follow a Student t copula with zero correlation and three degrees of freedom. The correlation coefficient is close to zero, but the two variables are far from independent.
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
import matplotlib.pyplot as plt
|
|
29
|
+
import depmaps as dpm
|
|
30
|
+
from depmaps.simulate import t_copula
|
|
31
|
+
|
|
32
|
+
uv = t_copula(5000, rho=0.0, df=3, rng=1)
|
|
33
|
+
x, y = uv[:, 0], uv[:, 1]
|
|
34
|
+
|
|
35
|
+
dm = dpm.dependence_map(x, y, grid=19) # quantile levels 0.05, ..., 0.95
|
|
36
|
+
dm.simultaneous_band(alpha=0.05) # critical value for max |Z| over the grid
|
|
37
|
+
print(dm.global_pvalue) # p-value of the test of independence
|
|
38
|
+
|
|
39
|
+
dm.plot() # dots mark cells that are not significant
|
|
40
|
+
plt.show()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+

|
|
44
|
+
|
|
45
|
+
`x` and `y` can be NumPy arrays, lists or pandas Series of equal length. Pairs with a missing value are dropped. Columns of a DataFrame can be passed by name, as in `dpm.dependence_map("load", "price", data=df)`.
|
|
46
|
+
|
|
47
|
+
## Examples from the CFE 2024 talk
|
|
48
|
+
|
|
49
|
+
[`examples/cfe2024_examples.py`](https://github.com/Brainologist/dependence-maps/blob/main/examples/cfe2024_examples.py) reproduces the examples of the talk with simulated data and writes the figures below. Slide numbers refer to the [slides](https://github.com/Brainologist/dependence-maps/blob/main/docs/CFE2024_dependence_maps_slides.pdf).
|
|
50
|
+
|
|
51
|
+
### Linear dependence (Example 1, slides 3 and 19–20)
|
|
52
|
+
|
|
53
|
+
Gaussian copula with ρ = 0.8. The raw deviation Cₙ(u, v) − uv (middle panel) is largest at the median, but only because it must vanish at the edges of the unit square. The standardized map (right) shows dependence of similar strength along the whole diagonal.
|
|
54
|
+
|
|
55
|
+

|
|
56
|
+
|
|
57
|
+
### Tail dependence without correlation (Example 2, slides 4 and 21–23)
|
|
58
|
+
|
|
59
|
+
Student t copula with ρ = 0 and three degrees of freedom. Joint extremes of the same sign occur more often than under independence (red corners) and extremes of opposite sign less often (blue corners). The centre of the map shows nothing.
|
|
60
|
+
|
|
61
|
+

|
|
62
|
+
|
|
63
|
+
### Independence (slides 16–18)
|
|
64
|
+
|
|
65
|
+
Even under independence the map shows streaks, since neighbouring cells are strongly correlated. Significance is therefore judged against a simultaneous critical value, about 3.5 for a 19×19 grid, rather than the pointwise 1.96.
|
|
66
|
+
|
|
67
|
+

|
|
68
|
+
|
|
69
|
+
### U-shaped dependence in a time series (compare slides 31–33)
|
|
70
|
+
|
|
71
|
+
Simulated hourly temperature and power price, with the price rising in both cold and hot weather, much as in the temperature and day-ahead price application of the talk. The map is blue on the cold side and red on the hot side, whereas a map of absolute deviations would show both sides as a single region of strong dependence. Both series are strongly autocorrelated, so the map is computed with `serial="hac"`. This is the figure at the top of the page.
|
|
72
|
+
|
|
73
|
+
### Lower-tail dependence (compare slides 34–36)
|
|
74
|
+
|
|
75
|
+
Clayton copula with θ = 2, where dependence is strongest in the joint lower tail. The load and day-ahead price application of the talk shows a similar asymmetry.
|
|
76
|
+
|
|
77
|
+

|
|
78
|
+
|
|
79
|
+
## The statistic
|
|
80
|
+
|
|
81
|
+
For a sample (X₁, Y₁), …, (Xₙ, Yₙ) with empirical copula Cₙ, the map is
|
|
82
|
+
|
|
83
|
+
Z(u, v) = √n (Cₙ(u, v) − uv) / √(u(1 − u) v(1 − v)).
|
|
84
|
+
|
|
85
|
+
When there are ties, u and v are replaced by the largest attainable marginal levels not exceeding them, which keeps the statistic exact.
|
|
86
|
+
|
|
87
|
+
The map is intuitive and easy to read since:
|
|
88
|
+
|
|
89
|
+
1. Z(u, v) is a statistic for a 2×2 table. If X is dichotomized at its u-quantile and Y at its v-quantile, then Z(u, v) = √n φ(u, v), where φ is the phi coefficient of the resulting table, and Z² is its Pearson χ² statistic. φ does not depend on the sample size and is available as `dm.phi`. Note, however, that the margins of the table bound |φ| from above. The bound equals 1 on the diagonal u = v but falls quickly away from it, and at (0.1, 0.9) φ cannot exceed 1/9 even under perfect dependence. `dm.phi_rel` = φ/φ_max corrects for this and equals ±1 everywhere under perfect positive or negative dependence.
|
|
90
|
+
2. Under independence and i.i.d. sampling, Z(u, v) is asymptotically N(0, 1) at every point, and the map as a whole converges to a Gaussian field with covariance ρ(u, u′)ρ(v, v′), where ρ(s, t) = (s∧t − st)/√(s(1 − s)t(1 − t)). This covariance contains no unknown quantities, so simultaneous critical values can be obtained by simulation, without resampling. Continuous margins are not required.
|
|
91
|
+
3. The sign carries information. Red cells indicate positive quadrant dependence at (u, v), meaning that the joint lower and joint upper orthants contain more observations than under independence, while blue cells indicate the opposite. A map of |Z| cannot distinguish the two and shows a U-shaped relationship as a single region of strong dependence.
|
|
92
|
+
|
|
93
|
+
The raw deviation Cₙ − uv is also available (`which="raw"`), but we do not recommend using it on its own. By the Fréchet bounds it tends to zero at the edges of the unit square regardless of the strength of dependence, which exaggerates dependence near the median.
|
|
94
|
+
|
|
95
|
+
## Usage
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
import depmaps as dpm
|
|
99
|
+
|
|
100
|
+
dm = dpm.dependence_map(x, y, grid=19) # levels 0.05, ..., 0.95
|
|
101
|
+
dm.simultaneous_band(alpha=0.05) # critical value for max |Z|
|
|
102
|
+
dm.plot() # signed map; dots mark non-significant cells
|
|
103
|
+
dm.plot(which="phi_rel") # effect size relative to its bound
|
|
104
|
+
dm.to_frame() # map as a table (needs pandas)
|
|
105
|
+
dm.global_pvalue # sup-norm test of independence
|
|
106
|
+
|
|
107
|
+
# serially dependent data
|
|
108
|
+
dm = dpm.dependence_map("load", "price", data=df, grid=19,
|
|
109
|
+
serial="hac") # lag by the Andrews (1991) rule
|
|
110
|
+
dm = dpm.dependence_map("load", "price", data=df, grid=19,
|
|
111
|
+
serial="hac", max_lag=168) # or a fixed lag
|
|
112
|
+
dm.simultaneous_band(method="gaussian") # HAC Gaussian null
|
|
113
|
+
dm.simultaneous_band(method="shift") # circular shifts of Y
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Inference
|
|
117
|
+
|
|
118
|
+
Simultaneous critical values can be computed in four ways:
|
|
119
|
+
|
|
120
|
+
| method | null distribution | valid for |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| `gaussian` | Gaussian field with known covariance | i.i.d. data |
|
|
123
|
+
| `gaussian` with `serial="hac"` | Gaussian field with covariance Σ_h w_h Γ_A(h) ⊗ Γ_B(h), estimated | stationary, weakly dependent series |
|
|
124
|
+
| `permutation` | random permutations of Y | i.i.d. data, exact under ties |
|
|
125
|
+
| `shift` | random circular shifts of Y | stationary series |
|
|
126
|
+
|
|
127
|
+
The HAC Gaussian null uses a dense covariance matrix over all pairs of grid cells and is therefore limited to 2,500 cells (a 49×49 grid). For finer grids, use `shift`.
|
|
128
|
+
|
|
129
|
+
Under serial dependence, the pointwise null variance of √n(Cₙ − uv) equals Σ_h γ_A(h)γ_B(h), where A_t = 1{U_t ≤ u} − u and B_t = 1{V_t ≤ v} − v are centred indicator series. With `serial="hac"`, the ratio κ(u, v) of this long-run variance to its i.i.d. counterpart is estimated with Bartlett weights and the map reports Z/√κ. The truncation lag is chosen by the AR(1) plug-in rule of Andrews (1991) applied to A_t B_t. The Newey–West rule of thumb is available as `max_lag="nw"`, but it is much too short for persistent series such as hourly prices. For persistent and seasonal series κ can be large and may keep growing with the lag, so results should be reported for several lags.
|
|
130
|
+
|
|
131
|
+
## Tests
|
|
132
|
+
|
|
133
|
+
Running `pytest` checks both the code and the underlying theory. Among other things, the tests verify that:
|
|
134
|
+
|
|
135
|
+
- the raw deviation at the centre of the Gaussian copula equals arcsin(ρ)/2π, and Z² equals the χ² statistic of the corresponding 2×2 table;
|
|
136
|
+
- the statistic remains exact under ties and is standard normal under independence;
|
|
137
|
+
- the simultaneous band has the correct size, and Gaussian and permutation critical values agree;
|
|
138
|
+
- the map detects dependence that is confined to the tails;
|
|
139
|
+
- for AR(1) series, the HAC correction restores unit null variance and gives a band of approximately correct size;
|
|
140
|
+
- φ/φ_max equals ±1 under perfect dependence, and the plug-in lag increases with persistence;
|
|
141
|
+
- the copula samplers have uniform margins and the correct Kendall's τ;
|
|
142
|
+
- invalid input (grid and lag arguments, misaligned indexes) is rejected with a clear error.
|
|
143
|
+
|
|
144
|
+
## Citing
|
|
145
|
+
|
|
146
|
+
If you use the package, please cite:
|
|
147
|
+
|
|
148
|
+
> Medovikov, I. (2024). *Dependence Maps: A Graphical Tool for Visualizing Dependence.* 18th International Conference on Computational and Financial Econometrics (CFE-CMStatistics 2024), King's College London, 14–16 December 2024.
|
|
149
|
+
|
|
150
|
+
The repository includes a `CITATION.cff` file, which GitHub uses for its "Cite this repository" button.
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
MIT; see [`LICENSE`](https://github.com/Brainologist/dependence-maps/blob/main/LICENSE).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "dependence-maps"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "Dependence maps: signed, standardized deviations of the empirical copula from independence"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{name = "Ivan Medovikov"}]
|
|
14
|
+
keywords = ["copula", "dependence", "empirical copula", "independence test",
|
|
15
|
+
"nonparametric statistics", "visualization", "tail dependence"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
22
|
+
"Topic :: Scientific/Engineering :: Visualization",
|
|
23
|
+
]
|
|
24
|
+
dependencies = ["numpy>=1.22", "scipy>=1.8", "matplotlib>=3.5"]
|
|
25
|
+
|
|
26
|
+
[project.optional-dependencies]
|
|
27
|
+
pandas = ["pandas>=1.4"]
|
|
28
|
+
test = ["pytest>=7", "pandas>=1.4"]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://github.com/Brainologist/dependence-maps"
|
|
32
|
+
Source = "https://github.com/Brainologist/dependence-maps"
|
|
33
|
+
Issues = "https://github.com/Brainologist/dependence-maps/issues"
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.packages.find]
|
|
36
|
+
where = ["src"]
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dependence-maps
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Dependence maps: signed, standardized deviations of the empirical copula from independence
|
|
5
|
+
Author: Ivan Medovikov
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Brainologist/dependence-maps
|
|
8
|
+
Project-URL: Source, https://github.com/Brainologist/dependence-maps
|
|
9
|
+
Project-URL: Issues, https://github.com/Brainologist/dependence-maps/issues
|
|
10
|
+
Keywords: copula,dependence,empirical copula,independence test,nonparametric statistics,visualization,tail dependence
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: numpy>=1.22
|
|
21
|
+
Requires-Dist: scipy>=1.8
|
|
22
|
+
Requires-Dist: matplotlib>=3.5
|
|
23
|
+
Provides-Extra: pandas
|
|
24
|
+
Requires-Dist: pandas>=1.4; extra == "pandas"
|
|
25
|
+
Provides-Extra: test
|
|
26
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
27
|
+
Requires-Dist: pandas>=1.4; extra == "test"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# dependence-maps
|
|
31
|
+
|
|
32
|
+
Dependence maps: a graphical tool for visualizing dependence between two scalar random variables.
|
|
33
|
+
|
|
34
|
+
A dependence map shows, on a grid of quantile levels (u, v), the signed and standardized deviation of the empirical copula from the independence copula. It indicates where in the joint distribution two variables depart from independence: around the median, in the joint upper or lower tail, or in the off-diagonal corners. The method was presented at CFE-CMStatistics 2024 ([slides](https://github.com/Brainologist/dependence-maps/blob/main/docs/CFE2024_dependence_maps_slides.pdf)).
|
|
35
|
+
|
|
36
|
+

|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install dependence-maps
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The package is imported as `depmaps` (the name `depmap` was already taken on PyPI). It requires Python 3.9 or later, NumPy, SciPy and Matplotlib. pandas is optional and is only needed for `to_frame()` and the `data=` argument:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install "dependence-maps[pandas]"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
For the development version, clone [the repository](https://github.com/Brainologist/dependence-maps) and run `pip install -e ".[test]"`, then `pytest`.
|
|
51
|
+
|
|
52
|
+
## Quickstart
|
|
53
|
+
|
|
54
|
+
The data below follow a Student t copula with zero correlation and three degrees of freedom. The correlation coefficient is close to zero, but the two variables are far from independent.
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
import matplotlib.pyplot as plt
|
|
58
|
+
import depmaps as dpm
|
|
59
|
+
from depmaps.simulate import t_copula
|
|
60
|
+
|
|
61
|
+
uv = t_copula(5000, rho=0.0, df=3, rng=1)
|
|
62
|
+
x, y = uv[:, 0], uv[:, 1]
|
|
63
|
+
|
|
64
|
+
dm = dpm.dependence_map(x, y, grid=19) # quantile levels 0.05, ..., 0.95
|
|
65
|
+
dm.simultaneous_band(alpha=0.05) # critical value for max |Z| over the grid
|
|
66
|
+
print(dm.global_pvalue) # p-value of the test of independence
|
|
67
|
+
|
|
68
|
+
dm.plot() # dots mark cells that are not significant
|
|
69
|
+
plt.show()
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+

|
|
73
|
+
|
|
74
|
+
`x` and `y` can be NumPy arrays, lists or pandas Series of equal length. Pairs with a missing value are dropped. Columns of a DataFrame can be passed by name, as in `dpm.dependence_map("load", "price", data=df)`.
|
|
75
|
+
|
|
76
|
+
## Examples from the CFE 2024 talk
|
|
77
|
+
|
|
78
|
+
[`examples/cfe2024_examples.py`](https://github.com/Brainologist/dependence-maps/blob/main/examples/cfe2024_examples.py) reproduces the examples of the talk with simulated data and writes the figures below. Slide numbers refer to the [slides](https://github.com/Brainologist/dependence-maps/blob/main/docs/CFE2024_dependence_maps_slides.pdf).
|
|
79
|
+
|
|
80
|
+
### Linear dependence (Example 1, slides 3 and 19–20)
|
|
81
|
+
|
|
82
|
+
Gaussian copula with ρ = 0.8. The raw deviation Cₙ(u, v) − uv (middle panel) is largest at the median, but only because it must vanish at the edges of the unit square. The standardized map (right) shows dependence of similar strength along the whole diagonal.
|
|
83
|
+
|
|
84
|
+

|
|
85
|
+
|
|
86
|
+
### Tail dependence without correlation (Example 2, slides 4 and 21–23)
|
|
87
|
+
|
|
88
|
+
Student t copula with ρ = 0 and three degrees of freedom. Joint extremes of the same sign occur more often than under independence (red corners) and extremes of opposite sign less often (blue corners). The centre of the map shows nothing.
|
|
89
|
+
|
|
90
|
+

|
|
91
|
+
|
|
92
|
+
### Independence (slides 16–18)
|
|
93
|
+
|
|
94
|
+
Even under independence the map shows streaks, since neighbouring cells are strongly correlated. Significance is therefore judged against a simultaneous critical value, about 3.5 for a 19×19 grid, rather than the pointwise 1.96.
|
|
95
|
+
|
|
96
|
+

|
|
97
|
+
|
|
98
|
+
### U-shaped dependence in a time series (compare slides 31–33)
|
|
99
|
+
|
|
100
|
+
Simulated hourly temperature and power price, with the price rising in both cold and hot weather, much as in the temperature and day-ahead price application of the talk. The map is blue on the cold side and red on the hot side, whereas a map of absolute deviations would show both sides as a single region of strong dependence. Both series are strongly autocorrelated, so the map is computed with `serial="hac"`. This is the figure at the top of the page.
|
|
101
|
+
|
|
102
|
+
### Lower-tail dependence (compare slides 34–36)
|
|
103
|
+
|
|
104
|
+
Clayton copula with θ = 2, where dependence is strongest in the joint lower tail. The load and day-ahead price application of the talk shows a similar asymmetry.
|
|
105
|
+
|
|
106
|
+

|
|
107
|
+
|
|
108
|
+
## The statistic
|
|
109
|
+
|
|
110
|
+
For a sample (X₁, Y₁), …, (Xₙ, Yₙ) with empirical copula Cₙ, the map is
|
|
111
|
+
|
|
112
|
+
Z(u, v) = √n (Cₙ(u, v) − uv) / √(u(1 − u) v(1 − v)).
|
|
113
|
+
|
|
114
|
+
When there are ties, u and v are replaced by the largest attainable marginal levels not exceeding them, which keeps the statistic exact.
|
|
115
|
+
|
|
116
|
+
The map is intuitive and easy to read since:
|
|
117
|
+
|
|
118
|
+
1. Z(u, v) is a statistic for a 2×2 table. If X is dichotomized at its u-quantile and Y at its v-quantile, then Z(u, v) = √n φ(u, v), where φ is the phi coefficient of the resulting table, and Z² is its Pearson χ² statistic. φ does not depend on the sample size and is available as `dm.phi`. Note, however, that the margins of the table bound |φ| from above. The bound equals 1 on the diagonal u = v but falls quickly away from it, and at (0.1, 0.9) φ cannot exceed 1/9 even under perfect dependence. `dm.phi_rel` = φ/φ_max corrects for this and equals ±1 everywhere under perfect positive or negative dependence.
|
|
119
|
+
2. Under independence and i.i.d. sampling, Z(u, v) is asymptotically N(0, 1) at every point, and the map as a whole converges to a Gaussian field with covariance ρ(u, u′)ρ(v, v′), where ρ(s, t) = (s∧t − st)/√(s(1 − s)t(1 − t)). This covariance contains no unknown quantities, so simultaneous critical values can be obtained by simulation, without resampling. Continuous margins are not required.
|
|
120
|
+
3. The sign carries information. Red cells indicate positive quadrant dependence at (u, v), meaning that the joint lower and joint upper orthants contain more observations than under independence, while blue cells indicate the opposite. A map of |Z| cannot distinguish the two and shows a U-shaped relationship as a single region of strong dependence.
|
|
121
|
+
|
|
122
|
+
The raw deviation Cₙ − uv is also available (`which="raw"`), but we do not recommend using it on its own. By the Fréchet bounds it tends to zero at the edges of the unit square regardless of the strength of dependence, which exaggerates dependence near the median.
|
|
123
|
+
|
|
124
|
+
## Usage
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
import depmaps as dpm
|
|
128
|
+
|
|
129
|
+
dm = dpm.dependence_map(x, y, grid=19) # levels 0.05, ..., 0.95
|
|
130
|
+
dm.simultaneous_band(alpha=0.05) # critical value for max |Z|
|
|
131
|
+
dm.plot() # signed map; dots mark non-significant cells
|
|
132
|
+
dm.plot(which="phi_rel") # effect size relative to its bound
|
|
133
|
+
dm.to_frame() # map as a table (needs pandas)
|
|
134
|
+
dm.global_pvalue # sup-norm test of independence
|
|
135
|
+
|
|
136
|
+
# serially dependent data
|
|
137
|
+
dm = dpm.dependence_map("load", "price", data=df, grid=19,
|
|
138
|
+
serial="hac") # lag by the Andrews (1991) rule
|
|
139
|
+
dm = dpm.dependence_map("load", "price", data=df, grid=19,
|
|
140
|
+
serial="hac", max_lag=168) # or a fixed lag
|
|
141
|
+
dm.simultaneous_band(method="gaussian") # HAC Gaussian null
|
|
142
|
+
dm.simultaneous_band(method="shift") # circular shifts of Y
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Inference
|
|
146
|
+
|
|
147
|
+
Simultaneous critical values can be computed in four ways:
|
|
148
|
+
|
|
149
|
+
| method | null distribution | valid for |
|
|
150
|
+
|---|---|---|
|
|
151
|
+
| `gaussian` | Gaussian field with known covariance | i.i.d. data |
|
|
152
|
+
| `gaussian` with `serial="hac"` | Gaussian field with covariance Σ_h w_h Γ_A(h) ⊗ Γ_B(h), estimated | stationary, weakly dependent series |
|
|
153
|
+
| `permutation` | random permutations of Y | i.i.d. data, exact under ties |
|
|
154
|
+
| `shift` | random circular shifts of Y | stationary series |
|
|
155
|
+
|
|
156
|
+
The HAC Gaussian null uses a dense covariance matrix over all pairs of grid cells and is therefore limited to 2,500 cells (a 49×49 grid). For finer grids, use `shift`.
|
|
157
|
+
|
|
158
|
+
Under serial dependence, the pointwise null variance of √n(Cₙ − uv) equals Σ_h γ_A(h)γ_B(h), where A_t = 1{U_t ≤ u} − u and B_t = 1{V_t ≤ v} − v are centred indicator series. With `serial="hac"`, the ratio κ(u, v) of this long-run variance to its i.i.d. counterpart is estimated with Bartlett weights and the map reports Z/√κ. The truncation lag is chosen by the AR(1) plug-in rule of Andrews (1991) applied to A_t B_t. The Newey–West rule of thumb is available as `max_lag="nw"`, but it is much too short for persistent series such as hourly prices. For persistent and seasonal series κ can be large and may keep growing with the lag, so results should be reported for several lags.
|
|
159
|
+
|
|
160
|
+
## Tests
|
|
161
|
+
|
|
162
|
+
Running `pytest` checks both the code and the underlying theory. Among other things, the tests verify that:
|
|
163
|
+
|
|
164
|
+
- the raw deviation at the centre of the Gaussian copula equals arcsin(ρ)/2π, and Z² equals the χ² statistic of the corresponding 2×2 table;
|
|
165
|
+
- the statistic remains exact under ties and is standard normal under independence;
|
|
166
|
+
- the simultaneous band has the correct size, and Gaussian and permutation critical values agree;
|
|
167
|
+
- the map detects dependence that is confined to the tails;
|
|
168
|
+
- for AR(1) series, the HAC correction restores unit null variance and gives a band of approximately correct size;
|
|
169
|
+
- φ/φ_max equals ±1 under perfect dependence, and the plug-in lag increases with persistence;
|
|
170
|
+
- the copula samplers have uniform margins and the correct Kendall's τ;
|
|
171
|
+
- invalid input (grid and lag arguments, misaligned indexes) is rejected with a clear error.
|
|
172
|
+
|
|
173
|
+
## Citing
|
|
174
|
+
|
|
175
|
+
If you use the package, please cite:
|
|
176
|
+
|
|
177
|
+
> Medovikov, I. (2024). *Dependence Maps: A Graphical Tool for Visualizing Dependence.* 18th International Conference on Computational and Financial Econometrics (CFE-CMStatistics 2024), King's College London, 14–16 December 2024.
|
|
178
|
+
|
|
179
|
+
The repository includes a `CITATION.cff` file, which GitHub uses for its "Cite this repository" button.
|
|
180
|
+
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
MIT; see [`LICENSE`](https://github.com/Brainologist/dependence-maps/blob/main/LICENSE).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/dependence_maps.egg-info/PKG-INFO
|
|
5
|
+
src/dependence_maps.egg-info/SOURCES.txt
|
|
6
|
+
src/dependence_maps.egg-info/dependency_links.txt
|
|
7
|
+
src/dependence_maps.egg-info/requires.txt
|
|
8
|
+
src/dependence_maps.egg-info/top_level.txt
|
|
9
|
+
src/depmaps/__init__.py
|
|
10
|
+
src/depmaps/core.py
|
|
11
|
+
src/depmaps/inference.py
|
|
12
|
+
src/depmaps/plotting.py
|
|
13
|
+
src/depmaps/simulate.py
|
|
14
|
+
tests/test_depmaps.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
depmaps
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Dependence maps: signed standardized deviations of the empirical copula from independence."""
|
|
2
|
+
from .core import DependenceMap, dependence_map, make_grid, pseudo_obs, default_max_lag, andrews_max_lag
|
|
3
|
+
from .inference import null_covariance, null_max_distribution, simultaneous_band
|
|
4
|
+
from .plotting import DEPMAP_CMAP, plot_map, rank_scatter
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"DependenceMap",
|
|
8
|
+
"dependence_map",
|
|
9
|
+
"make_grid",
|
|
10
|
+
"pseudo_obs",
|
|
11
|
+
"default_max_lag",
|
|
12
|
+
"andrews_max_lag",
|
|
13
|
+
"simultaneous_band",
|
|
14
|
+
"null_max_distribution",
|
|
15
|
+
"null_covariance",
|
|
16
|
+
"plot_map",
|
|
17
|
+
"rank_scatter",
|
|
18
|
+
"DEPMAP_CMAP",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
__version__ = "0.1.1"
|