<jupyter_start><jupyter_text>ColinearidadeO RDKit nos permite calcular 200 descritores 2D para descrever estruturas químicas. Alguns pacotes permitem o cálculo de ainda mais descritores. Dessa forma, é natural que alguns pares desses descritores sejam colineares. Isso quer dizer que, se fizermos um gráfico com os valores de um descritor no eixo x e de outro no eixo y, obteremos uma reta.Como exemplo, vamos usar o banco de dados de Delaney e verificar a relação entre os descritores `MolWt` e `ExactMolWt` do RDKit, que correspondem à massa molecular relativa e massa molecular relativa exata, respectivamente.<jupyter_code>import pandas as pd
import matplotlib.pyplot as plt
from sklearn.metrics import r2_score
df = pd.read_csv("Delaney_descriptors.csv", sep=";")
df.head()
df[["MolWt","ExactMolWt"]]
## Cálculo do coeficiente de correlação R²
r2 = str(r2_score(df["MolWt"], df["ExactMolWt"]).round(5))

## Gráfico
plt.scatter(df["MolWt"], df["ExactMolWt"])
plt.xlabel("MolWt")
plt.ylabel("ExactMolWt")
plt.title(f"R-quadrado = {r2}")
plt.show()<jupyter_output><empty_output><jupyter_text>Vemos que esses dois descritores são praticamente idênticos. Isso é de se esperar, pois os valores diferem apenas nas casas decimais. Imagine agora que fôssemos treinar um modelo preditivo e que esses dois descritores estivessem presentes. Na melhor das hipóteses, nosso modelo usaria apenas um deles, e reconheceria o outro como sendo irrelevante. Porém, nem sempre isso ocorre, e existe a possibilidade de que a presença de variáveis correlacionadas introduza instabilidade aos modelos. Como exemplo, vamos demonstrar o valor dos coeficientes de uma regressão linear contendo os dois descritores, e uma regressão na qual não usamos o descritor ExactMolWt. Para mais detalhes sobre esse tipo de análise, veja o Notebook sobre Importância de Atributos.<jupyter_code># Vamos selecionar apenas algumas colunas para possibilitar uma melhor visualização dos coeficientes
# X = df[['MolWt', 'ExactMolWt', 'NumValenceElectrons', 'NumHAcceptors',
#          'NumHDonors', 'NumSaturatedRings', 'MolLogP', 'MolMR']]
X = df[["MolWt", "ExactMolWt", "FractionCSP3", "MolLogP", "NumAromaticRings", "NumHAcceptors", 
        "NumHDonors", "NumRotatableBonds", "TPSA", "LabuteASA"]]
y = df.iloc[:, -1]  # resposta
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
# Padronizando os dados
X = pd.DataFrame(StandardScaler().fit_transform(X), columns=X.columns)

# Regressão linear com MolWt e ExactMolWt = colinearidade
reg1 = LinearRegression()
reg1.fit(X, y)
ypred1 = reg1.predict(X)
imp1 = reg1.coef_

# Regressão linear removendo ExactMolWt
new_X = X.drop(["ExactMolWt"], axis=1)
reg2 = LinearRegression()
reg2.fit(new_X, y)
ypred2 = reg2.predict(new_X)
imp2 = reg2.coef_
# Gráficos com os valores dos coeficientes
plt.figure(figsize=(10,7))

plt.subplot(2, 1, 1)
plt.barh(X.columns, imp1)
plt.title(f"R-quadrado = {str(r2_score(ypred1, y).round(5))}")

plt.subplot(2, 1, 2)
plt.barh(new_X.columns, imp2)
plt.title(f"R-quadrado = {str(r2_score(ypred2, y).round(5))}")

plt.show()<jupyter_output><empty_output><jupyter_text>Veja que os coeficientes de MolWt e ExactMolWt são muito grandes, praticamente do mesmo tamanho, e de sinais opostos. Ou seja, podemos acreditar que ambos são muito importantes para descrever nossa variável. Porém, quando retiramos um deles, vemos que a importância do outro no modelo é, na verdade, muito menor do que antes. Portanto, concluímos que **é uma boa prática remover variáveis correlacionadas antes de criar modelos de ML**.Uma forma de fazer isso é calculando a correlação entre todos os pares de variáveis. Vejamos como fazer isso:<jupyter_code># Verificando a existência de variáveis altamente correlacionadas
from itertools import combinations

corr_matrix = X.corr()
comb = combinations(corr_matrix.columns, 2)
for c1, c2 in comb:
    if abs(corr_matrix.loc[c1, c2]) > 0.8:
        print(f'r2 (módulo) entre as variáveis {c1} e {c2} = {corr_matrix.loc[c1, c2]:.3f}')<jupyter_output>r2 (módulo) entre as variáveis MolWt e ExactMolWt = 1.000
r2 (módulo) entre as variáveis MolWt e LabuteASA = 0.970
r2 (módulo) entre as variáveis ExactMolWt e LabuteASA = 0.971
r2 (módulo) entre as variáveis NumHAcceptors e TPSA = 0.897<jupyter_text>Verificamos que existem algumas variáveis altamente correlacionadas. Dessa forma, podemos remover `ExactMolWt` e `LabuteASA`, já que são colineares com `MolWt`, e `TPSA`, que é correlacionada com `NumHAcceptors`.<jupyter_code>X.drop(["ExactMolWt", "LabuteASA", "TPSA"], axis=1, inplace=True)
X.head()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09562607204116638, 'fraction_numerical': 0.016080617495711835, 'mean_word_length': 5.900887573964497, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '226576', 'license': 'MIT', 'n_tokens_mistral': 1839, 'n_tokens_neox': 1764, 'n_words': 532, 'path': 'Quiminformatica/Removendo descritores colineares.ipynb', 'repo_name': 'rflameiro/Python_e_Quiminformatica', 'size': '4664'}