Add Brant test (resolves: https://github.com/jasp-stats/jasp-issues/issues/3295)#511
Add Brant test (resolves: https://github.com/jasp-stats/jasp-issues/issues/3295)#511rphars wants to merge 27 commits into
Conversation
|
👋 Friendly reminder: It looks like If your changes include bug fixes, new features, or UI tweaks, please consider adding a quick note to the |
|
build bot build |
✅ Build Complete!Your JASP module bundles have been successfully built for macOS (ARM) and Windows. 👉 Click here to download the artifacts (Scroll to the bottom of the page to find the "Artifacts" section). |
There was a problem hiding this comment.
Really nice, especially as a first contribution! Just some minor suggestions:
- Please add a note in news.md so that your change gets included in the next release notes
- on line 1257 you have a footnote with whitespaces and indentations, which does not work for translations and the like. Please just make this one continuous string
i.e.,gettext("Negative \u03A7\u00B2 statistics are computational artifacts. They indicate the estimated covariance matrix is not positive semi-definite or is ill-conditioned, often due to small samples or sparse data. Test results might be misleading." - 1:numThresholds / 1:numPredictors → seq_len(...) (safe here given the guards, but it's the style-guide convention).
- the qml logic can be smoothened out so that it works correctly on a JASP restart:
- GlmInputComponent.qml — make the property a binding (line 25):
// before
property bool isOrdinalModel: false
// after
property bool isOrdinalModel: family.currentValue === "other" && otherGlmModel.currentValue === "ordinalLogistic" - GlmInputComponent.qml — delete both imperative assignments now that the binding does the work.
In the family DropDown's handler, drop just the one line (keep the rest of the handler):
onCurrentValueChanged:
{
isOrdinalModel = (family.currentValue === "other") && (otherGlmModel.currentValue === "ordinalLogistic"); // ← delete this line
if (!familyMap[currentValue].includes(link.value))
...
In the otherGlmModel DropDown, remove the entire onCurrentValueChanged block (it exists only to set the property):
{ label: qsTr("Firth Logistic Regression"), value: "firthLogistic"}
]
onCurrentValueChanged: // ← delete these
{ // four
isOrdinalModel = ... // lines
} // entirely
}
-
GeneralizedLinearModel.qml — tab-indent the new Group (it's a sibling of the just-closed Output group, so 2 tabs / 3 / 4), and drop the stray ; after visible:
Group { title: qsTr("Assumption Checks") visible: input.isOrdinalModel CheckBox { name: "brantTest" label: qsTr("Brant test of proportional odds") } }
| return() | ||
|
|
||
| brantTable <- createJaspTable(title = gettext("Brant Test for Proportional Odds Assumption")) | ||
| brantTable$dependOn(options = c("dependent", "modelTerms", "otherGlmModel", "brantTest", "weights", "offset")) |
There was a problem hiding this comment.
maybe also add family, link, interceptTerm to the dependencies to ensure it's updated when relevant
|
Thanks for the extensive review/comments. I'll implement them as soon as time allows! |
Implements the Brant test, which tests the proportional odds (also called parallel lines) assumption in ordered logit models. This resolves: jasp-stats/jasp-issues#3295
The test is described in
Brant, R. (1990). Assessing proportionality in the proportional odds model for ordinal logistic regression. Biometrics, 46(4), 1171–1178. https://doi.org/10.2307/2532457
This is a new implementation, different from earlier implementations in brant::brant and gofcat::brant.test. Several reasons for this:
The code adds a new menu option when ordinal logit models are selected:

Outputs are tested against:
-STATA's brant (implemented by Long & Freese)
-prior R implementations from brant::brant and gofcat::brant.test.
The code outputs the same results as in STATA's brant:

with every dataset I've tried. Screenshot shows data from: https://stats.oarc.ucla.edu/r/dae/ordinal-logistic-regression/
There is one small implementation difference compared to brant::brant and gofcat::brant.test, which both omit a transpose in one specific place indicated in the code. This leads to minor numerical differences in small samples. The current implementation is consistent with STATA's brant and Brant's paper.
Note: this is my first contribution, so apologies in advance if I missed anything.