Grow a binary tree by directly maximizing concentration-index gain across
all candidate variables and split points at each node, while storing the
result as a standard partykit::party() object.
ctree_ci() is kept for existing code. New code should use ci_tree(),
because the current tree-growing method is greedy concentration-index
splitting rather than conditional-inference splitting.
Usage
ci_tree(
formula,
data,
rank_name,
outcome_name,
weights = NULL,
type = c("CI", "CIg", "CIc", "L"),
control = ci_tree_control(),
na.action = stats::na.omit,
...
)
ctree_ci(...)Arguments
- formula
A model formula, typically with a two-column response such as
cbind(rank, outcome) ~ x1 + x2.- data
A data frame containing the variables in
formula.- rank_name
Name of the socioeconomic rank variable.
- outcome_name
Name of the outcome variable.
- weights
Optional non-negative numeric case weights.
- type
One of
"CI","CIg","CIc", or"L"selecting the inequality index used for split scoring."L"uses observed socioeconomic levels in the first response column rather than fractional ranks.- control
A control object created by
ci_tree_control(). Objects frompartykit::ctree_control()are also accepted for shared controls such asminsplit,minbucket,minprob,maxdepth, andmtry.- na.action
A function for handling missing values.
- ...
Currently ignored; retained for backwards compatibility.
Value
A fitted ci_tree object inheriting from constparty and party.
A fitted ci_tree object inheriting from constparty and party.
Details
This helper is intended for inequality-aware tree fitting where the response
contains a socioeconomic ranking variable and a health outcome. Unlike
partykit::ctree(), it does not use conditional-inference tests for
first-stage variable selection.
At each non-terminal node t, ci_tree() searches across all
candidate variables and all admissible split points, then selects the pair
with the largest concentration-index gain:
$$(j^*, s^*) =
\arg\max_{j \in \mathcal{J}_t,\ s \in \mathcal{S}_{jt}}
G_m(t, j, s).$$
The gain G_m is computed by weighted_ci_gain() from the selected
concentration-index impurity m, one of "CI", "CIg", "CIc", or
"L".
The fitted object uses partykit::party() for storage, traversal,
prediction, and plotting, but the tree-growing rule is the package's greedy
concentration-index rule rather than the conditional-inference test-based
rule used by partykit::ctree().
Stopping rules operate in three places. First, a node is searched only when
it satisfies minsplit and has not reached maxdepth. Second, candidate
splits are admissible only when both child nodes satisfy minbucket and
minprob. Third, after all admissible splits are scored, the best split is
accepted only when its gain is finite and greater than min_gain.
If min_relative_gain is positive, the split must also recover at least
that share of the parent-node impurity.
References
Breiman L, Friedman JH, Olshen RA, Stone CJ (1984). Classification and Regression Trees. Wadsworth.
Hothorn T, Zeileis A (2015). "partykit: A Modular Toolkit for Recursive Partytioning in R." Journal of Machine Learning Research, 16, 3905-3909. https://jmlr.org/papers/v16/hothorn15a.html.
Wagstaff A, van Doorslaer E, Watanabe N (2003). "On Decomposing the Causes of Health Sector Inequalities with an Application to Malnutrition Inequalities in Vietnam." Journal of Econometrics, 112(1), 207-223. doi:10.1016/S0304-4076(02)00161-6.
Examples
data(kenya, package = "ineqTrees")
kenya_model_vars <- c(
"wealth",
"deadu5_num",
"rural",
"ed",
"reg",
"unskilled"
)
kenya_model_data <- kenya[
stats::complete.cases(kenya[, kenya_model_vars]),
kenya_model_vars
]
set.seed(20260512)
kenya_model_data <- kenya_model_data[
sample.int(nrow(kenya_model_data), 800L),
,
drop = FALSE
]
fit <- ci_tree(
formula = cbind(wealth, deadu5_num) ~ rural + ed + reg + unskilled,
data = kenya_model_data,
rank_name = "wealth",
outcome_name = "deadu5_num",
control = ci_tree_control(
minsplit = 100,
minbucket = 50,
minprob = 0.05,
maxdepth = 3
)
)
fit
#> Greedy concentration-index tree
#>
#> Formula:
#> cbind(wealth, deadu5_num) ~ rural + ed + reg + unskilled
#>
#> Criterion: CI
#> Observations: 800
#> Inner nodes: 5
#> Terminal nodes: 6
#> Max depth: 3
#>
#> Root node:
#> mean outcome = 7.2%
#> CI = 0.413
#>
#> Terminal node summary (highest criterion first):
#> node n weight depth CI outcome_mean outcome_percent
#> 9 209 209 3 0.322 0.048 4.8
#> 10 127 127 3 0.285 0.157 15.7
#> 11 86 86 2 0.147 0.244 24.4
#> 6 137 137 2 0.011 0.029 2.9
#> 5 132 132 3 0.003 0.023 2.3
#> 4 109 109 3 0.000 0.000 0.0
#> rule
#> reg in {Mombasa, Kwale, Kilifi, Tana River, Wajir, Mandera, Marsabit, Tharaka-Nithi, Embu, Makueni, Kiambu, Turkana, West Pokot, Samburu, Uasin Gishu, Elgeyo-Marakwet, Narok, Kericho, Bomet, Kakamega, Bungoma, Siaya, Homa Bay, Kisii, Nyamira} & reg in {Mombasa, Kwale, Kilifi, Tharaka-Nithi, Embu, Makueni, Kiambu, West Pokot, Samburu, Uasin Gishu, Elgeyo-Marakwet, Narok, Kericho, Bomet, Kakamega, Bungoma, Siaya, Kisii, Nyamira} & unskilled in {No}
#> reg in {Mombasa, Kwale, Kilifi, Tana River, Wajir, Mandera, Marsabit, Tharaka-Nithi, Embu, Makueni, Kiambu, Turkana, West Pokot, Samburu, Uasin Gishu, Elgeyo-Marakwet, Narok, Kericho, Bomet, Kakamega, Bungoma, Siaya, Homa Bay, Kisii, Nyamira} & reg in {Mombasa, Kwale, Kilifi, Tharaka-Nithi, Embu, Makueni, Kiambu, West Pokot, Samburu, Uasin Gishu, Elgeyo-Marakwet, Narok, Kericho, Bomet, Kakamega, Bungoma, Siaya, Kisii, Nyamira} & unskilled in {Yes}
#> reg in {Mombasa, Kwale, Kilifi, Tana River, Wajir, Mandera, Marsabit, Tharaka-Nithi, Embu, Makueni, Kiambu, Turkana, West Pokot, Samburu, Uasin Gishu, Elgeyo-Marakwet, Narok, Kericho, Bomet, Kakamega, Bungoma, Siaya, Homa Bay, Kisii, Nyamira} & reg in {Tana River, Wajir, Mandera, Marsabit, Turkana, Homa Bay}
#> reg in {Lamu, Taita Taveta, Garissa, Isiolo, Meru, Kitui, Machakos, Nyandarua, Nyeri, Kirinyaga, Murang'a, Trans Nzoia, Nandi, Baringo, Laikipia, Nakuru, Kajiado, Vihiga, Busia, Kisumu, Migori, Nairobi} & unskilled in {Yes}
#> reg in {Lamu, Taita Taveta, Garissa, Isiolo, Meru, Kitui, Machakos, Nyandarua, Nyeri, Kirinyaga, Murang'a, Trans Nzoia, Nandi, Baringo, Laikipia, Nakuru, Kajiado, Vihiga, Busia, Kisumu, Migori, Nairobi} & unskilled in {No} & reg in {Meru, Nyeri, Laikipia, Nakuru, Kajiado, Vihiga, Busia, Kisumu, Migori, Nairobi}
#> reg in {Lamu, Taita Taveta, Garissa, Isiolo, Meru, Kitui, Machakos, Nyandarua, Nyeri, Kirinyaga, Murang'a, Trans Nzoia, Nandi, Baringo, Laikipia, Nakuru, Kajiado, Vihiga, Busia, Kisumu, Migori, Nairobi} & unskilled in {No} & reg in {Lamu, Taita Taveta, Garissa, Isiolo, Kitui, Machakos, Nyandarua, Kirinyaga, Murang'a, Trans Nzoia, Nandi, Baringo}
ci_tree_terminal_summary(fit)
#> node n weight depth ci outcome_mean outcome_percent
#> <int> <int> <num> <int> <num> <num> <num>
#> 1: 4 109 109 3 0.000000000 0.00000000 0.000000
#> 2: 5 132 132 3 0.002525253 0.02272727 2.272727
#> 3: 6 137 137 2 0.010948905 0.02919708 2.919708
#> 4: 9 209 209 3 0.321531100 0.04784689 4.784689
#> 5: 10 127 127 3 0.285039370 0.15748031 15.748031
#> 6: 11 86 86 2 0.146733112 0.24418605 24.418605
#> rule
#> <char>
#> 1: reg in {Lamu, Taita Taveta, Garissa, Isiolo, Meru, Kitui, Machakos, Nyandarua, Nyeri, Kirinyaga, Murang'a, Trans Nzoia, Nandi, Baringo, Laikipia, Nakuru, Kajiado, Vihiga, Busia, Kisumu, Migori, Nairobi} & unskilled in {No} & reg in {Lamu, Taita Taveta, Garissa, Isiolo, Kitui, Machakos, Nyandarua, Kirinyaga, Murang'a, Trans Nzoia, Nandi, Baringo}
#> 2: reg in {Lamu, Taita Taveta, Garissa, Isiolo, Meru, Kitui, Machakos, Nyandarua, Nyeri, Kirinyaga, Murang'a, Trans Nzoia, Nandi, Baringo, Laikipia, Nakuru, Kajiado, Vihiga, Busia, Kisumu, Migori, Nairobi} & unskilled in {No} & reg in {Meru, Nyeri, Laikipia, Nakuru, Kajiado, Vihiga, Busia, Kisumu, Migori, Nairobi}
#> 3: reg in {Lamu, Taita Taveta, Garissa, Isiolo, Meru, Kitui, Machakos, Nyandarua, Nyeri, Kirinyaga, Murang'a, Trans Nzoia, Nandi, Baringo, Laikipia, Nakuru, Kajiado, Vihiga, Busia, Kisumu, Migori, Nairobi} & unskilled in {Yes}
#> 4: reg in {Mombasa, Kwale, Kilifi, Tana River, Wajir, Mandera, Marsabit, Tharaka-Nithi, Embu, Makueni, Kiambu, Turkana, West Pokot, Samburu, Uasin Gishu, Elgeyo-Marakwet, Narok, Kericho, Bomet, Kakamega, Bungoma, Siaya, Homa Bay, Kisii, Nyamira} & reg in {Mombasa, Kwale, Kilifi, Tharaka-Nithi, Embu, Makueni, Kiambu, West Pokot, Samburu, Uasin Gishu, Elgeyo-Marakwet, Narok, Kericho, Bomet, Kakamega, Bungoma, Siaya, Kisii, Nyamira} & unskilled in {No}
#> 5: reg in {Mombasa, Kwale, Kilifi, Tana River, Wajir, Mandera, Marsabit, Tharaka-Nithi, Embu, Makueni, Kiambu, Turkana, West Pokot, Samburu, Uasin Gishu, Elgeyo-Marakwet, Narok, Kericho, Bomet, Kakamega, Bungoma, Siaya, Homa Bay, Kisii, Nyamira} & reg in {Mombasa, Kwale, Kilifi, Tharaka-Nithi, Embu, Makueni, Kiambu, West Pokot, Samburu, Uasin Gishu, Elgeyo-Marakwet, Narok, Kericho, Bomet, Kakamega, Bungoma, Siaya, Kisii, Nyamira} & unskilled in {Yes}
#> 6: reg in {Mombasa, Kwale, Kilifi, Tana River, Wajir, Mandera, Marsabit, Tharaka-Nithi, Embu, Makueni, Kiambu, Turkana, West Pokot, Samburu, Uasin Gishu, Elgeyo-Marakwet, Narok, Kericho, Bomet, Kakamega, Bungoma, Siaya, Homa Bay, Kisii, Nyamira} & reg in {Tana River, Wajir, Mandera, Marsabit, Turkana, Homa Bay}