Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement SPI #522

Merged
merged 14 commits into from
Apr 6, 2022
Merged

implement SPI #522

merged 14 commits into from
Apr 6, 2022

Conversation

strengejacke
Copy link
Member

#521

This does not yet change all the docs, I think this would result in too many conflicts, probably. So we might mention the "SPI" option in the docs later.

@bwiernik
Copy link
Contributor

bwiernik commented Apr 4, 2022

Do we want to copy the function from SPIn rather than soft-importing, considering that the package hasn't been updated since 2013?

@strengejacke
Copy link
Member Author

I wasn't sure about that, but this can be done easily. We just need the code in .spi(). It's more a moral question to me about copying the code 1:1 ;-)

@bwiernik
Copy link
Contributor

bwiernik commented Apr 4, 2022

SPIn is licensed GPL>=2, so we are contractually in the clear so long as we attribute the source.

I think we should do this considering that the CRAN version of SPIn generates several NOTEs based on changes to CRAN policies that have happened since it was last updated.

https://www.r-project.org/nosvn/R.check/r-devel-linux-x86_64-debian-clang/SPIn-00check.html

@strengejacke
Copy link
Member Author

That method or the code doesn't seem to be very robust:

library(bayestestR)
x <- rnorm(1000)
spi(x) |> as.data.frame()
#>     CI    CI_low  CI_high
#> 1 0.95 -1.851012 2.079607
SPIn::SPIn(x)$spin
#> [1] -1.851012  2.079607

m <- insight::download_model("brms_1")
d <- as.data.frame(m)
sapply(d, spi)
#> Error in quadprog::solve.QP(D.u, d.u, A.u, c(1, rep(0, u.u - u.l + 2)), : constraints are inconsistent, no solution!

sapply(d, SPIn::SPIn)
#> Error in solve.QP(D.u, d.u, A.u, c(1, rep(0, u.u - u.l + 2)), u.u - u.l): constraints are inconsistent, no solution!

Created on 2022-04-04 by the reprex package (v2.0.1)

@bwiernik
Copy link
Contributor

bwiernik commented Apr 4, 2022

The constraints are the A.l matrix. I would need to look more into the code for how this is generated and the paper this is based on to understand what's going on

@DominiqueMakowski
Copy link
Member

DominiqueMakowski commented Apr 5, 2022

should I submit without this PR or wait for a bit?

@DominiqueMakowski
Copy link
Member

should I submit without this PR or wait for a bit?

bump 😬

@strengejacke
Copy link
Member Author

w/o this PR, I'd say we must first take a closer look and see how this function can be made more stable. The original SPIn() in the SPIn package has some more arguments, which might help adjusting the algorithm to not fail in the above example - but it doesn't help user for whom it is probably still too opaque at the moment what they could do.

@strengejacke
Copy link
Member Author

strengejacke commented Apr 6, 2022

But you could elaborate a bit on #519 :-)

@bwiernik
Copy link
Contributor

bwiernik commented Apr 6, 2022

@strengejacke The issue that's causing it to fail is the bandwidth argument bw is somewhat too large for the intercept and lp_ parameters.

Let's try this:

  1. Use tryCatch() with the function using the default bw = round((sqrt(n.sims) - 1)/2)
  2. If that errors, try again multiplying that bw by .9, .8, then .7

That should make it safe for most distributions.

@bwiernik
Copy link
Contributor

bwiernik commented Apr 6, 2022

(I'll take care of that)

@bwiernik
Copy link
Contributor

bwiernik commented Apr 6, 2022

library(bayestestR)
m <- insight::download_model("brms_1")
d <- as.data.frame(m)
sapply(d, spi)
# > sapply(d, spi)
#         b_Intercept b_wt      b_cyl      sigma    lp__     
# CI      0.95        0.95      0.95       0.95     0.95     
# CI_low  36.25617    -4.703458 -2.386442  1.985231 -83.11161
# CI_high 43.31241    -1.567123 -0.6765242 3.385691 -77.98328

@bwiernik
Copy link
Contributor

bwiernik commented Apr 6, 2022

Assuming the checks pass, we can include this

@strengejacke
Copy link
Member Author

@DominiqueMakowski have you already submitted? If yes, it's no big deal, but if not, we may include this PR as well - we still need to add this to the docs as well.

@strengejacke
Copy link
Member Author

I don't know, this test seems to me like the results are a bit random...

https://github.com/easystats/bayestestR/runs/5856422169?check_suite_focus=true#step:10:336

@bwiernik
Copy link
Contributor

bwiernik commented Apr 6, 2022

That's seems very random. We might want to try to stabilize the seed on that test? But seems unrelated to the current changes

R/spi.R Outdated
x1 <- l
w.l <- 1
x.l <- NA
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bwiernik There are some edge cases, where this if-statement is TRUE, and then x.l was not initialized. I set it to NA, is that ok?

R/spi.R Outdated
x2 <- u
w.u <- 1
x.u <- NA
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. Try spi(distribution_normal(1000), ci = 0.0000001), in which case this if-statement is TRUE, and x.u wasn't initialized later when we return the data frame.

@bwiernik
Copy link
Contributor

bwiernik commented Apr 6, 2022

What if statement do you mean?

@strengejacke
Copy link
Member Author

We have

  # upper bound
  if (!is.na(ui) && all(ui == n.sims)) {
    x2 <- u
    w.u <- 1
    x.u <- NA # <- this here is new
  } else {

and at the bottom of the function:

  # output
  data.frame(
    "CI" = ci,
    "CI_low" = x.l,
    "CI_high" = x.u
  )

when if (!is.na(ui) && all(ui == n.sims)) { was TRUE, x.u wasn't initialized, so I added x.u <- NA # <- this here is new to the if-statement. I also did some minor fixes based on the tests I added, and fixed all errors/issues I found. Mostly rare edge cases, as you can see from the tests. But in general, it now works well with models.

@strengejacke
Copy link
Member Author

See my last changes here: a22371d
Based on the tests I copied from the test-hdi.R file. This showed some issues I fixed in that commit.

@strengejacke
Copy link
Member Author

@IndrajeetPatil why does test-coverage always fail? Is there something wrong with the script/action?

@bwiernik
Copy link
Contributor

bwiernik commented Apr 6, 2022

Oh, no. The x1 and x2 variables assigned above should just be changed to x.l and x.u. Missed updating those

@strengejacke
Copy link
Member Author

Cool, I think we're set.

@bwiernik
Copy link
Contributor

bwiernik commented Apr 6, 2022

Not sure what's up with those tests

@strengejacke strengejacke merged commit e2e985d into master Apr 6, 2022
@strengejacke strengejacke deleted the spin branch April 6, 2022 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants