azevedolab.net 1 Modelagem de Sistemas O fluxograma abaixo destaca o uso de uma abordagem computacional para o estudo de sistemas biológicos, destacado em vermelho. Em verde temos a abordagem experimental. Ao final comparamos os resultados para validar a abordagem computacional. Sistema Biológico Modelagem Realiza Simulações Realiza Experimentos Resultados Experimentais Resultados das Simulações Compara Testes dos Modelos 2 Modelagem de Sistemas A comparação é necessária para a validação da abordagem computacional, sem tal etapa a modelagem fica sem base experimental para o estudo do sistema biológico a ser simulado. Sistema Biológico Modelagem Realiza Simulações Realiza Experimentos Resultados Experimentais Resultados das Simulações Compara Testes dos Modelos 3 Quantitative Structure Activity Relationship www.python.org A abordagem moderna do desenho e desenvolvimento de fármacos é resultado de um processo iterativo. Em cada iteração (ciclo de desenvolvimento), espera-se que a atividade farmacológica da molécula seja aprimorada, de forma que haja uma evolução no processo (otimização da atividade farmacológica). O diagrama ao lado ilustra o ciclo. No processo iterativo, a molécula é desenhada e passa para síntese. Neste ponto pode ser necessário retorno à fase de desenho, caso a síntese apresente desafios, não previstos na fase de desenho. Quantitative Structure Activity Relationship www.python.org Chegando-se à fase de teste, a atividade é averiguada e os resultados relacionados à estrutura do fármaco em potencial. Neste processo podemos inserir uma fase de análise, onde elaboramos um modelo computacional. O modelo permite que a atividade da molécula seja relacionada com sua estrutura, ou seja, um estudo da Relação Quantitativa-Estrutura-Atividade (Quantitative Structure-Activity Relationship, QSAR). Neste estudo, descritores moleculares são relacionados à atividade da molécula, e uma análise estatística dos descritores leva a um modelo, que pode ser usado para prever atividade farmacológica. QSAR Quantitative Structure Activity Relationship www.python.org A abordagem de QSAR foi introduzida pelo trabalho pioneiro de Corwin Hansch na década de 1960, no seu estudo da atividade biológica de uma série de compostos relacionados estruturalmente. A atividade biológica pode ser relacionada com a estrutura molecular, a partir de equações como a descrita abaixo: 1 log 0 1 logP 2 C onde C é a concentração molar de um composto necessário para produzir uma dada atividade biológica, por exemplo IC50, log P é o coeficiente de partição entre octanol e água, é outro descritor molecular, como número de doadores de ligação de hidrogênio da molécula. Descritores moleculares descrevem propriedade gerais de uma dada molécula, que podem estar relacionadas com a atividade farmacológica. Por exemplo, um logP abaixo de 5, indica que a molécula tem baixa hidrofobicidade, aumentando as chances de disponibilidade oral. Fonte da imagem: http://www.sciencephoto.com/media/350656/enlarge Acesso em: 25 de novembro de 2016. Hansch, C., Ruth, A.S., Anderson, S.M., Bentley, D.L. Parabolic dependence of drug action upon lipophilic character as revealed by study of hypnotics. J. Med Chem 11 (1968) 1-11. Quantitative Structure Activity Relationship www.python.org Várias metodologias têm sido usadas para elaborar modelos de QSAR, sendo regressão a mais aplicada, colocada na sua forma linear, a equação de regressão tem o seguinte aspecto: y = 0 + 1 x onde y é a variável dependente (a propriedade biológica a ser modelada), um exemplo de variável dependente usada em QSAR é log (1/IC50). IC50 é a constante inibitória para que a atividade biológica caia 50 %. O termo x é a variável independente (descritor molecular), como exemplos de variáveis independentes, usadas em QSAR, temos o log P, número de ligações rotáveis, número de doadores de ligação de H etc. O 1 é coeficiente angular da reta, ou do ponto de vista de otimização, o peso da variável x e 0 é a constante de regressão. Reta (em vermelho) obtida por regressão linear para um conjunto de pontos experimentais (pontos azuis). O gráfico foi gerado com o programa Mathematica (http://demonstrations.wolfram.com/VisualizingrsquareddInSt atistics/) Acesso em: 25 de novembro de 2016. Quantitative Structure Activity Relationship www.python.org Não é objetivo do presente curso ir a fundo em métodos numéricos, mas a matemática necessária para entendermos a regressão linear é simples, por isso vamos ver as equações usadas no método. Nas equações abaixo, os termos entre < > indicam média aritmética. Na regressão linear, os coeficientes ’s são dados pelas seguintes equações, N 1 ( x i x )( y i y ) 0 y 1 x i 1 N 2 (xi x ) i 1 As linhas descritas por regressão linear passam pelo ponto médio ( x , y ), onde <x> e <y> são as médias das variáveis independente e dependente, respectivamente, como mostrada nas equações abaixo, N é o número de dados disponíveis (pares x,y): 1 N x xi N i 1 1 N y yi N i 1 Quantitative Structure Activity Relationship www.python.org Vamos considerar um conjunto de 20 pontos, mostrados na tabela abaixo. Usaremos estes dados para calcular a melhor reta, a partir das equações da regressão linear. O Excel já tem uma função de regressão, usaremos o exemplo abaixo para explicitar os termos. X Y Numa abordagem algorítmica para resolução do 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 1.25 1.5 4 5.1 6.3 5 8.7 9 11 14 13.75 15 18 17.5 19 17 21 22.5 26 25.1 problema, temos como primeiro passo o cálculo da média, com as equações abaixo: x 1 N y yi N i 1 1 xi N i 1 N Em seguida calculamos 1, com a equação a seguir: N 1 ( x i x )( y i y ) i 1 Por último calculamos 0. 0 y 1 x N 2 (xi x ) i 1 Quantitative Structure Activity Relationship www.python.org Temos a seguinte sequencia de cálculos: 1) Médias 1 N x x i 1,05 N i 1 1 N y y i 13,035 N i 1 2) Cálculo do 1 N 1 ( x i x )( y i y ) i 1 N 2 (xi x ) 85,795 6,65 i 1 12,902 3) Cálculo do 0 0 y x 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 1.05 y 1.25 1.5 4 5.1 6.3 5 8.7 9 11 14 13.75 15 18 17.5 19 17 21 22.5 26 25.1 13.035 1 x x- <x> -0.95 -0.85 -0.75 -0.65 -0.55 -0.45 -0.35 -0.25 -0.15 -0.05 0.05 0.15 0.25 0.35 0.45 0.55 0.65 0.75 0.85 0.95 y-<y> (x-<x>)(y-<y>) (x-<x>)^2 -11.785 11.19575 0.9025 -11.535 9.80475 0.7225 -9.035 6.77625 0.5625 -7.935 5.15775 0.4225 -6.735 3.70425 0.3025 -8.035 3.61575 0.2025 -4.335 1.51725 0.1225 -4.035 1.00875 0.0625 -2.035 0.30525 0.0225 0.965 -0.04825 0.0025 0.715 0.03575 0.0025 1.965 0.29475 0.0225 4.965 1.24125 0.0625 4.465 1.56275 0.1225 5.965 2.68425 0.2025 3.965 2.18075 0.3025 7.965 5.17725 0.4225 9.465 7.09875 0.5625 12.965 11.02025 0.7225 12.065 11.46175 0.9025 85.795 6.65 13,035 12,902.1,05 0,512 Quantitative Structure Activity Relationship www.python.org No final temos a melhor reta (equação de regressão), indicada abaixo: y = 1x + 0 y =12,902x – 0,512 Y 0.1 1.25 0.2 1.5 0.3 4 0.4 5.1 0.5 6.3 0.6 5 0.7 8.7 0.8 9 0.9 11 1 14 1.1 13.75 1.2 15 1.3 18 1.4 17.5 1.5 19 1.6 17 1.7 21 1.8 22.5 1.9 26 2 25.1 30 25 Variável dependente X 20 15 10 5 0 0 0,5 1 1,5 2 2,5 Variável independente Na elaboração de modelos de QSAR, normalmente temos mais de uma variável independente, o que leva ao uso de regressão linear múltipla. Outro nível de abstração do modelo de QSAR, é o uso de variáveis independentes não lineares. Tais métodos de aproximação estão disponíveis em pacotes como o Mathematica (www.wolfram.com). Além disso, podemos implementar os métodos de regressão linear, a partir da linguagem de programação Python. Quantitative Structure Activity Relationship www.python.org Tanto nos modelos de QSAR, obtidos por regressão linear, como para aqueles obtidos por regressão linear múltipla, ou mesmo não linear, temos que acessar a qualidade do modelo de regressão, ou seja, a qualidade do ajuste da curva (ou reta) modelada, contra os pontos experimentais (yi). Um dos parâmetros usados, é o coeficiente de correlação quadrado (R2). Considere que ycalc,i são valores calculados a partir da equação de regressão, usando observações experimentais xi. Assim temos os seguintes termos: soma total dos quadrados (Total Sum of Squares, TSS), soma dos quadrados “explicada” (Explained Sum of Squares, ESS) e soma residual dos quadrados (Residual Sum of Squares): TSS y i y N i 1 2 ESS y calc ,i y N i 1 2 Que são usados para o cálculo de R2, como segue: RSS R 1 TSS 2 RSS y i y calc ,i N i 1 2 Quantitative Structure Activity Relationship www.python.org x y 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 1.05 1.25 1.5 4 5.1 6.3 5 8.7 9 11 14 13.75 15 18 17.5 19 17 21 22.5 26 25.1 13.035 x-<x> -0.95 -0.85 -0.75 -0.65 -0.55 -0.45 -0.35 -0.25 -0.15 -0.05 0.05 0.15 0.25 0.35 0.45 0.55 0.65 0.75 0.85 0.95 y-<y> -11.785 -11.535 -9.035 -7.935 -6.735 -8.035 -4.335 -4.035 -2.035 0.965 0.715 1.965 4.965 4.465 5.965 3.965 7.965 9.465 12.965 12.065 ycalc,i 0.7782 2.0684 3.3586 4.6488 5.939 7.2292 8.5194 9.8096 11.0998 12.39 13.6802 14.9704 16.2606 17.5508 18.841 20.1312 21.4214 22.7116 24.0018 25.292 RSS y i y calc ,i 26,66599 N i 1 R2 1 2 (y-ycalc,i)^2 0.22259524 0.32307856 0.41139396 0.20358144 0.130321 4.96933264 0.03261636 0.65545216 0.00996004 2.5921 0.00487204 0.00087616 3.02551236 0.00258064 0.025281 9.80441344 0.17757796 0.04477456 3.99280324 0.036864 26.6659868 (y-<y>)^2 (ycalc,i-<y))^2 138.886225 150.2291462 133.056225 120.2663156 81.631225 93.63271696 62.964225 70.32835044 45.360225 50.353216 64.561225 33.70731364 18.792225 20.39064336 16.281225 10.40320516 4.141225 3.74499904 0.931225 0.416025 0.511225 0.41628304 3.861225 3.74577316 24.651225 10.40449536 19.936225 20.39244964 35.581225 33.709636 15.721225 50.35605444 63.441225 70.33170496 89.586225 93.63658756 168.091225 120.2707022 145.564225 150.234049 1133.5505 1106.969667 TSS y i y RSS 26,66599 1 0,9765 TSS 1133,551 N i 1 2 1133,551 Quantitative Structure Activity Relationship www.python.org O coeficiente de correlação quadrado mede a qualidade do ajuste da função teórica (equação de regressão) aos pontos experimentais. Esse índice varia de 0 a 1. O valor zero não indica correlação entre os dados. Para R2 igual a 1, ou próximo desse, temos uma equação de regressão com boa correlação como os dados experimentais. A equação de regressão obtida, no exemplo apresentado, tem excelente correlação, R2 = 0,9765, tal concordância pode ser vista na análise do gráfico, onde todos os pontos experimentais estão próximos à reta de regressão. 30 y = 1x + 0 y =12,902x – 0,512 R2 = 0,9765 Variável dependente 25 20 15 10 5 0 0 0,5 1 1,5 Variável independente 2 2,5 Quantitative Structure Activity Relationship www.python.org É óbvio que sistemas biológicos, caracterizados por uma dada atividade, raramente podem ser modelados com funções lineares simples. A introdução de variáveis independentes no modelo de QSAR leva, muitas vezes, a um modelo mais robusto, onde características químicas relevantes (descritores) são considerados. Contudo, o princípio da parcimônia deve ser adotado, ou seja, nem sempre um modelo com mais variáveis independentes é o mais adequado para modelar a atividade biológica. Colocaremos como exemplo o uso do programa Mathematica para encontrarmos modelos matemáticos para conjuntos de dados. Depois implementaremos em Python. Polinômio de grau 2 (-0,634408x2 + 1,24534x + 0,0807008) usado para aproximar os cinco pontos experimentais mostrados acima. O gráfico foi gerado com o programa Mathematica (http://demonstrations.wolfram.com/CurveFitting/) Acesso em: 25 de novembro de 2016. Quantitative Structure Activity Relationship www.python.org A idéia básica atrás da aproximação de uma função é usar uma lista de funções matemáticas especificadas antecipadamente, e tentar encontrar uma combinação linear dessas funções dadas, de forma que essa combinação linear de funções fique o mais próximo possível do conjunto de dados. Vamos ilustrar as idéias principais com exemplos. Vamos considerar um conjunto formado pelos 19 pontos experimentais, indicados na tabela ao lado. Para colocar essas informações no Mathematica digitamos: x 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. y 34.8105 35.381 35.8167 40.6048 47.0132 42.4577 43.1319 37.3182 33.6343 28.0988 28.3107 29.9822 27.2542 33.407 35.4875 38.1126 41.57 42.1533 39.5108 data={{73.,34.8105},{74.,35.381},{75.,35.8167},{76.,40.6048},{77., 47.0132}, {78., 42.4577},{79., 43.1319}, {80.,37.3182},{81.,33.6343},{82.,28.0988}, {83.,28.3107},{84.,29.9822},{85.,27.2542},{86.,33.407},{87.,35.4875},{88.,38.11 26},{89.,41.57},{90.,42.1533},{91.,39.5108}}; Quantitative Structure Activity Relationship www.python.org Vamos gerar o gráfico dos pontos experimentais e conectá-los. Para isto definimos lp1 e lp2 que no Mathematica fica da seguinte forma: lp1=ListPlot[data,PlotStyle->PointSize[0.03],DisplayFunction->Identity]; lp2=ListPlot[data,PlotJoined->True, DisplayFunction->Identity]; Agora preparamos o gráfico, digitando: Show[lp1,lp2, DisplayFunction->$DisplayFunction] O resultado é mostrado ao lado. Quantitative Structure Activity Relationship www.python.org Vamos gerar curvas que ajustem-se ao conjunto de dados experimentais. Podemos testar vários cenários, esta é uma das vantagens de usarmos um pacote poderoso como o Mathematica, ou ainda uma linguagem de programação como o Python, que veremos adiante. Para gerarmos um ajuste por regressão linear e graficarmos os resultados, usamos os seguintes comandos: Clear[p] p=Fit[data,{1,x},x] plotp=Plot[p,{x,71,93},DisplayFunction->Identity]; Show[plotp,lp1,PlotRange->{0,50},DisplayFunction->$DisplayFunction] Os resultados são mostrados no gráfico. A equação de regressão é: Y= 42.2346 -0.0695772 x Vemos pelo gráfico que o ajuste é insatisfatório. Quantitative Structure Activity Relationship www.python.org Vamos tentar uma nova curva, com um polinômio com x e x2, para isto basta mudarmos a linha de comando Fit (indicado em vermelho), o restante é mantido. Clear[p] p=Fit[data,{1,x,x^2},x] plotp=Plot[p,{x,71,93},DisplayFunction->Identity]; Show[plotp,lp1,PlotRange->{0,50},DisplayFunction->$DisplayFunction] Os resultados são mostrados no gráfico. A equação de regressão é: Y= 549.149 -12.4887 x+0.0757266 x2 Vemos pelo gráfico que o ajuste é Insatisfatório. No próximo slide temos aproximações para polinômios até o grau 5. Quantitative Structure Activity Relationship www.python.org Nas figuras a seguir temos ajustes para diversas funções polinomiais. Aproximação com polinômio de grau 3 Aproximação com polinômio de grau 4 y = -13615.6+508.522 x-6.29506 x2+0.0258975 x3 y = -198884.+9597.83 x-173.196 x2+1.38539 x3-0.00414481 x4 A última função (com termos até a quinta potência) é a que melhor se ajusta aos pontos experimentais. y = 2.82867×106-176099. x+4376. x2-54.2556 x3+0.335627 x4-0.000828711 x5 Programa: qsar1.py www.python.org Usaremos o programa qsar1.py, as linhas de código estão no próximo slide. O gráfico gerado está na figura ao lado. O arquivo de entrada é o data2.csv. A equação polinomial está mostrada abaixo. Veja que o resultado está próximo ao obtido com o Mathematica para o polinômio de grau 5. Type CSV file name => data2.csv Type polynomial equation degree => 5 Best fit polynomial equation: 5 4 3 2 -0.0008287 x + 0.3356 x - 54.26 x + 4376 x - 1.761e+05 x + 2.829e+0 21 Programa: qsar1.py www.python.org Abaixo temos a função main(). Inicialmente chamamos a função read_csv() que retorna as colunas lidas como array e o grau do polinômio a ser aproximado aos pontos experimentais. Em seguida é chamada a função lsq() que determina o polinômio. Por último, é chamada a função gen_plot() que gera o gráfico. def main(): # Call read_csv() x,y,my_deg = read_csv() # Call lsq() p = lsq(x,y,my_deg) # Call gen_plot() gen_plot(x,y,p) main() 22 Programa: qsar1.py www.python.org Abaixo temos a função read_csv(), que retorna as duas colunas lidas do arquivo csv como arrays. Além do grau do polinômio. def read_csv(): """Function to read csv""" import numpy as np # Reads input file name and polynomial equation degree my_input_file = input("Type CSV file name => ") my_deg = int(input("Type polynomial equation degree => ")) # Reads CSV file my_csv = np.genfromtxt (my_input_file, delimiter=",", skip_header = 1) # Gets each column from CSV file x = my_csv[:,0] y = my_csv[:,1] return x,y,my_deg 23 Programa: qsar1.py www.python.org Abaixo temos a função lsq() que determina os coeficientes do polinômio por meio do método de regressão. def lsq(x,y,my_deg): """Function to generate regression model""" import numpy as np # Least-squares polynomial fitting z = np.polyfit(x,y, my_deg) p = np.poly1d(z) print("\nBest fit polynomial equation: ",p) return p 24 Programa: qsar1.py www.python.org Por último a função gen_plot() gera o gráfico da função. ddef gen_plot(x,y,p): """Function to generate plot""" import matplotlib.pyplot as plt # Generates plot plt.scatter(x,y) # Generates plot plt.plot(x, p(x), '-') # Shows plot plt.show() # Saves plot on png file plt.savefig('qsar1.png') 25 Programa: qsar2.py www.python.org Vimos que o coeficiente de correlação ao quadrado (R2) é usado para atestar a qualidade de um modelo obtido por regressão. A biblioteca NumPy tem a função np.corrcoef(x,y)[0,1], para o cálculo do coeficiente de correlação (R) entre os arrays x e y. A partir deste valor, basta elevarmos ao quadrado para obtermos R2. O código qsar2.py traz esta função. Se usarmos o programa qsar2.py, com o arquivo data1.csv, podemos conferir com os resultados anteriormente determinados. O gráfico está ao lado. Os resultados estão no quadro abaixo. O código está no próximo slide, com as linhas em vermelho indicando as modificações com relação ao qsar1.py. Type CSV file name => data1.csv Type polynomial equation degree => 1 Best fit polynomial equation: 12.9 x - 0.5116 , R^2 = 0.976475697411 26 Programa: qsar2.py www.python.org A única modificação no programa qsar2.py é na função lsq() que agora calcula o R2, como destacado abaixo. def lsq(x,y,my_deg): """Function to generate regression model""" import numpy as np # Least-squares polynomial fitting z = np.polyfit(x,y, my_deg) p = np.poly1d(z) rsquare = (np.corrcoef(y,p(x))[0,1] )**2 print("\nBest fit polynomial equation: ",p,", R^2 = ",rsquare) return p 27 SciKit-Learn www.python.org Já vimos programas que faziam uso de funções pré-definidas das bibliotecas NumPy e Matplotlib. Agora continuaremos a expandir nosso arsenal de bibliotecas, com alguns programas que usam recursos da biblioteca scikit-learn. Esta biblioteca é dedicada a disponibilizar para comunidade de programadores em Python ferramentas de aprendizado de máquina. Usaremos scikit-learn para resolver um problema simples e depois aplicaremos o que aprendemos para um problema para a previsão de atividade de uma série de fármacos contra câncer. “Machine Learning is the study and design of programs that improve the performance of a task by learning from experience. It is the study of programs that learn from data.” HACKELING G. Mastering Machine Learning with scikitlearn. Birmingham: Packt Publishing Ltd., 2014. 221 p. Página de entrada do site scikit-learn.org. Acesso em 25 de novembro de 2016. 28 SciKit-Learn www.python.org Vamos supor que você quer usar métodos de aprendizado de máquina para prever o preço de uma pizza. Você foi recentemente 5 vezes ao Blondie’s Pizza e comprou pizzas de diferentes diâmetros, como detalhado na tabela abaixo. Índice do Dado do Conjunto Treino Diâmetro da Pizza (cm) Preço (R$) 1 15,0 24,50 2 20,0 31,50 3 25,0 45,50 4 35,0 61,25 5 45,0 63,00 29 SciKit-Learn (pizza1.py) www.python.org Abaixo temos a função main() que evoca as funções read_CSV() e gen_scatter_plot1(). Veja que a primeira função a ser evocada é a read_CSV(), que retorna os arrays x e y que são passados como argumentos da função gen_scatter_plot1(). def main(): # Call read_CSV() function x,y = read_CSV() # Call gen_scatter_plot1() gen_scatter_plot1(x,y,"Diameter (cm)","R$","Pizza Price vs Diameter","pizza1.png") main() 30 SciKit-Learn (pizza1.py) www.python.org Iremos gerar um gráfico de dispersão para os dados da tabela anterior (arquivo pizza1.csv) com os recursos da biblioteca Matplotlib. O programa pizza1.py tem duas funções, uma para leitura de um arquivo no formato CSV (read_CSV()) e outra para o gráfico de dispersão dos pontos. Abaixo temos a função read_CSV(). Nesta função importamos a biblioteca NumPy, em seguida lemos o nome do arquivo de entrada. Depois usamos o genfromtxt() para realizarmos a leitura de um arquivo no formato CSV. As colunas são atribuídas como arrays às variáveis x e y. Estes arrays retornam ao trecho onde a função foi evocada. def read_CSV(): """Function to read a CSV file and return two columns""" import numpy as np # Reads input file name my_input_file = input("Type CSV file name => ") # Reads CSV file my_csv = np.genfromtxt (my_input_file, delimiter=",", skip_header = 1) # Gets each column from CSV file x = my_csv[:,0] y = my_csv[:,1] return x,y 31 SciKit-Learn (pizza1.py) www.python.org Abaixo temos a função gen_scatter_plot1(), que gera o gráfico de dispersão. Nesta função temos os recursos do Matplotlib vistos anteriormente. def gen_scatter_plot1(x,y,x_label,y_label,title,output_file): """Function to generate scatter plot""" import matplotlib.pyplot as plt # Generates plot plt.scatter(x,y) # Title plt.title(title) # X-axis label plt.xlabel(x_label) # Y-axis label plt.ylabel(y_label) # Grid plt.grid(True) # Shows plot plt.show() # Saves plot on png file plt.savefig(output_file) 32 SciKit-Learn (pizza1.py) www.python.org Abaixo temos a execução do código pizza1.py, onde usamos o arquivo pizza1.csv como entrada. O programa gera o gráfico pizza1.png, também mostrado abaixo. Type CSV file name => pizza1.csv 33 SciKit-Learn (Regressão Linear Simples) www.python.org Retornamos à tabela do arquivo pizza1.csv. Vamos supor que você queira saber, baseado nas informações da tabela abaixo, o preço de uma pizza com diâmetro de 30 cm. Índice do Dado do Diâmetro da Pizza (cm) Preço (R$) Conjunto Treino 1 15,0 24,50 2 20,0 31,50 3 25,0 45,50 4 35,0 61,25 5 45,0 63,00 Veja, não temos na tabela o diâmetro de 30 cm, mas podemos usar a informação conhecida, chamada de observações passadas, no jargão de aprendizado da máquina, para prever o preço de uma pizza com 30 cm de diâmetro. Para esta previsão, usaremos o método de regressão linear simples, onde as observações passadas serão usadas para elaborarmos um modelo (equação) para a previsão do preço. 34 SciKit-Learn (Regressão Linear Simples) www.python.org Para nos familiarizarmos com a notação dos métodos de aprendizado de máquina, vamos definir os termos necessários para a elaboração do modelo de regressão linear. Variável explanatória Variável resposta Índice do Dado do Conjunto Treino Diâmetro da Pizza (cm) Preço (R$) 1 15,0 24,50 2 20,0 31,50 3 25,0 45,50 4 35,0 61,25 5 45,0 63,00 Conjunto treino A variável diâmetro é chamada variável explanatória e o preço correspondente é a variável resposta, os valores conhecidos destas variáveis compõem o conjunto treino (training data). O método de regressão é chamado de método de aprendizado supervisionado, visto que usamos as observações passadas, para obter um modelo contínuo entre variável resposta e a variável explanatória. 35 SciKit-Learn (Regressão Linear Simples) www.python.org Vimos a função polyfit() da biblioteca NumPy para realizar a regressão linear. Na biblioteca SciKit-learn temos o método linear_model.LinearRegression(). Vamos ilustrar seu uso no programa pizza2.py. Mas antes de iniciarmos o código, devemos fazer algumas considerações sobre o uso de métodos das bibliotecas do Python. Essas bibliotecas facilitam a vida do programador, pois disponibilizam métodos sofisticados, prontos para uso. Por outro lado, temos que estar atentos à estrutura dos dados que são inseridos nos métodos. No nosso exemplo do preço da pizza, se colocarmos um print() para os arrays x e y, que retornam da função read_CSV(), teremos o seguinte resultado. [ 15. 20. 25. 35. 45.] [ 24.5 31.5 45.5 61.25 63. ] O que funcionou bem quando foram passados para a função gen_scatter_plot1(). Por outro lado, para usarmos o método linear_model.LinearRegression(), temos que ter os arrays na seguinte estrutura. [[15.0], [20.0], [25.0], [35.0], [45.0]] [[24.5], [31.5], [45.5], [61.25], [63.0]] Assim, temos que converter os arrays para a estrutura acima, caso contrário teremos uma mensagem de erro ao executar o código. 36 SciKit-Learn (Regressão Linear Simples) (pizza2.py) www.python.org O programa pizza2.py tem uma função para converter os arrays, chamada convert2scikit(). O código está mostrado abaixo. O que a função faz é basicamente receber um array x e convertê-lo num array de arrays. Para isto a função varre o array de entrada e atribui o elemento do array a uma lista (list0) que então é passada para o array de arrays (X). A função retorna o array modificado. def convert2scikit(x): """Function to convert array to scikit-learn format""" # Set up empty lists X = [] list0 = [] # Looping through x for line in x: # Converts element to list list0.append(line) # Append list to list X.append(list0) list0 = [] # Return new array return X 37 SciKit-Learn (Regressão Linear Simples) (pizza2.py) www.python.org Para geramos o modelo, usamos a função simple_linear_regression1(). Os arrays x_in e y_in são os parâmetros da função. Explicaremos cada linha. Inicialmente importamos o método linear_model da biblioteca simple_linear_regression1. Também importamos a biblioteca NumPy, ambas indicadas em vermelho abaixo. def simple_linear_regression1(x_in,y_in): """Function to generate a linear regression model for one explanatory variable and their response variable. This function uses sklearn.linear_model.LinearRegression method.""" # Import library from sklearn import linear_model import numpy as np # Create and fit the model model = linear_model.LinearRegression() model.fit(x_in, y_in) # Get Linear Model alpha1 = float(model.coef_) const = float(model.intercept_) z = np.array([alpha1,const]) p = np.poly1d(z) A classe sklearn import linear_model é um “estimador”, que é usado para prever um valor, baseado em dados observados. print("\nBest fit linear regression model: ",p) return p 38 SciKit-Learn (Regressão Linear Simples) (pizza2.py) www.python.org Para criarmos o modelo de regressão linear (model), usamos o comando model = linear_model.LinearRegression(), que permite que usemos o método para regressão linear, chamado .fit(), como indicado abaixo. O método .fit() ajusta uma reta com equação y = const + alpha1.x aos pontos do conjunto treino. def simple_linear_regression1(x_in,y_in): """Function to generate a linear regression model for one explanatory variable and their response variable. This function uses sklearn.linear_model.LinearRegression method.""" # Import library from sklearn import linear_model import numpy as np # Create and fit the model model = linear_model.LinearRegression() model.fit(x_in, y_in) # Get Linear Model alpha1 = float(model.coef_) const = float(model.intercept_) z = np.array([alpha1,const]) p = np.poly1d(z) print("\nBest fit linear regression model: ",p) return p 39 SciKit-Learn (Regressão Linear Simples) (pizza2.py) www.python.org A constante da reta pode ser obtida a partir do comando const = float(model.intercept_) e o coeficiente angular pode ser determinado a partir do comando, alpha1 = float(model.coef_), como indicado abaixo. def simple_linear_regression1(x_in,y_in): """Function to generate a linear regression model for one explanatory variable and their response variable. This function uses sklearn.linear_model.LinearRegression method.""" # Import library from sklearn import linear_model import numpy as np # Create and fit the model model = linear_model.LinearRegression() model.fit(x_in, y_in) # Get Linear Model alpha1 = float(model.coef_) const = float(model.intercept_) z = np.array([alpha1,const]) p = np.poly1d(z) print("\nBest fit linear regression model: ",p) return p 40 SciKit-Learn (Regressão Linear Simples) (pizza2.py) www.python.org A seguir montamos um array com a constante e coeficiente angular, com o comando, z = np.array([alpha1,const]). O array z é usado para gerar a equação da reta, com o comando p = np.poly1d(z). Por último, a equação da reta de regressão linear é mostrada na tela e retornamos o p para o programa principal. def simple_linear_regression1(x_in,y_in): """Function to generate a linear regression model for one explanatory variable and their response variable. This function uses sklearn.linear_model.LinearRegression method.""" # Import library from sklearn import linear_model import numpy as np # Create and fit the model model = linear_model.LinearRegression() model.fit(x_in, y_in) # Get Linear Model alpha1 = float(model.coef_) const = float(model.intercept_) z = np.array([alpha1,const]) p = np.poly1d(z) print("\nBest fit linear regression model: ",p) return p 41 SciKit-Learn (Regressão Linear Simples) (pizza2.py) www.python.org A função gen_scatter_plot2() traz como novidade a inclusão da equação da reta p como parâmetro e uma linha de código para incluir a reta no gráfico, destacada em vermelho no código abaixo. O restante do código é o mesmo da função gen_scatter_plot1(), vista no programa pizza1.py. def gen_scatter_plot2(x,y,p,x_label,y_label,title,output_file): """Function to generate scatter plot""" import matplotlib.pyplot as plt # Generates plot plt.scatter(x,y) # Title plt.title(title) # X-axis label plt.xlabel(x_label) # Y-axis label plt.ylabel(y_label) # Grid plt.grid(True) # Generates plot plt.plot(x, p(x), '-') # Shows plot plt.show() # Saves plot on png file plt.savefig(output_file) Gera o gráfico da reta 42 SciKit-Learn (Regressão Linear Simples) (pizza2.py) www.python.org A função main() evoca duas vezes a função convert2scikit(), em seguida evocamos a função simple_linear_regression1(). Depois mostramos o valor previsto para preço da pizza de 30 cm e, por ultimo, chamamos a função gen_scatter_plot2() para gerarmos o gráfico. def main(): # Call read_CSV() function x,y = read_CSV() # Call convert2scikit(x) xs = convert2scikit(x) ys = convert2scikit(y) # Call simple_linear_regression1() p = simple_linear_regression1(xs,ys) # Predict the price for 30 cm pizza pred = p(30) print("Predicted price for 30 cm pizza (R$): %.2f"%pred) # Call gen_scatter_plot2() gen_scatter_plot2(x,y,p,"Diameter (cm)","R$","Pizza Price vs Diameter","pizza2.png“ main() 43 SciKit-Learn (Regressão Linear Simples) (pizza2.py) www.python.org Vejam que ao usarmos a linha de comando pred = p(30) colocamos como argumento da equação p o valor 30. A equação p é a equação obtida por regressão linear, quando evocamos a função simple_linear_regression1(). def main(): # Call read_CSV() function x,y = read_CSV() # Call convert2scikit(x) xs = convert2scikit(x) ys = convert2scikit(y) # Call simple_linear_regression1() p = simple_linear_regression1(xs,ys) # Predict the price for 30 cm pizza pred = p(30) print("Predicted price for 30 cm pizza (R$): %.2f"%pred) # Call gen_scatter_plot2() gen_scatter_plot2(x,y,p,"Diameter (cm)","R$","Pizza Price vs Diameter","pizza2.png“ main() 44 SciKit-Learn (pizza2.py) www.python.org Abaixo temos a execução do código pizza2.py, onde usamos o arquivo pizza1.csv como entrada. O programa gera o gráfico pizza2.png, também mostrado abaixo. A linha azul do gráfico é a equação obtida por regressão linear. Type CSV file name => pizza1.csv Best fit linear regression model: 1.367 x + 6.879 Predicted price for 30 cm pizza (R$): 47.88 45 SciKit-Learn (pizza2.py) www.python.org De forma resumida, podemos dizer que a melhor reta é aquela que minimiza a distância dos pontos experimentais (dados do conjunto treino) para a reta. Matematicamente, a equação da reta (p) tem a seguinte forma: p 0 1 x1 Onde p tem o valor estimado (teórico) para o preço da pizza e x1 recebe o valor do diâmetro da pizza( variável explanatória). Os coeficientes (0 e 1) são determinados de forma minimizar a diferença entre p e os valores experimentais do preço da pizza (yi), ou seja, minimizam a soma do quadrado dos resíduos (Residual Sum of Squares): RSS N 2 y p i i i 1 A somatória é feita para todos os pontos do conjunto treino. 46 SciKit-Learn (Regressão Linear Simples) (pizza3.py) www.python.org Muito bem, temos um modelo para previsão do preço da pizza, mas o quão confiável é nosso modelo? Vamos supor que vimos um anuncio da Blondie’s pizza com a seguinte tabela de preços (pizza2.csv). Esta informação não foi usada para obtermos o modelo de regressão, tal conjunto de dados é chamado de conjunto teste (test set). Adicionamos uma coluna com os valores previstos pelo nosso modelo. O conjunto teste pode ser usado para avaliar o poder de previsão do nosso modelo. Índice do Dado do Conjunto Test Diâmetro da Pizza (cm) Preço (R$) Preço Previsto pelo Modelo (R$) 1 20,0 38,50 34,22 2 22,5 29,75 37,63 3 27,5 52,50 44,47 4 40,0 63,00 61,55 5 30,0 38,50 47,88 47 Quantitative Structure Activity Relationship www.python.org Para acessar a qualidade do modelo de regressão, ou seja, a qualidade do ajuste da curva (ou reta) modelada, contra os pontos experimentais (yi), podemos calcular o coeficiente r2. Considere que pi são valores calculados a partir da equação de regressão, usando observações experimentais xi. Assim temos os seguintes termos: soma total dos quadrados (Total Sum of Squares, TSS), soma dos quadrados “explicada” (Explained Sum of Squares, ESS) e soma residual dos quadrados (Residual Sum of Squares): TSS yi N i 1 p 2 ESS pi N p 2 i 1 RSS N y pi 2 i i 1 O termo <p> representa o valor médio do preço da pizza estimado pela equação de regressão linear (p). O termo yi representa o valor do preço (experimental) da pizza para os diferentes diâmetros. Os termos acima são usados para o cálculo de R2, como segue: RSS R 1 TSS 2 SciKit-Learn (Regressão Linear Simples) (pizza3.py) www.python.org Modificaremos a função simple_linear_regression1() para que esta calcule o R2 no programa pizza3.py. O programa pizza3.py lerá os dados dos conjuntos treino (pizza1.csv) e teste (pizza2.csv). Índice do Dado do Conjunto Test Diâmetro da Pizza (cm) Preço (R$) Preço Previsto pelo Modelo (R$) 1 20,0 38,50 34,22 2 22,5 29,75 37,63 3 27,5 52,50 44,47 4 40,0 63,00 61,55 5 30,0 38,50 47,88 49 SciKit-Learn (Regressão Linear Simples) (pizza3.py) www.python.org A função simple_linear_regression2() tem quatro parâmetros, além dos dois anteriores (x_in,y_in), com os dados do conjunto treino, temos dois novos arrays para os dados do conjunto teste (parâmetros x_test e y_test). def simple_linear_regression2(x_in,y_in,x_test,y_test): """Function to generate a linear regression model for one explanatory variable and their response variable. This function uses sklearn.linear_model.LinearRegression method.""" # Import library from sklearn import linear_model import numpy as np # Create and fit the model model = linear_model.LinearRegression() model.fit(x_in, y_in) # Get Linear Model alpha1 = float(model.coef_) const = float(model.intercept_) z = np.array([alpha1,const]) p = np.poly1d(z) r_square = model.score(x_test, y_test) print("\nBest fit linear regression model: ",p) print('R-squared: %.4f' % r_square) return p 50 SciKit-Learn (Regressão Linear Simples) (pizza3.py) www.python.org A outra novidade é o método .score(), que é usado para calcular o R2 que é atribuído à variável r_square. O resultado é mostrado na tela. def simple_linear_regression2(x_in,y_in,x_test,y_test): """Function to generate a linear regression model for one explanatory variable and their response variable. This function uses sklearn.linear_model.LinearRegression method.""" # Import library from sklearn import linear_model import numpy as np # Create and fit the model model = linear_model.LinearRegression() model.fit(x_in, y_in) # Get Linear Model alpha1 = float(model.coef_) const = float(model.intercept_) z = np.array([alpha1,const]) p = np.poly1d(z) r_square = model.score(x_test, y_test) print("\nBest fit linear regression model: ",p) print('R-squared: %.4f' % r_square) return p 51 SciKit-Learn (Regressão Linear Simples) (pizza3.py) www.python.org No programa principal (função main()) temos que evocar duas vezes a leitura dos arquivos CSV (função read_CSV()) além das respectivas conversões, como destacado em vermelho abaixo. def main(): # Call read_CSV() function x1,y1 = read_CSV() # Call convert2scikit() xs1 = convert2scikit(x1) ys1 = convert2scikit(y1) # Call read_CSV() function again x2,y2 = read_CSV() # Call convert2scikit(x) again xs2 = convert2scikit(x2) ys2 = convert2scikit(y2) # Call simple_linear_regression2() p = simple_linear_regression2(xs1,ys1,xs2,ys2) # Call gen_scatter_plot2() gen_scatter_plot2(xs1,ys1,p,"Diameter (cm)","R$","Pizza Price vs Diameter","pizza3.png") main() 52 SciKit-Learn (Regressão Linear Simples) (pizza3.py) www.python.org Abaixo temos o resultado de rodar o programa pizza3.py, veja que temos dois arquivos de entrada. Type CSV file name => pizza1.csv Type CSV file name => pizza2.csv Best fit linear regression model: 1.367 x + 6.879 R-squared: 0.6620 53 SciKit-Learn (Regressão Linear Múltipla) www.python.org Muito bem, evoluímos com nosso modelo para previsão do preço das pizzas. Mas se refletimos sobre a qualidade do nosso modelo, podemos imaginar que temos como melhoras. Qualquer apreciador de pizza sabe que um dos determinantes do preço da pizza é o número de coberturas. Assim podemos adicionar esta nova variável explanatória ao nosso modelo. Assim, a equação de regressão passa a ter múltiplas varáveis, um caso geral a equação tem a seguinte forma, p 0 1 x1 2 x2 3 x3 ... M xM Onde M é o número de variáveis explanatórias. Quando usamos a equação acima para obtermos um modelo estamos usando o método de regressão linear múltipla. No nosso novo modelo para previsão do preço das pizzas adicionamos uma variável explanatória, assim a equação tem a seguinte forma, p 0 1 x1 2 x2 54 SciKit-Learn (Regressão Linear Múltipla) www.python.org Retornamos às tabelas de preço, só que agora temos uma informação adicional, com o número de coberturas para o conjunto treino. Índice do Dado do Conjunto Treino Diâmetro da Pizza (cm) Número de Coberturas Preço (R$) 1 15,0 2 24,50 2 20,0 1 31,50 3 25,0 0 45,50 4 35,0 2 61,25 5 45,0 0 63,00 A nova coluna é a variável explanatória x2. 55 SciKit-Learn (Regressão Linear Múltipla) www.python.org Abaixo temos a tabela para o conjunto teste Índice do Dado do Diâmetro da Pizza (cm) Conjunto Teste Número de Coberturas Preço (R$) 1 20,0 2 38,50 2 22,5 0 29,75 3 27,5 2 52,50 4 40,0 2 63,00 5 30,0 0 38,50 A nova coluna é a variável explanatória x2. 56 SciKit-Learn (Regressão Linear Simples) (pizza4.py) www.python.org Para simplificar a apresentação vamos elaborar um código para gerar o modelo de regressão múltipla e prever o preço da pizza de 40 cm. O código da função main() segue abaixo. def main(): # Call read_CSV_3cols() function x1,x2,y1 = read_CSV_3cols() # Call convert2scikit() ytr = convert2scikit(y1) # Call make_2d_array() Xtr = make_2d_array(x1,x2) # Call read_CSV_3cols() function again x1,x2,y2 = read_CSV_3cols() # Call convert2scikit(x) again yte = convert2scikit(y2) # Call make_2d_array() Xte = make_2d_array(x1,x2) # Call multiple_linear_regression() p = multiple_linear_regression(Xtr,ytr,Xte,yte) # Prediction of the price for 40 cm pizza y = p[0] + p[1]*2.0 + p[2]*40.0 print("\nPredicted price for 40 cm pizza: %6.2f"%y) main() 57 SciKit-Learn (Regressão Linear Simples) (pizza4.py) www.python.org A principal novidade é que temos que converter as duas colunas com as variáveis explanatórias (diâmetro e número de coberturas) num array bidimensional, ou seja, uma matriz. Usaremos a função make_2d_array(). def main(): # Call read_CSV_3cols() function x1,x2,y1 = read_CSV_3cols() # Call convert2scikit() ytr = convert2scikit(y1) # Call make_2d_array() Xtr = make_2d_array(x1,x2) # Call read_CSV_3cols() function again x1,x2,y2 = read_CSV_3cols() # Call convert2scikit(x) again yte = convert2scikit(y2) # Call make_2d_array() Xte = make_2d_array(x1,x2) # Call multiple_linear_regression() p = multiple_linear_regression(Xtr,ytr,Xte,yte) # Prediction of the price for 40 cm pizza y = p[0] + p[1]*2.0 + p[2]*40.0 print("\nPredicted price for 40 cm pizza: %6.2f"%y) main() 58 SciKit-Learn (Regressão Linear Simples) (pizza4.py) www.python.org Inicialmente é evocada a função read_CSV_3cols() que é similar à read_CSV() só que agora retornamos três arrays, que são atribuídos às variáveis x1,x2, y1. def main(): # Call read_CSV_3cols() function x1,x2,y1 = read_CSV_3cols() # Call convert2scikit() ytr = convert2scikit(y1) # Call make_2d_array() Xtr = make_2d_array(x1,x2) # Call read_CSV_3cols() function again x1,x2,y2 = read_CSV_3cols() # Call convert2scikit(x) again yte = convert2scikit(y2) # Call make_2d_array() Xte = make_2d_array(x1,x2) # Call multiple_linear_regression() p = multiple_linear_regression(Xtr,ytr,Xte,yte) # Prediction of the price for 40 cm pizza y = p[0] + p[1]*2.0 + p[2]*40.0 print("\nPredicted price for 40 cm pizza: %6.2f"%y) main() 59 SciKit-Learn (Regressão Linear Simples) (pizza4.py) www.python.org Em seguida convertermos a variável resposta para que possa ser lida pelo scikitlearn. def main(): # Call read_CSV_3cols() function x1,x2,y1 = read_CSV_3cols() # Call convert2scikit() ytr = convert2scikit(y1) # Call make_2d_array() Xtr = make_2d_array(x1,x2) # Call read_CSV_3cols() function again x1,x2,y2 = read_CSV_3cols() # Call convert2scikit(x) again yte = convert2scikit(y2) # Call make_2d_array() Xte = make_2d_array(x1,x2) # Call multiple_linear_regression() p = multiple_linear_regression(Xtr,ytr,Xte,yte) # Prediction of the price for 40 cm pizza y = p[0] + p[1]*2.0 + p[2]*40.0 print("\nPredicted price for 40 cm pizza: %6.2f"%y) main() 60 SciKit-Learn (Regressão Linear Simples) (pizza4.py) www.python.org A função make_2d_array() tem como argumentos os array lidos e converte estes numa matriz, que é atribuída à variável Xtr. Até então só lemos os dados do conjunto treino (ytr e Xtr). def main(): # Call read_CSV_3cols() function x1,x2,y1 = read_CSV_3cols() # Call convert2scikit() ytr = convert2scikit(y1) # Call make_2d_array() Xtr = make_2d_array(x1,x2) # Call read_CSV_3cols() function again x1,x2,y2 = read_CSV_3cols() # Call convert2scikit(x) again yte = convert2scikit(y2) # Call make_2d_array() Xte = make_2d_array(x1,x2) # Call multiple_linear_regression() p = multiple_linear_regression(Xtr,ytr,Xte,yte) # Prediction of the price for 40 cm pizza y = p[0] + p[1]*2.0 + p[2]*40.0 print("\nPredicted price for 40 cm pizza: %6.2f"%y) main() 61 SciKit-Learn (Regressão Linear Simples) (pizza4.py) www.python.org As linhas seguintes fazem a leitura e conversão dos dados do conjunto treino. Em seguida é chamada a função multiple_linear_regression() que recebe as matrizes Xtr e Xte. def main(): # Call read_CSV_3cols() function x1,x2,y1 = read_CSV_3cols() # Call convert2scikit() ytr = convert2scikit(y1) # Call make_2d_array() Xtr = make_2d_array(x1,x2) # Call read_CSV_3cols() function again x1,x2,y2 = read_CSV_3cols() # Call convert2scikit(x) again yte = convert2scikit(y2) # Call make_2d_array() Xte = make_2d_array(x1,x2) # Call multiple_linear_regression() p = multiple_linear_regression(Xtr,ytr,Xte,yte) # Prediction of the price for 40 cm pizza y = p[0] + p[1]*2.0 + p[2]*40.0 print("\nPredicted price for 40 cm pizza: %6.2f"%y) main() 62 SciKit-Learn (Regressão Linear Simples) (pizza4.py) www.python.org Por último usamos o polinômio determinado, para obtermos uma estimativa do preço da pizza de 40 cm com duas coberturas. def main(): # Call read_CSV_3cols() function x1,x2,y1 = read_CSV_3cols() # Call convert2scikit() ytr = convert2scikit(y1) # Call make_2d_array() Xtr = make_2d_array(x1,x2) # Call read_CSV_3cols() function again x1,x2,y2 = read_CSV_3cols() # Call convert2scikit(x) again yte = convert2scikit(y2) # Call make_2d_array() Xte = make_2d_array(x1,x2) # Call multiple_linear_regression() p = multiple_linear_regression(Xtr,ytr,Xte,yte) # Prediction of the price for 40 cm pizza y = p[0] + p[1]*2.0 + p[2]*40.0 print("\nPredicted price for 40 cm pizza: %6.2f"%y) main() 63 SciKit-Learn (Regressão Linear Simples) (pizza4.py) www.python.org A única função nova é a make_2d_array(), mostrada abaixo. A novidade aqui é que geramos uma matriz de zeros. Em seguida temos um loop for que atribui os elementos dos vetores aos elementos da matrix. def make_2d_array(x1,x2): """Function to make 2-d array""" import numpy as np # Set up number of columns and rows number_columns = 2 number_rows = len(x1) # Set up zero matrix X= [[0]*number_columns for i in range(number_rows)] # Get matrix for i in range(number_rows): X[i][0] = x1[i] X[i][1] = x2[i] return X 64 SciKit-Learn (Regressão Linear Simples) (pizza3.py) www.python.org Abaixo temos o resultado de rodar o programa pizza4.py, veja que temos dois arquivos de entrada. Type CSV file name => pizza3.csv Type CSV file name => pizza4.csv Best fit linear regression model: 1.415 x + 1.385 x + 4.156 R-squared: 0.7702 Predicted price for 40 cm pizza: 2 63.51 Índice do houve Dado do (cm) o Número Preço (R$) Veja que umaDiâmetro melhorada noPizza modelo, R2 foi dede0,66 para 0,77. Conjunto Teste Coberturas 1 20,0 2 38,50 2 22,5 0 29,75 3 27,5 2 52,50 4 40,0 2 63,00 5 30,0 0 38,50 65 Métodos de Aprendizado de Máquina Supervisionado www.python.org Vimos a aplicação do método de regressão linear para a elaboração de um modelo, a partir dos dados do conjunto treino. A biblioteca scikit-learn tem um arsenal de métodos de aprendizado de máquina supervisionado, além da regressão linear. Abaixo temos seis métodos disponíveis no scikit-learn. Esses métodos adicionais visam reduzir o número de variáveis explanatórias no modelo de regressão. A tabela verdade abaixo traz a identificação de cada termo com o respectivo peso do termo adicional somado ao RSS. RSS yi ycalc,i N 2 i 1 11 P P j 1 j 1 2 j 2 2 j Método Linear Regression Ridge Ridge CV Lasso Lasso CV Elastic Net Elastic Net CV α1 0 0 0 1 1 1 1 α2 0 1 1 0 0 1 1 66 Modelagem de Sistemas (CDKs com Ki) Para discutirmos os principais métodos para melhora de funções escores com métodos de aprendizado de máquina supervisionado, iremos considerar como sistema biológico uma proteína chamada quinase dependente de ciclina (CDKs) com informação de Ki (constante de inibição). Moléculas que se ligam à CDK tem o potencial de serem usadas como drogas contra o câncer. 67 Modelagem de Sistemas (CDKs com Ki) Abaixo temos uma tabela com informações para 30 estruturas de CDKs para as quais há informação de Ki. Iremos considerar somente três variáveis explanatórias, Protein Score, Water Score e Electro Long Score. A variável log(Ki) é a variável resposta. 68 CDKs com Ki (Regressão Linear) Usaremos um programa que é parte integrante do SAnDReS (Xavier et al., 2016). O programa chamado sml15.py chama um módulo (scikit_regression_methods_v001z_works.py). Nos concentraremos no seu uso. Abaixo temos o trecho do programa principal que faz a leitura do arquivo CSV e indica o método de regressão linear. def main(): # # # # # # Get the CSV file name, we the following file to be used as imput: Verma_Hansch_EJMC_2010_Table1.csv Verma_Hansch_EJMC_2010_Table2.csv Verma_Hansch_EJMC_2010_Table3.csv cdk_ki.csv data01_19col.csv csv_file = "cdk_ki.csv" # Call get_number_of_cols() n_columns = get_number_of_cols(csv_file) # Call generate_LOO_files() generate_LOO_files(csv_file,n_columns) # Call SF() SF(csv_file,n_columns-1,"ElasticNetCV") main() 69 CDKs com Ki (Regressão Linear) Na função main() inicialmente definimos o nome do arquivo CSV que tem as variáveis explanatórias e a variável resposta (log(Ki)), indicada em vermelho. def main(): # # # # # # Get the CSV file name, we the following file to be used as imput: Verma_Hansch_EJMC_2010_Table1.csv Verma_Hansch_EJMC_2010_Table2.csv Verma_Hansch_EJMC_2010_Table3.csv cdk_ki.csv data01_19col.csv csv_file = "cdk_ki.csv" # Call get_number_of_cols() n_columns = get_number_of_cols(csv_file) # Call generate_LOO_files() generate_LOO_files(csv_file,n_columns) # Call SF() SF(csv_file,n_columns-1,"ElasticNetCV") main() 70 CDKs com Ki (Regressão Linear) Em seguida é chamada a função get_number_of_cols() que determina o número de colunas do arquivo CSV. def main(): # # # # # # Get the CSV file name, we the following file to be used as imput: Verma_Hansch_EJMC_2010_Table1.csv Verma_Hansch_EJMC_2010_Table2.csv Verma_Hansch_EJMC_2010_Table3.csv cdk_ki.csv data01_19col.csv csv_file = "cdk_ki.csv" # Call get_number_of_cols() n_columns = get_number_of_cols(csv_file) # Call generate_LOO_files() generate_LOO_files(csv_file,n_columns) # Call SF() SF(csv_file,n_columns-1,"ElasticNetCV") main() 71 CDKs com Ki (Regressão Linear) Depois é chamada a função generate_LOO_files(), que gera arquivos CSV auxiliares com uma estrutura deixada fora (leave one out)(loo). Tal abordagem visa verificar a consistência interna do modelo de regressão linear gerado, onde uma linha de dado é deixada de fora para cada iteração da determinação dos pesos das variáveis explanatórias. def main(): # # # # # # Get the CSV file name, we the following file to be used as imput: Verma_Hansch_EJMC_2010_Table1.csv Verma_Hansch_EJMC_2010_Table2.csv Verma_Hansch_EJMC_2010_Table3.csv cdk_ki.csv data01_19col.csv csv_file = "cdk_ki.csv" # Call get_number_of_cols() n_columns = get_number_of_cols(csv_file) # Call generate_LOO_files() generate_LOO_files(csv_file,n_columns) # Call SF() SF(csv_file,n_columns-1,"ElasticNetCV") main() 72 CDKs com Ki (Regressão Linear) A última função chamada é a SF() que determina o modelo de regressão linear. Um dos argumentos passado é o método de regressão a ser usado, no caso abaixo “LinearRegression”. Além deste, o programa pode testar: Lasso, LassoCV, Ridge, RidgeCV, ElasticNet e ElasticNetCV def main(): # # # # # # Get the CSV file name, we the following file to be used as imput: Verma_Hansch_EJMC_2010_Table1.csv Verma_Hansch_EJMC_2010_Table2.csv Verma_Hansch_EJMC_2010_Table3.csv cdk_ki.csv data01_19col.csv csv_file = "cdk_ki.csv" # Call get_number_of_cols() n_columns = get_number_of_cols(csv_file) # Call generate_LOO_files() generate_LOO_files(csv_file,n_columns) # Call SF() SF(csv_file,n_columns-1,“LinearRegression") main() 73 CDKs com Ki (Regressão Linear) Como já vimos, o método “LinearRegression” determina os pesos de cada variável explanatória onde x1 é o Protein Score, x2 o Water Score e x3 o Electro Long Score. log( Ki ) 0 1.x1 2 .x2 3 .x3 def main(): # # # # # # Get the CSV file name, we the following file to be used as imput: Verma_Hansch_EJMC_2010_Table1.csv Verma_Hansch_EJMC_2010_Table2.csv Verma_Hansch_EJMC_2010_Table3.csv cdk_ki.csv data01_19col.csv csv_file = "cdk_ki.csv" # Call get_number_of_cols() n_columns = get_number_of_cols(csv_file) # Call generate_LOO_files() generate_LOO_files(csv_file,n_columns) # Call SF() SF(csv_file,n_columns-1,“LinearRegression") main() 74 CDKs com Ki (Regressão Linear) O método “LinearRegression” determina os pesos de cada variável explanatória de N forma que a função RSS seja minimizada. 2 RSS y x i T i i 1 RSS representa o resíduo, yi o valor experimental de log(Ki) para cada estrutura do conjunto treino. Os termos xi são as variáveis explanatórias e ω um vetor com o peso de cada variável explanatória. def main(): # # # # # # Get the CSV file name, we the following file to be used as imput: Verma_Hansch_EJMC_2010_Table1.csv Verma_Hansch_EJMC_2010_Table2.csv Verma_Hansch_EJMC_2010_Table3.csv cdk_ki.csv data01_19col.csv csv_file = "cdk_ki.csv" # Call get_number_of_cols() n_columns = get_number_of_cols(csv_file) # Call generate_LOO_files() generate_LOO_files(csv_file,n_columns) # Call SF() SF(csv_file,n_columns-1,“LinearRegression") main() 75 CDKs com Ki (Regressão Linear) Ao rodarmos o programa obtemos os seguintes resultados (arquivo SF.log). ######################################### MODEL GENERATOR ############################################### File: cdk_ki.csv Regression equation : Pred. Log(Ki) = - 4.571716 + 0.017517*(Protein) - 0.141223*(Water) - 0.511956*(ElectroLong) Error for c(0) : 2.166260 Error for Protein : 0.015999 Error for Water : 0.142385 Error for ElectroLong : 0.536931 Best fit equation between observed and predicted information: 0.2755 x - 4.834 N : Standard deviation : R : R-squared : p-value : Adjusted R-square : Spearman correlation : p-value : Quality factor (Q) : q-squared for LOO : F-stat : Chi-squared : RMSE : 30 1.209319 0.524853 0.275470 2.903439e-03 0.191871 0.567138 1.082796e-03 0.434007 0.278364 3.295116 5.764193 0.125592 76 Modelos de QSAR (Taxol) www.python.org Vamos analisar um modelo de QSAR publicado para fixarmos os conceitos de regressão. Selecionei um artigo do criador do método, Dr. C. Hansch (Verma & Hansch. QSAR modeling of taxane analogues against colon cancer. European Journal of Medicinal Chemistry 45 (2010) 1470–1477). Nesse artigo são elaborados modelos de QSAR para uma série de compostos anti-cancerígenos, análogos do taxol (CID 36314), mostrado na figura ao lado. O taxol apresenta atividade anticancerígena e é extraído da casca da árvore Taxus brevefolia. Os substituintes para gerar os análogos foram montados pela adição de diferentes grupos químicos na posição X, indicada na figura ao lado. Estrutura do taxol (CID 36314) Verma, R.P & Hansch, C. QSAR modeling of taxane analogues against colon cancer. European Journal of Medicinal Chemistry 45 (2010) 1470–1477. 77 Modelos de QSAR (Taxol) www.python.org A tabela usada para obter um dos modelos de QSAR está mostrada abaixo. Nela temos os seguintes descritores moleculares: X, MRX e ICYALK. A atividade é a inibição de células cancerosas de HCT-116 (câncer de cólon). Descreveremos brevemente os descritores moleculares. Molecule CH3 C6H5 4-F-C6H4 CH2F CCl3 C2H5 CH]CH2 (CH2)2CH3 CH(CH3)2 C(CH3) =CH2 trans-CH = CHCH3 Cy-C3H5 (CH2)3CH3 Cy-C4H7 (CH2)4CH3 Cy-C5H9 OCH3 OCH2CH3 O(CH2)2CH3 NH-Cy-C4H7 Imidazole Aziridine piX 0.7 1.91 2.05 0.37 2.58 1.23 0.85 1.76 1.54 1.16 1.38 1.28 2.28 1.61 2.81 2.17 0.68 1.21 1.74 1.55 0.18 0.87 MRX 0.46 2.51 2.53 0.48 1.94 0.93 0.98 1.39 1.39 1.44 1.44 1.25 1.86 1.68 2.32 2.14 0.62 1.08 1.54 2.05 1.73 1.12 ICYALK 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 1 0 0 Observed log 1/IC50 8.62 6.39 6.1 8.15 8.4 8.7 8.22 8.96 8.3 8.35 8.64 9 8.7 8.82 8.22 8.7 8.7 9 8.59 8.04 6.1 7.81 78 Modelos de QSAR (Taxol) www.python.org O descritor X, é a diferença entre o log P para o composto (no caso taxol) e os análogos deste (log PX ), como definido pela equação abaixo: X log PX - log P Este descritor é uma medida da hidrofobicidade. O descritor MRX é a refractividade molar, dada pela equação a seguir: n 2 - 1 MW . MR X 2 n 2 d onde n é o índice de refração, d a densidade e MW a massa molecular. Normalmente esse descritor é usado para descrever o volume da molécula. 79 Modelos de QSAR (Taxol) www.python.org O termo e ICYALK é um indicador da atividade incomum dos substituintes que apresentam cicloaquila (cycloalkyl). O termo assume o valor “1” se apresenta o grupo cicloaquila, caso contrário o valor é “0”. É o que podemos chamar de um descritor binário, que assume somente valores “0” e “1”. Molecule CH3 C6H5 4-F-C6H4 CH2F CCl3 C2H5 CH]CH2 (CH2)2CH3 CH(CH3)2 C(CH3) =CH2 trans-CH = CHCH3 Cy-C3H5 (CH2)3CH3 Cy-C4H7 (CH2)4CH3 Cy-C5H9 OCH3 OCH2CH3 O(CH2)2CH3 NH-Cy-C4H7 Imidazole Aziridine piX 0.7 1.91 2.05 0.37 2.58 1.23 0.85 1.76 1.54 1.16 1.38 1.28 2.28 1.61 2.81 2.17 0.68 1.21 1.74 1.55 0.18 0.87 MRX 0.46 2.51 2.53 0.48 1.94 0.93 0.98 1.39 1.39 1.44 1.44 1.25 1.86 1.68 2.32 2.14 0.62 1.08 1.54 2.05 1.73 1.12 ICYALK 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 1 0 0 Observed log 1/IC50 8.62 6.39 6.1 8.15 8.4 8.7 8.22 8.96 8.3 8.35 8.64 9 8.7 8.82 8.22 8.7 8.7 9 8.59 8.04 6.1 7.81 80 Modelos de QSAR (Taxol) www.python.org A abordagem clássica da modelagem de QSAR parte da tabela de atividades e descritores, para alimentarmos o programa de regressão. A atividade biológica a ser relacionada com a estrutura molecular é o IC50, assim nossa equação de regressão terá a seguinte forma geral (sem a determinação dos coeficientes ), 1 log IC 50 0 1 X 2MR X 3ICYALK A equação acima tem 3 variáveis explanatórias (X, MRX e ICYALK ) e a variável resposta é log (1/IC50). 81 Modelos de QSAR (Taxol) www.python.org A equação de regressão obtida é a seguinte: log (1/IC50) = 9.04307 +0.887579 icy-1.96693 mrx+1.33766 pix Onde: 0 = 9,04307 1 = 1,33766 2 = -1,96693 3 = 0,887579 Assim temos a seguinte equação de regressão: 1 log IC 50 9,04 1,34 X - 1,97 MR X 0,89 ICYALK A presença de um positivo para o termo ICYALK sugere que a presença do grupo é favorável à atividade dos análogos de taxol. Veja que seguimos a ordem: X, MRX, ICYALK e log (1/IC50). 82 Modelos de QSAR (Taxol) www.python.org Vamos realizar uma análise estatística dos resultados. Para isto precisamos calcular o Predicted log (1/IC50) (ycalc) para todos os pontos experimentais. A coluna indicada em vermelho foi obtida a partir da inserção da equação de regressão, obtida com o Mathematica, na planilha do Excel. Molecule piX MRX ICYALK Observed log 1/IC50 Predicted log 1/IC50 delta^2 (log 1/IC50(Exp)-<log 1/IC50(Exp)>)^2 (log 1/IC50(Teor)-<log 1/IC50(Exp)>)^2 CH3 0.7 0.46 0 8.62 9.0746442 0.206701 0.172225 0.756281035 C6H5 1.91 2.51 0 6.39 6.6610063 0.073444 3.294225 2.383916546 4-F-C6H4 2.05 2.53 0 6.1 6.8089401 0.502596 4.431025 1.948983244 CH2F 0.37 0.48 0 8.15 8.5938778 0.197028 0.003025 0.151225943 CCl3 2.58 1.94 0 8.4 8.6783886 0.0775 0.038025 0.224096767 C2H5 1.23 0.93 0 8.7 8.8591469 0.025328 0.245025 0.427908167 CH]CH2 0.85 0.98 0 8.22 8.2524896 0.001056 0.000225 0.002255262 (CH2)2CH3 1.76 1.39 0 8.96 8.6633189 0.08802 0.570025 0.210056214 CH(CH3)2 1.54 1.39 0 8.3 8.3690337 0.004766 0.009025 0.026907055 C(CH3) =CH2 1.16 1.44 0 8.35 7.7623764 0.345301 0.021025 0.195915651 trans-CH = CHCH3 1.38 1.44 0 8.64 8.0566616 0.340284 0.189225 0.022004281 Cy-C3H5 1.28 1.25 1 9 9.1841913 0.033926 0.632025 0.958815602 (CH2)3CH3 2.28 1.86 0 8.7 8.434445 0.070519 0.245025 0.052645008 Cy-C4H7 1.61 1.68 1 8.82 8.7798392 0.001613 0.378225 0.330440106 (CH2)4CH3 2.81 2.32 0 8.22 8.238617 0.000347 0.000225 0.001130103 Cy-C5H9 2.17 2.14 1 8.7 8.624141 0.005755 0.245025 0.175679178 OCH3 0.68 0.62 0 8.7 8.7331822 0.001101 0.245025 0.278976436 OCH2CH3 1.21 1.08 0 9 8.5373542 0.214041 0.632025 0.110459314 O(CH2)2CH3 1.74 1.54 0 8.59 8.3415262 0.061739 0.148225 0.018639403 NH-Cy-C4H7 1.55 2.05 1 8.04 7.9718155 0.004649 0.027225 0.054375011 Imidazole 0.18 1.73 0 6.1 5.8810599 0.047935 4.431025 5.400697588 Aziridine 0.87 1.12 0 7.81 8.0038726 0.037587 0.156025 0.040452231 83 Modelos de QSAR (Taxol) www.python.org Os valores para r2, sd e F são mostrados abaixo. Entradas N p <log 1/IC50(> 22 3 8.205 RSS 2.341235229 TSS 16.11315 ESS 13.77186015 R^2 0.854700339 sd 0.360650279 F 35.29383115 84 Modelos de QSAR (Taxol) www.python.org A partir do gráfico de dispersão entre os valores calculados (log (1/IC50)(teor) e os valores experimentais Observed (log (1/IC50), podemos verificar a boa concordância do modelo de QSAR com os dados experimentais. 9,5 9 log (1/IC50)(teor) 8,5 8 7,5 7 6,5 6 6 6,5 7 7,5 8 8,5 9 9,5 Observed log (1/IC50) 85 Trabalho 1 Considere os resultados da atividade anticâncer de uma família de moléculas disponíveis nas tabela: Verma_Hansch_EJMC_2010_Table1.csv Aplique os métodos de aprendizado de máquina supervisionado indicados na tabela abaixo e identifique o melhor modelo considerando como critério o valor de R2. RSS y N i i 1 xiT P P j 1 j 1 11 j 22 2j 2 Método Linear Regression Ridge Ridge CV Lasso Lasso CV Elastic Net Elastic Net CV α1 0 0 0 1 1 1 1 α2 0 1 1 0 0 1 1 Entrega: 29 de novembro de 2016. 86 Referências www.python.org -BRESSERT, Eli. SciPy and NumPy. Sebastopol: O’Reilly Media, Inc., 2013. 56 p. -DAWSON, Michael. Python Programming, for the absolute beginner. 3ed. Boston: Course Technology, 2010. 455 p. -HACKELING G. Mastering Machine Learning with scikit-learn. Birmingham: Packt Publishing Ltd., 2014. 221 p. -HETLAND, Magnus Lie. Python Algorithms. Mastering Basic Algorithms in the Python Language. Nova York: Springer Science+Business Media LLC, 2010. 316 p. -IDRIS, Ivan. NumPy 1.5. An action-packed guide dor the easy-to-use, high performance, Python based free open source NumPy mathematical library using real-world examples. Beginner’s Guide. Birmingham: Packt Publishing Ltd., 2011. 212 p. -LUTZ, Mark. Programming Python. 4ed. Sebastopol: O’Reilly Media, Inc., 2010. 1584 p. -MODEL, Mitchell L. Bioinformatics Programming Using Python. Sebastopol: O’Reilly Media, Inc., 2011. 1584 p. -TOSI, Sandro. Matplotlib for Python Developers. Birmingham: Packt Publishing Ltd., 2009. 293 p. Última atualização: 25 de novembro de 2016. 87