Em geral, não.

Árvores de decisão não são sensíveis a feature scaling (escalonamento) porque suas divisões não mudam com transformações monotônicas dos dados.

A normalização também não é necessária, mas pode mudar seus resultados porque não é monotônica, como veremos mais adiante.

Dito isso, a implementação numérica de uma biblioteca específica pode fazer com que as previsões da sua árvore de decisão mudem se você não escalonar ou normalizar seus dados.

Essa geralmente é uma mudança muito pequena, com a qual você não precisa se preocupar, mas é bom saber se você se encontrar em uma situação em que precisa explicar por que suas previsões são diferentes.

Outros algoritmos de machine learning baseados em árvores de decisão, como XGBoost, LightGBM, Random Forests, etc., seguem a mesma regra.

O Que É Uma Transformação Monotônica?

Uma transformação monotônica é uma transformação que preserva a ordem dos valores.

Um exemplo é a transformação quadrática.

Imagine que temos os seguintes dados de temperatura:

import numpy as np

data = np.array([2.1, 2.3, 2.5, 2.7, 2.9, 3.1, 3.3, 3.5, 3.7, 3.9])

Imagine que uma árvore de decisão muito simples,com apenas um split, decida que a melhor divisão deve ser em 3,1.

Tudo abaixo disso pertence à classe negativa e tudo acima pertence à classe positiva.

As previsões seriam:

predictions = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1])

Agora, se aplicarmos uma transformação quadrática aos dados originais, obteremos:

data = data**2

np.array([ 4.41,  5.29,  6.25,  7.29,  8.41,  9.61, 10.89, 12.25, 13.69,
       15.21])

A melhor divisão seria em 9,61. Embora a divisão seja numericamente diferente, as previsões são as mesmas:

predictions = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1])

Comparando Árvores De Decisão Com E Sem Escalonamento

Vamos usar o conjunto de dados de qualidade do vinho tinto para comparar as previsões de uma árvore de decisão com e sem feature scaling.

Este conjunto de dados contém amostras de propriedades químicas de vinhos tintos e sua qualidade.

A ideia é prever a qualidade de um vinho com base em suas propriedades químicas.

data = pd.read_csv(os.path.join(path, "winequality-red.csv"))

X = data.drop(columns=["quality"])
y = data["quality"]

X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.3, random_state=42)
fixed acidity volatile acidity citric acid residual sugar chlorides free sulfur dioxide total sulfur dioxide density pH sulphates alcohol quality
0 7.4 0.7 0 1.9 0.076 11 34 0.9978 3.51 0.56 9.4 5
1 7.8 0.88 0 2.6 0.098 25 67 0.9968 3.2 0.68 9.8 5
2 7.8 0.76 0.04 2.3 0.092 15 54 0.997 3.26 0.65 9.8 5
3 11.2 0.28 0.56 1.9 0.075 17 60 0.998 3.16 0.58 9.8 6
4 7.4 0.7 0 1.9 0.076 11 34 0.9978 3.51 0.56 9.4 5

Depois de dividir os dados em conjuntos de treinamento e validação, treinamos uma árvore de decisão.

Vamos criá-la usando a classe DecisionTreeRegressor do scikit-learn.

Vamos definir o parâmetro random_state como 42 para tornar nossos resultados reprodutíveis.

tree = DecisionTreeRegressor(random_state=42)
tree.fit(X_train, y_train)

p = tree.predict(X_val)

p armazena a previsão para esta árvore sem feature scaling.

Agora vamos escalonar os dados usando a classe StandardScaler do scikit-learn.

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_val_scaled = scaler.transform(X_val)

tree = DecisionTreeRegressor(random_state=42)
tree.fit(X_train_scaled, y_train)

p_scaled = tree.predict(X_val_scaled)

A classe StandardScaler escala os dados subtraindo a média de cada feature e dividindo pelo desvio padrão.

Para ver se as previsões são diferentes, podemos calcular suas médias.

p.mean(), p_scaled.mean()

Neste caso, o primeiro valor é 5,71875 e o segundo é 5,72083.

Sim, há uma pequena diferença insignificante entre as previsões das duas árvores por causa da maneira como os computadores lidam com números.

Isso não significa que você deva sempre escalonar seus dados antes de treinar uma árvore de decisão porque existem fatores mais importantes para se preocupar, como a qualidade das features e o tamanho do conjunto de dados.

Comparando Árvores De Decisão Com E Sem Normalização

Normalização é um tipo de feature scaling que faz com que cada amostra tenha uma norma unitária.

Ele calcula a norma de cada amostra e divide cada feature por ela.

Um detalhe: na prática você verá eu e mais pessoas usando escalonamento e normalização como sinônimos, mas eles são diferentes. 98,5% das vezes, quando alguém fala sobre normalização, está se referindo a escalonamento.

Vamos usar a classe Normalizer do scikit-learn para verificar seu efeito nas previsões de uma árvore de decisão.

from sklearn.preprocessing import Normalizer

normalizer = Normalizer()
X_train_norm = normalizer.fit_transform(X_train)
X_val_norm = normalizer.transform(X_val)

tree = DecisionTreeRegressor(random_state=42)
tree.fit(X_train_norm, y_train)

p_norm = tree.predict(X_val_norm)
p_norm.mean()

A média das previsões é 5,69375, que é diferente de qualquer um dos valores anteriores.

Eu seria mais cuidadoso com essa transformação, porque ela não é monotônica.

Se você rankear e comparar os valores das features antes e depois da normalização, verá que a ordem é diferente.

X_train_norm = pd.DataFrame(X_train_norm, columns=X_train.columns, index=X_train.index)
np.allclose(X_train.rank(), X_train_norm.rank())
False

Já nos dados escalonados, a ordem é preservada.

X_train_scaled = pd.DataFrame(X_train_scaled, columns=X_train.columns, index=X_train.index)
np.allclose(X_train.rank(), X_train_scaled.rank())
True

Meu conselho é não se preocupar em usar feature scaling ou normalização para árvores de decisão.

É apenas mais uma etapa que você terá que implementar e manter em produção e não tem um impacto significativo nos resultados.

É uma história diferente se você estiver usando um algoritmo baseado em distância como vizinhos mais próximos ou um modelo que usa descida de gradiente como regressão linear e redes neurais.

Seja o primeiro a saber das novidades em Machine Learning. Me siga no LinkedIn.