Skip to content

Commit a4d5564

Browse files
committed
bug fix
1 parent bc34703 commit a4d5564

File tree

6 files changed

+114
-118
lines changed

6 files changed

+114
-118
lines changed

.travis.yml

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,23 @@
11
## Documentation: http://docs.travis-ci.com/user/languages/julia/
22
language: julia
3-
4-
fast_finish: true
5-
6-
group: travis_latest
7-
83
os:
94
- linux
105
- osx
11-
12-
addons:
13-
apt:
14-
packages: ['gfortran','liblapack-dev','libopenmpi-dev']
15-
166
julia:
17-
- 0.6
7+
- 1.5
8+
- 1.1
189
- nightly
19-
2010
notifications:
2111
email: false
22-
2312
git:
24-
depth: 99999
13+
depth: 99999999
2514

26-
before_install:
27-
- if [[ $TRAVIS_OS_NAME == osx ]]; then
28-
brew update > /dev/null;
29-
brew install gcc || true;
30-
brew link --overwrite gcc;
31-
brew install lapack open-mpi > /dev/null;
32-
export FC=gfortran;
33-
fi
34-
35-
# (tests will run but not make your overall status red)
15+
## uncomment the following lines to allow failures on nightly julia
16+
## (tests will run but not make your overall status red)
3617
matrix:
37-
allow_failures:
38-
- julia: nightly
18+
allow_failures:
19+
- julia: nightly
20+
3921

4022
after_success:
41-
- julia -e 'cd(Pkg.dir("InvariantCausal")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(process_folder())'
23+
- julia -e 'using Pkg; Pkg.add("Coverage"); using Coverage; Coveralls.submit(process_folder())'

Project.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ version = "1.0.0"
77
CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597"
88
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
99
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
10+
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
1011
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
1112
GLM = "38e38edf-8417-5370-95a0-9cbb8c7f171a"
1213
GLMNet = "8d5ece8b-de18-5317-b113-243142960cc6"
@@ -15,8 +16,8 @@ Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
1516
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
1617
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
1718
StatsModels = "3eaba693-59b7-5ba5-a881-562e759f1c8d"
18-
UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"
1919
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
20+
UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"
2021

2122
[compat]
2223
CategoricalArrays = "0.9"
@@ -29,5 +30,3 @@ StatsBase = "0.33"
2930
StatsModels = "0.6"
3031
UnicodePlots = "1.3"
3132
julia = "1"
32-
33-

README.md

Lines changed: 93 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44

55
![college](docs/college.png)
66

7-
This is a Julia v.0.6 implementation for the Invariant Causal Prediction algorithm of [Peters, Bühlmann and Meinshausen](https://doi.org/10.1111/rssb.12167). The method uncovers direct causes of a target variable from datasets under different environments (e.g., interventions or experimental settings).
7+
This is a **Julia 1.x** implementation for the **Invariant Causal Prediction** algorithm of [Peters, Bühlmann and Meinshausen](https://doi.org/10.1111/rssb.12167). The method uncovers direct causes of a target variable from datasets under different environments (e.g., interventions or experimental settings).
88

99
See also this [R package](https://cran.r-project.org/package=InvariantCausalPrediction) and [this report](docs/InvariantCausal.pdf).
1010

1111
#### Changelog
1212

13-
- 2018/06/20: version 0.1.1
13+
- 2020/12/03: version 1.0.0 (Julia 1.x)
14+
- 2018/06/20: version 0.1.1 (Julia 0.6)
1415

1516
#### Dependencies
1617

@@ -44,122 +45,146 @@ Generate a simple [Gaussian structure equation model](https://en.wikipedia.org/w
4445
```julia
4546
julia> using InvariantCausal
4647
julia> using Random
47-
julia> Random.seed!(1926)
48+
julia> Random.seed!(77)
4849
julia> sem_obs = random_gaussian_SEM(21, 3)
50+
4951
Gaussian SEM with 21 variables:
5052
B =
5153
Sparsity Pattern
5254
┌───────────┐
53-
1 │⠀⠀⡄⠀⠐⡠⠀⡀⢢⡄⠀│ > 0
54-
│⠠⠀⠄⡀⡸⡠⠠⡀⠀⢠⠀│ < 0
55-
⠀⠈⠠⠀⠈⠉⠀⠄⠀⠀⠀
56-
⠀⢂⠢⠀⢨⢀⠀⡀⢀⠂⡒
57-
⠀⠀⠀⠀⠠⢲⠀⠄⠀⠀⠐
58-
21 │⠀⠀⠹⠀⠀⠐⠐⠆⠐⠥⠀│
55+
1 │⠀⠠⠀⠀⢐⠀⠀⠄⠀⢔⠀│ > 0
56+
│⠠⠀⠠⠨⠁⠀⠄⠀⠀⠸⠀│ < 0
57+
⠠⠈⠈⠀⠌⠠⠀⠅⠀⠩⠉
58+
⠠⣨⠴⠰⠪⠠⠄⠀⠸⠉⣐
59+
⢀⠲⠈⢠⠠⠀⠀⠂⠀⠲⠁
60+
21 │⠀⠐⠀⠀⠠⠠⠀⠀⠀⠔⠀│
5961
└───────────┘
6062
1 21
61-
nz = 63σ² = [1.3995969539576336, 1.3797542626927117, 1.8725924411035275, 1.1558670231511754, 0.6313157118985134, 1.3861564933413408, 1.4515091017758692, 1.7392330458711087, 1.55834175481778, 1.1102263218265493, 1.2459898446608833, 0.9582172366364653, 0.8341414371776826, 1.9452530507977812, 1.48880401416046, 1.5359339337413704, 1.691737599591161, 0.6496166911064964, 1.1210005303098285, 1.1459738623697713, 0.6920288559801938]
63+
nz = 70σ² = [1.9727697778060356, 1.1224733663047743, 1.1798805640594814, 1.2625825149076064, 0.8503782631176267, 0.5262963446298372, 1.3835334059064883, 1.788996301274282, 1.759286517329432, 0.842571682652995, 1.713382150423666, 1.4524484793202235, 1.9464648511794784, 1.7729995603828317, 0.7110857327642559, 1.6837378902964577, 1.085405687408806, 1.3069888003095986, 1.3933773717634643, 1.0571823834646068, 1.9187793877731028]
6264
```
6365

64-
Suppose we want to infer the direct causes for the last variables, which are
66+
Suppose we want to infer the direct causes for the last variables, i.e., 9, 11 and 18.
6567

6668
```julia
6769
julia> causes(sem_obs, 21)
68-
2-element Array{Int64,1}:
69-
2
70-
5
70+
3-element Array{Int64,1}:
71+
9
72+
11
73+
18
7174
```
7275

73-
Firstly, let us generate some observational data and call it environment 1.
76+
Firstly, let us generate some observational data and call it **environment 1**.
7477

7578
```julia
7679
julia> X1 = simulate(sem_obs, 1000)
7780
```
7881

79-
Then, we simulate from environment 2 by performing do-intervention on variables 3, 4, 5, 6. Here we set them to fixed random values.
82+
Then, we simulate from **environment 2** by performing **do-intervention** on variables 3, 4, 5, 6. Here we set them to fixed random values.
8083

8184
```julia
8285
julia> X2 = simulate(sem_obs, [3,4,5,6], randn(4), 1000)
8386
```
8487

85-
We run the algorithm on environments 1 and 2.
88+
We run the algorithm on **environments 1 and 2**.
8689

8790
```julia
8891
julia> causalSearch(vcat(X1, X2)[:,1:20], vcat(X1, X2)[:,21], repeat([1,2], inner=1000))
8992

90-
8 variables are screened out from 20 variables with lasso: [2, 5, 6, 8, 13, 15, 16, 20]
91-
Causal invariance search across 2 environments with at α=0.01 (|S| = 8, method = chow)
92-
93-
S = [] : p-value = 0.0000 [ ] ⋂ = [2, 5, 6, 8, 13, 15, 16, 20]
94-
S = [2] : p-value = 0.1376 [*] ⋂ = [2]
95-
S = [20] : p-value = 0.0000 [ ] ⋂ = [2]
96-
S = [16] : p-value = 0.0000 [ ] ⋂ = [2]
97-
S = [15] : p-value = 0.0000 [ ] ⋂ = [2]
98-
...
99-
S = [2, 5, 6] : p-value = 0.3557 [*] ⋂ = [2]
100-
S = [5, 6, 20] : p-value = 0.1879 [*] ⋂ = Int64[]
93+
8 variables are screened out from 20 variables with lasso: [5, 7, 8, 9, 11, 12, 15, 17]
94+
Causal invariance search across 2 environments with at α=0.01 (|S| = 8, method = chow, model = linear)
95+
96+
S = [] : p-value = 0.0000 [ ] ⋂ = [5, 7, 8, 9, 11, 12, 15, 17]
97+
S = [5] : p-value = 0.0000 [ ] ⋂ = [5, 7, 8, 9, 11, 12, 15, 17]
98+
S = [17] : p-value = 0.0000 [ ] ⋂ = [5, 7, 8, 9, 11, 12, 15, 17]
99+
S = [15] : p-value = 0.0000 [ ] ⋂ = [5, 7, 8, 9, 11, 12, 15, 17]
100+
S = [12] : p-value = 0.0000 [ ] ⋂ = [5, 7, 8, 9, 11, 12, 15, 17]
101+
S = [11] : p-value = 0.0144 [*] ⋂ = [11]
102+
S = [9] : p-value = 0.0000 [ ] ⋂ = [11]
103+
S = [8] : p-value = 0.0000 [ ] ⋂ = [11]
104+
S = [7] : p-value = 0.0000 [ ] ⋂ = [11]
105+
S = [11, 5] : p-value = 0.0000 [ ] ⋂ = [11]
106+
S = [11, 12] : p-value = 0.0000 [ ] ⋂ = [11]
107+
S = [11, 15] : p-value = 0.0007 [ ] ⋂ = [11]
108+
S = [7, 11] : p-value = 0.0082 [ ] ⋂ = [11]
109+
S = [11, 8] : p-value = 0.0000 [ ] ⋂ = [11]
110+
S = [9, 11] : p-value = 0.0512 [*] ⋂ = [11]
111+
S = [17, 11] : p-value = 0.0000 [ ] ⋂ = [11]
112+
S = [9, 12] : p-value = 0.0000 [ ] ⋂ = [11]
113+
S = [9, 15] : p-value = 0.0064 [ ] ⋂ = [11]
114+
S = [7, 9] : p-value = 0.0000 [ ] ⋂ = [11]
115+
S = [9, 8] : p-value = 0.0000 [ ] ⋂ = [11]
116+
S = [9, 5] : p-value = 0.7475 [*] ⋂ = Int64[]
117+
118+
Tested 21 sets: 3 sets are accepted.
101119

102120
* Found no causal variable (empty intersection).
103121

104-
Variables considered include [2, 5, 6, 8, 13, 15, 16, 20]
122+
Variables considered include [5, 7, 8, 9, 11, 12, 15, 17]
105123
```
106124

107-
The algorithm cannot find any direct causal variables (parents) of variable 21 due to insufficient power of two environments. The algorithm tends to discover more with more environments. Let us define a new environment where we perform a noise (soft) intervention that changes the equations for 5 variables other than the target. Note it is important that the target is left untouched.
125+
The algorithm **cannot find any** direct causal variables (parents) of variable 21 due to **insufficient power** of two environments. The algorithm tends to **discover more** with **more environments**. Let us define a new environment where we perform a **noise (soft) intervention** that changes the equations for 5 variables other than the target. Note it is important that the **target** is left **untouched**.
108126

109127
```Julia
110128
julia> sem_noise, variables_intervened = random_noise_intervened_SEM(sem_obs, p_intervened=5, avoid=[21])
111129

112130
(Gaussian SEM with 21 variables:
113131
B =
114132
Sparsity Pattern
115-
┌─────────────
116-
1 │⠀⠀⠂⠄⠀⠔⠀⠀⠂⠂⡆> 0
117-
⢀⢠⠈⡀⠠⠠⣀⠀⠀⠅⠀│ < 0
118-
⠀⠐⠉⠀⠈⠠⠘⠀⠀⠆⠉│
119-
⠀⠐⢠⠀⠀⡀⠐⠀⢂⠀⡂
120-
⠀⠠⢐⠀⠉⠵⠠⠁⠄⠈⠂
121-
21⠈⠄⠸⠀⠀⠈⠀⠀⠉⠀⠁
122-
└─────────────
133+
┌───────────┐
134+
1 │⠀⠠⠀⠀⢐⠀⠀⠄⠀⢔⠀> 0
135+
⠠⠀⠠⠨⠁⠀⠄⠀⠀⠸⠀│ < 0
136+
⠠⠈⠈⠀⠌⠠⠀⠅⠀⠩⠉│
137+
⠠⣨⠴⠰⠪⠠⠄⠀⠸⠉⣐
138+
⢀⠲⠈⢠⠠⠀⠀⠂⠀⠲⠁
139+
21⠀⠐⠀⠀⠠⠠⠀⠀⠀⠔⠀
140+
└───────────┘
123141
1 21
124-
nz = 63
125-
σ² = [1.3996, 1.20882, 1.87259, 1.15587, 0.631316, 1.38616, 1.45151, 1.73923, 2.55396, 1.11023, 1.24599, 0.958217, 0.506628, 1.94525, 2.16212, 1.53593, 1.69174, 0.649617, 1.121, 2.19366, 0.692029], [9, 15, 13, 2, 20])
142+
nz = 70σ² = [1.9727697778060356, 1.1224733663047743, 1.1798805640594814, 1.2625825149076064, 0.8503782631176267, 0.5262963446298372, 1.3835334059064883, 1.788996301274282, 1.759286517329432, 0.5837984015051159, 3.01957479564807, 0.9492838187140921, 1.9398913901673531, 1.7729995603828317, 0.7110857327642559, 1.6837378902964577, 1.2089053651343495, 1.3069888003095986, 1.3933773717634643, 1.0571823834646068, 1.9187793877731028], [17, 13, 10, 11, 12])
126143
```
127144

128-
Here the equations for variables 9, 15, 13, 2, 20 have been changed. Now we simulate from this modified SEM and call it environment 3. We run the algorithm on all 3 environments.
145+
Here the equations for variables 17, 13, 10, 11, 12 have been changed. Now we simulate from this modified SEM and call it **environment 3**. We run the algorithm on all **3 environments**.
129146

130147
```Julia
131148
julia> X3 = simulate(sem_noise, 1000)
132149
julia> causalSearch(vcat(X1, X2, X3)[:,1:20], vcat(X1, X2, X3)[:,21], repeat([1,2,3], inner=1000))
133150
```
134151

135-
The algorithm searches over subsets for a while and successfully discovers variables 2.
152+
The algorithm searches over subsets for a while and successfully **discovers** variables 11. The other two causes, 9 and 18, can hopefully be discovered given even more environments.
136153

137154
```
138-
8 variables are screened out from 20 variables with lasso: [1, 2, 5, 6, 8, 13, 15, 20]
139-
Causal invariance search across 3 environments with at α=0.01 (|S| = 8, method = chow)
140-
141-
S = [] : p-value = 0.0000 [ ] ⋂ = [1, 2, 5, 6, 8, 13, 15, 20]
142-
S = [1] : p-value = 0.0000 [ ] ⋂ = [1, 2, 5, 6, 8, 13, 15, 20]
143-
S = [20] : p-value = 0.0000 [ ] ⋂ = [1, 2, 5, 6, 8, 13, 15, 20]
144-
S = [15] : p-value = 0.0000 [ ] ⋂ = [1, 2, 5, 6, 8, 13, 15, 20]
145-
S = [13] : p-value = 0.0000 [ ] ⋂ = [1, 2, 5, 6, 8, 13, 15, 20]
146-
S = [8] : p-value = 0.0000 [ ] ⋂ = [1, 2, 5, 6, 8, 13, 15, 20]
147-
S = [6] : p-value = 0.0000 [ ] ⋂ = [1, 2, 5, 6, 8, 13, 15, 20]
148-
S = [5] : p-value = 0.0001 [ ] ⋂ = [1, 2, 5, 6, 8, 13, 15, 20]
149-
S = [2] : p-value = 0.1714 [*] ⋂ = [2]
150-
S = [5, 1] : p-value = 0.0000 [ ] ⋂ = [2]
151-
S = [2, 5] : p-value = 0.2211 [*] ⋂ = [2]
152-
S = [5, 20] : p-value = 0.0000 [ ] ⋂ = [2]
153-
...
154-
S = [1, 13, 2, 5, 8, 15, 6] : p-value = 0.4380 [*] ⋂ = [2]
155-
S = [20, 6, 13, 2, 5, 8, 15, 1] : p-value = 0.6916 [*] ⋂ = [2]
156-
157-
* Causal variables include: [2]
158-
159-
variable 1.0 % 99.0 %
160-
2 0.5831 0.7054
161-
162-
⋅ Variables considered include [1, 2, 5, 6, 8, 13, 15, 20]
155+
causalSearch(vcat(X1, X2, X3)[:,1:20], vcat(X1, X2, X3)[:,21], repeat([1,2,3], inner=1000))
156+
8 variables are screened out from 20 variables with lasso: [4, 5, 7, 8, 9, 11, 12, 16]
157+
Causal invariance search across 3 environments with at α=0.01 (|S| = 8, method = chow, model = linear)
158+
159+
S = [] : p-value = 0.0000 [ ] ⋂ = [4, 5, 7, 8, 9, 11, 12, 16]
160+
S = [4] : p-value = 0.0000 [ ] ⋂ = [4, 5, 7, 8, 9, 11, 12, 16]
161+
S = [16] : p-value = 0.0000 [ ] ⋂ = [4, 5, 7, 8, 9, 11, 12, 16]
162+
S = [12] : p-value = 0.0000 [ ] ⋂ = [4, 5, 7, 8, 9, 11, 12, 16]
163+
S = [11] : p-value = 0.0084 [ ] ⋂ = [4, 5, 7, 8, 9, 11, 12, 16]
164+
S = [9] : p-value = 0.0000 [ ] ⋂ = [4, 5, 7, 8, 9, 11, 12, 16]
165+
S = [8] : p-value = 0.0000 [ ] ⋂ = [4, 5, 7, 8, 9, 11, 12, 16]
166+
S = [7] : p-value = 0.0000 [ ] ⋂ = [4, 5, 7, 8, 9, 11, 12, 16]
167+
S = [5] : p-value = 0.0000 [ ] ⋂ = [4, 5, 7, 8, 9, 11, 12, 16]
168+
S = [4, 11] : p-value = 0.0000 [ ] ⋂ = [4, 5, 7, 8, 9, 11, 12, 16]
169+
S = [11, 5] : p-value = 0.0000 [ ] ⋂ = [4, 5, 7, 8, 9, 11, 12, 16]
170+
S = [11, 8] : p-value = 0.0000 [ ] ⋂ = [4, 5, 7, 8, 9, 11, 12, 16]
171+
S = [7, 11] : p-value = 0.0000 [ ] ⋂ = [4, 5, 7, 8, 9, 11, 12, 16]
172+
S = [9, 11] : p-value = 0.0000 [ ] ⋂ = [4, 5, 7, 8, 9, 11, 12, 16]
173+
S = [16, 11] : p-value = 0.0709 [*] ⋂ = [11, 16]
174+
S = [11, 12] : p-value = 0.0000 [ ] ⋂ = [11, 16]
175+
...
176+
S = [7, 9, 4, 16, 11, 5, 12] : p-value = 0.0000 [ ] ⋂ = [11]
177+
S = [7, 9, 4, 16, 11, 8, 12] : p-value = 0.0001 [ ] ⋂ = [11]
178+
S = [7, 4, 9, 16, 11, 5, 8, 12] : p-value = 0.0002 [ ] ⋂ = [11]
179+
180+
Tested 256 sets: 6 sets are accepted.
181+
182+
* Causal variables include: [11]
183+
184+
variable 1.0 % 99.0 %
185+
11 0.1123 1.1017
186+
187+
⋅ Variables considered include [4, 5, 7, 8, 9, 11, 12, 16]
163188
```
164189

165190
### Functionalities
@@ -181,24 +206,8 @@ variable 1.0 % 99.0 %
181206

182207
### Features
183208

184-
- High performance implementation in Julia v.0.6
209+
- High performance implementation in Julia v1.x
185210
- Faster search:
186211
- skipping testing supersets of A if A is accepted ( under `selection_only` mode)
187212
- Priority queue to prioritize testing sets likely to be invariant
188213

189-
### Todo
190-
191-
- ~~Confidence intervals~~
192-
- ~~Logistic regression~~
193-
- ~~Variable screening~~
194-
- ~~glmnet~~
195-
- ~~HOLP~~
196-
- ~~Subsampling for large n in Chow's test~~
197-
- Nonparametric two-sample tests
198-
- Hidden variable case
199-
- ~~Inference of graph and plotting~~
200-
201-
### Issues
202-
203-
- ~~Better reporting~~
204-

src/causalSearch.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ function causalSearch(X::Union{Matrix{Float64}, DataFrame}, y::Vector{Float64},
106106
model = "logistic"
107107
# combine into a DataFrame (note: GLM.jl has to work with DataFrame)
108108
@assert all((y.==1) .| (y.==0))
109-
df = DataFrame(hcat(X, y, makeunique=true))
109+
df = DataFrame(isa(X, DataFrame) ? hcat(X, y, makeunique=true) : hcat(X, y))
110110
for _col in propertynames(df)
111111
if isa(df[!, _col], CategoricalArray)
112112
@assert length(unique(df[!, _col])) == 2 "categorical variable $_col should be recoded to binary"

src/conditionalInvTests.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,10 @@ function conditional_inv_test_logistic(df::DataFrame, target::Symbol, S::Vector{
179179
return reject, p_value, conf_intervals
180180
end
181181

182-
function conditional_inv_test_logistic_LR(df::DataFrame, target::Symbol, S::Vector{Int64},
183-
env::Vector{Int64}, n_env::Int64; α=0.01, add_intercept=true)
184-
conditional_inv_test_logistic_LR(df, target, names(df)[S], env, n_env; α=α, add_intercept=add_intercept)
182+
function conditional_inv_test_logistic(df::DataFrame, target::Symbol, S::Vector{Int64},
183+
env::Vector{Int64}, n_env::Int64; α=0.01, add_intercept=true, method="logistic-LR")
184+
conditional_inv_test_logistic(df, target, propertynames(df)[S], env, n_env;
185+
α=α, add_intercept=add_intercept, method=method)
185186
end
186187

187188
"""

test/test_search.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,13 @@ end
2020
x3 = [0.0 0.0 1.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0 1.0 0.0][:],
2121
y = [1.0 1.0 1.0 0.0 0.0 1.0 1.0 1.0 0.0 1.0 1.0 0.0 0.0 1.0 1.0 0.0][:])
2222
env = repeat([1,2], inner=8)
23+
X = Matrix{Float64}(df[!, 1:3])
2324
r1 = causalSearch(df, :y, env, method="logistic-LR", iterate_all=true)
2425
@test length(r1.S) == 0
26+
r1 = causalSearch(X, df.y, env, method="logistic-LR", iterate_all=true)
27+
@test length(r1.S) == 0
2528
r2 = causalSearch(df, :y, env, method="logistic-SF", iterate_all=true)
2629
@test length(r2.S) == 0
30+
r2 = causalSearch(X, df.y, env, method="logistic-SF", iterate_all=true)
31+
@test length(r2.S) == 0
2732
end

0 commit comments

Comments
 (0)