Confesso que sou um intérprete medíocre de código c e esse código antigo não é fácil de usar. Dito isto, passei pelo código fonte e fiz essas observações, o que me deixa bastante seguro em dizer: "o rpart escolhe literalmente a primeira e a melhor coluna variável". Como as colunas 1 e 2 produzem divisões inferiores, petal.length será a primeira variável dividida, porque essa coluna é anterior à petal.width em data.frame / matrix. Por fim, mostro isso invertendo a ordem das colunas para que petal.with seja a primeira variável dividida.
No arquivo de origem c "bsplit.c" no código-fonte do rpart , cito a linha 38:
* test out the variables 1 at at time
me->primary = (pSplit) NULL;
for (i = 0; i < rp.nvar; i++) {
... assim, iterando em um loop for a partir de i = 1 para rp.nvar, uma função de perda será chamada para varrer todas as divisões por uma variável, dentro de gini.c para a linha "divisão não categórica" 230, a divisão mais encontrada é atualizado se uma nova divisão for melhor. (Também pode ser uma função de perda definida pelo usuário)
if (temp < best) {
best = temp;
where = i;
direction = lmean < rmean ? LEFT : RIGHT;
}
e última linha 323, a melhoria para melhor divisão por uma variável é calculada ...
*improve = total_ss - best
... de volta ao bsplit.c a melhoria é verificada se for maior do que a vista anteriormente e atualizada apenas se for maior.
if (improve > rp.iscale)
rp.iscale = improve; /* largest seen so far */
Minha impressão é que o primeiro e o melhor (dos possíveis empates serão escolhidos), porque somente se o novo ponto de interrupção tiver uma pontuação melhor, ele será salvo. Isso diz respeito ao primeiro melhor ponto de interrupção encontrado e à primeira melhor variável encontrada. Os pontos de interrupção parecem não ser verificados simplesmente da esquerda para a direita no gini.c, portanto, o primeiro ponto de interrupção encontrado pode ser difícil de prever. Mas as variáveis são muito previsíveis varridas da primeira coluna para a última coluna.
Esse comportamento é diferente da implementação randomForest, na qual classTree.c é usada a seguinte solução:
/* Break ties at random: */
if (crit == critmax) {
if (unif_rand() < 1.0 / ntie) {
*bestSplit = j;
critmax = crit;
*splitVar = mvar;
}
ntie++;
}
Por fim, confirmo esse comportamento lançando as colunas de íris, de modo que petal.width seja escolhido primeiro
library(rpart)
data(iris)
iris = iris[,5:1] #flip/flop", invert order of columns columns
obj = rpart(Species~.,data=iris)
print(obj) #now petal width is first split
1) root 150 100 setosa (0.33333333 0.33333333 0.33333333)
2) Petal.Width< 0.8 50 0 setosa (1.00000000 0.00000000 0.00000000) *
3) Petal.Width>=0.8 100 50 versicolor (0.00000000 0.50000000 0.50000000)
6) Petal.Width< 1.75 54 5 versicolor (0.00000000 0.90740741 0.09259259) *
7) Petal.Width>=1.75 46 1 virginica (0.00000000 0.02173913 0.97826087) *
... e volte novamente
iris = iris[,5:1] #flop/flip", revert order of columns columns
obj = rpart(Species~.,data=iris)
print(obj) #now petal length is first split
1) root 150 100 setosa (0.33333333 0.33333333 0.33333333)
2) Petal.Length< 2.45 50 0 setosa (1.00000000 0.00000000 0.00000000) *
3) Petal.Length>=2.45 100 50 versicolor (0.00000000 0.50000000 0.50000000)
6) Petal.Width< 1.75 54 5 versicolor (0.00000000 0.90740741 0.09259259) *
7) Petal.Width>=1.75 46 1 virginica (0.00000000 0.02173913 0.97826087) *