<jupyter_start><jupyter_text>Activity CliffsQuando estamos desenvolvendo um modelo de SAR/SPR (relação estrutura-atividade/propriedade), fazemos a seguinte suposição:_"Compostos com estruturas similares terão propriedades similares"_Isso é equivalente a imaginar o espaço químico (um espaço imaginário contendo todas as moléculas nos eixos x e y, e o valor de sua atividade no eixo z) como sendo contínuo, sem grandes variações em pequenas distâncias. Porém, nem sempre esse é o caso: pequenas modificações em uma estrutura molecular podem influenciar significativamente a atividade (ou qualquer propriedade). Em um espaço físico, isso seria equivalente a um precipício (ravina, barranco, etc.), ou, em inglês, *cliff*. Dessa forma, quando um par de estruturas muito similares apresentam propriedades muito diferentes, dizemos que se trata de um *activity cliff*.O que significa "ser muito similar"? O que significa "propriedades muito diferentes"? Não há definição estabelecida, portanto, escolha os valores de corte da forma que se encaixar melhor ao seu caso.Neste notebook vamos verificar a existência de *activity cliffs* em um banco de dados de inibidores enzimáticos, e tentar explorar as razões moleculares por trás desses *cliffs*. Vamos começar importando o chembl_webresource_client, para trabalharmos com estruturas do ChEMBL<jupyter_code>from chembl_webresource_client.new_client import new_client
activities = new_client.activity
def get_inhibitors(target):
    """
    Input: código ChEMBL do alvo. Para descobrir o código do seu alvo, acesse o site do ChEMBL
        Exemplo: alvo = Catepsina B = "CHEMBL4072"
    Output: um dataframe contendo SMILES e pChEMBL values (atividade) dos inibidores do alvo
    """
    inhibitors = activities.filter(target_chembl_id=target, pchembl_value__isnull=False)
    data = [[item["canonical_smiles"], item["pchembl_value"]] for item in inhibitors]
    df = pd.DataFrame(data, columns=["SMILES", "pChEMBL"])
    return df
# Vamos procurar activity cliffs em inibidores de Catepsina B
df = get_inhibitors("CHEMBL4072")
# Remover linhas com dados faltando
df.dropna(inplace=True)
# Remover duplicatas
df = df.sort_values("pChEMBL", ascending=False).drop_duplicates(subset="SMILES").reset_index(drop=True)

df.head()
len(df)<jupyter_output><empty_output><jupyter_text>Podemos definir *activity cliffs* de acordo com uma diferença de atividade (por exemplo, uma diferença de duas unidades logarítmicas) ou separando os compostos em "ativos" e "inativos" e definindo que um *cliff* contém um par de compostos similares no qual um é ativo e um é inativo.Portanto, para definir nossos activity cliffs, vamos escolher o valor de pChEMBL = 6 como valor de corte: compostos com pChEMBL >= 6 serão considerados ativos, e inativos se pChEMBL < 6.<jupyter_code># A coluna pChEMBL é importada como string, precisamos convertê-la a float
df["Active"] = df["pChEMBL"].astype('float64') >= 6

# Número de compostos considerados "ativos"
df["Active"].sum()<jupyter_output><empty_output><jupyter_text>Já temos os valores de atividade dos compostos. Agora, precisamos comparar as similaridades entre as estruturas. Uma forma comum de fazer isso é utilizando *fingerprints* moleculares.Como exemplo, vamos utilizar os MACCS *fingerprints*, que consistem em uma lista contendo 166 valores (bits) que podem conter os números 0 ou 1. O valor 0 indica a ausência de uma sub-estrutura, e o valor 1 indica sua ausência. Por exemplo, o 42° bit de um MACCS *fingerprint* corresponde à presença ou ausência de um átomo de flúor: se a estrutura contém flúor, o valor desse bit será 1, caso contrário, será 0. As definições de cada bit podem ser encontradas [neste link](https://github.com/rdkit/rdkit/blob/master/rdkit/Chem/MACCSkeys.py).Após calcular os *fingerprints* para todas as estruturas, usaremos o valor do coeficiente de Tanimoto igual a 0.9 como valor de corte para similaridade. Em resumo, o coeficiente de Tanimoto compara dois *fingerprints* moleculares e retorna um valor entre 0 e 1; quanto mais próximo de 1, maior a similaridade. Assim, pares de compostos contendo um ativo e um inativo, cuja similaridade (coeficiente de Tanimoto) seja maior que 0.9 serão considerados *activity cliffs*.<jupyter_code>from rdkit.Chem import AllChem
from rdkit.Chem import MACCSkeys

# Criar coluna com RDKit Mol
df["rdkit_mol"] = df["SMILES"].apply(Chem.MolFromSmiles)

# Criar coluna com MACCS fingerprints
df["Morgan"] = df["rdkit_mol"].apply(lambda mol: AllChem.GetMorganFingerprintAsBitVect(mol, 2, nBits=1024))
# df["MACCS"] = df["rdkit_mol"].apply(MACCSkeys.GenMACCSKeys)
# Calcular activity cliffs
cliffs = []
fps = df["Morgan"].to_list()

for i in range(len(fps)):
    for j in range(i+1, len(fps)):
        sim = DataStructs.FingerprintSimilarity(fps[i], fps[j], metric=DataStructs.TanimotoSimilarity)
        if (sim > 0.9) and (df.loc[i]["Active"] != df.loc[j]["Active"]):
            # Append the indexes of the pair in order (active, inactive)
            if df.loc[i]["Active"]:
                cliffs.append((i,j))
            else:
                cliffs.append((j,i))
# Criar listas com os RDKit Mol de cada cliff e legendas contendo o índice e o valor da atividade
ms = []
leg = []
for item in cliffs:
    ms.append(df.loc[item[0]]["rdkit_mol"])
    leg.append(', '.join((str(item[0]), df.loc[item[0]]["pChEMBL"])))
    ms.append(df.loc[item[1]]["rdkit_mol"])
    leg.append(', '.join((str(item[1]), df.loc[item[1]]["pChEMBL"])))
# Quantos cliffs foram encontrados
len(cliffs)
img = Draw.MolsToGridImage(ms, molsPerRow=2, subImgSize=(500, 300), legends=leg)
img<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09107047754304988, 'fraction_numerical': 0.009408840759808274, 'mean_word_length': 5.143947655398037, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 16, 'https://': 1, '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': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '263141', 'license': 'MIT', 'n_tokens_mistral': 2016, 'n_tokens_neox': 1897, 'n_words': 651, 'path': 'Quiminformatica/qinfo - Encontrando activity cliffs.ipynb', 'repo_name': 'rflameiro/Python_e_Quiminformatica', 'size': '5633'}