[{"data":1,"prerenderedAt":1955},["ShallowReactive",2],{"lang-switch-post-\u002Fplaylists\u002Fpattern-recognition\u002Flinear-regression-estimator":3,"post-pt-pattern-recognition-linear-regression-estimator":4},"\u002Fen\u002Fplaylists\u002Fpattern-recognition\u002Flinear-regression-estimator",{"id":5,"title":6,"body":7,"cover":1940,"date":1941,"description":1942,"extension":1943,"meta":1944,"navigation":240,"order":45,"path":1945,"playlist":1946,"seo":1947,"status":1948,"stem":1949,"tags":1950,"__hash__":1954},"posts\u002Fpt\u002Fplaylists\u002Fpattern-recognition\u002Flinear-regression-estimator.md","Regressão Linear na Unha: Construindo um Estimador do Zero",{"type":8,"value":9,"toc":1929},"minimark",[10,14,19,32,67,78,82,212,221,253,268,285,289,297,327,373,382,391,851,854,1092,1101,1105,1120,1140,1148,1156,1181,1368,1375,1379,1390,1434,1479,1486,1529,1535,1567,1575,1582,1586,1589,1682,1707,1710,1719,1742,1745,1759,1771,1775,1782,1797,1808,1811,1815,1865,1881,1885,1888,1908,1915,1922,1925],[11,12,13],"p",{},"Aula 1 da matéria do Dr. Boldt. O notebook dele quase não tem célula de markdown, é ele codando direto, então boa parte do trabalho deste post é meu: recontar o \"por quê\" de cada bloco de código, com o Bishop do lado como referência. Bora.",[15,16,18],"h2",{"id":17},"o-dataset-442-pacientes-de-verdade","O dataset: 442 pacientes de verdade",[11,20,21,22,26,27,31],{},"Diferente da playlist da especialização do Andrew Ng, aqui o dataset já vem embutido no próprio scikit-learn: o ",[23,24,25],"code",{},"load_diabetes",", com ",[28,29,30],"strong",{},"442 pacientes"," reais, 10 variáveis de entrada (idade, sexo, índice de massa corporal, pressão arterial média e seis medidas de sangue) e um alvo, uma medida numérica de quanto a diabetes progrediu depois de um ano.",[33,34,39],"pre",{"className":35,"code":36,"language":37,"meta":38,"style":38},"language-python shiki shiki-themes github-light github-dark","from sklearn.datasets import load_diabetes\ndata = load_diabetes()\nX = data.data   # (442, 10)\ny = data.target # (442,)\n","python","",[23,40,41,49,55,61],{"__ignoreMap":38},[42,43,46],"span",{"class":44,"line":45},"line",1,[42,47,48],{},"from sklearn.datasets import load_diabetes\n",[42,50,52],{"class":44,"line":51},2,[42,53,54],{},"data = load_diabetes()\n",[42,56,58],{"class":44,"line":57},3,[42,59,60],{},"X = data.data   # (442, 10)\n",[42,62,64],{"class":44,"line":63},4,[42,65,66],{},"y = data.target # (442,)\n",[11,68,69,70,73,74,77],{},"Um detalhe que pega muita gente desprevenida: as 10 colunas de ",[23,71,72],{},"X"," ",[28,75,76],{},"não"," estão nas unidades originais. O scikit-learn já entrega esse dataset com cada coluna centralizada em zero e reescalada. Por isso o índice de massa corporal (a coluna que eu vou usar o post inteiro) varia entre -0.09 e 0.17 em vez de ficar na faixa normal de 15 a 40. Guarda essa informação, ela explica por que os coeficientes que vão aparecer mais pra frente parecem números gigantes: eles estão compensando uma variável de entrada minúscula.",[15,79,81],{"id":80},"o-modelo-mais-simples-possível","O modelo mais simples possível",[11,83,84],{},[42,85,88,130],{"className":86},[87],"katex",[42,89,92],{"className":90},[91],"katex-mathml",[93,94,96],"math",{"xmlns":95},"http:\u002F\u002Fwww.w3.org\u002F1998\u002FMath\u002FMathML",[97,98,99,125],"semantics",{},[100,101,102,106,110,113,116,119,122],"mrow",{},[103,104,105],"mi",{},"y",[107,108,109],"mo",{},"=",[103,111,112],{},"a",[107,114,115],{},"⋅",[103,117,118],{},"x",[107,120,121],{},"+",[103,123,124],{},"b",[126,127,129],"annotation",{"encoding":128},"application\u002Fx-tex","y = a \\cdot x + b",[42,131,135,162,183,202],{"className":132,"ariaHidden":134},[133],"katex-html","true",[42,136,139,144,150,155,159],{"className":137},[138],"base",[42,140],{"className":141,"style":143},[142],"strut","height:0.625em;vertical-align:-0.1944em;",[42,145,105],{"className":146,"style":149},[147,148],"mord","mathnormal","margin-right:0.0359em;",[42,151],{"className":152,"style":154},[153],"mspace","margin-right:0.2778em;",[42,156,109],{"className":157},[158],"mrel",[42,160],{"className":161,"style":154},[153],[42,163,165,169,172,176,180],{"className":164},[138],[42,166],{"className":167,"style":168},[142],"height:0.4445em;",[42,170,112],{"className":171},[147,148],[42,173],{"className":174,"style":175},[153],"margin-right:0.2222em;",[42,177,115],{"className":178},[179],"mbin",[42,181],{"className":182,"style":175},[153],[42,184,186,190,193,196,199],{"className":185},[138],[42,187],{"className":188,"style":189},[142],"height:0.6667em;vertical-align:-0.0833em;",[42,191,118],{"className":192},[147,148],[42,194],{"className":195,"style":175},[153],[42,197,121],{"className":198},[179],[42,200],{"className":201,"style":175},[153],[42,203,205,209],{"className":204},[138],[42,206],{"className":207,"style":208},[142],"height:0.6944em;",[42,210,124],{"className":211},[147,148],[11,213,214,215,217,218,220],{},"A mesma cara de sempre: uma reta, onde ",[23,216,112],{}," é a inclinação (o quanto o alvo muda pra cada unidade de índice de massa corporal) e ",[23,219,124],{}," é o intercepto. O professor testa dois chutes na mão, sem otimizar nada ainda, só pra ver a cara da reta:",[33,222,224],{"className":35,"code":223,"language":37,"meta":38,"style":38},"def modelo_linear(X, a, b):\n    return a*X + b\n\nypred = modelo_linear(X2, 1000, 100)  # primeiro chute\nypred = modelo_linear(X2, 1500, 150)  # segundo chute\n",[23,225,226,231,236,242,247],{"__ignoreMap":38},[42,227,228],{"class":44,"line":45},[42,229,230],{},"def modelo_linear(X, a, b):\n",[42,232,233],{"class":44,"line":51},[42,234,235],{},"    return a*X + b\n",[42,237,238],{"class":44,"line":57},[42,239,241],{"emptyLinePlaceholder":240},true,"\n",[42,243,244],{"class":44,"line":63},[42,245,246],{},"ypred = modelo_linear(X2, 1000, 100)  # primeiro chute\n",[42,248,250],{"class":44,"line":249},5,[42,251,252],{},"ypred = modelo_linear(X2, 1500, 150)  # segundo chute\n",[11,254,255,256,259,260,262,263,259,265,267],{},"Mexe nos sliders abaixo (aqui no blog eu uso a notação padrão ",[23,257,258],{},"w","\u002F",[23,261,124],{},", é exatamente o mesmo ",[23,264,112],{},[23,266,124],{}," do professor) numa amostra real de 45 pacientes do conjunto de treino e vê você mesmo qual reta cai melhor em cima dos pontos:",[269,270],"model-playground",{":b-max":271,":b-min":272,":b-step":273,":initial-b":274,":initial-w":275,":w-max":276,":w-min":272,":w-step":277,":x-train":278,":y-train":279,"dataLabel":280,"error-label":281,"prediction-label":282,"x-label":283,"y-label":284},"300","0","5","100","1000","1600","20","[-0.0062, -0.0903, 0.0714, 0.0445, 0.0143, -0.0698, -0.0849, -0.0461, -0.0655, -0.0213, -0.0041, 0.0358, 0.0692, 0.0207, -0.0504, 0.024, -0.0094, 0.1102, 0.0477, 0.0143, -0.0256, -0.0385, 0.08, -0.0041, 0.0412, -0.0418, 0.093, 0.01, 0.0606, 0.0391, 0.0595, 0.0164, -0.0105, 0.0067, 0.0013, -0.0299, -0.0235, -0.072, -0.0084, 0.1609, -0.0224, 0.0595, -0.0073, -0.0105, 0.0067]","[219, 94, 295, 129, 90, 48, 90, 72, 214, 281, 68, 184, 277, 197, 189, 121, 257, 258, 317, 191, 252, 127, 257, 198, 198, 103, 128, 150, 245, 246, 178, 268, 168, 109, 229, 118, 71, 77, 81, 346, 84, 85, 52, 25, 67]","Paciente","Erro total (soma dos erros absolutos)","Modelo","IMC (normalizado)","progressão da diabetes",[15,286,288],{"id":287},"como-saber-se-um-chute-é-bom","Como saber se um chute é bom",[11,290,291,292,296],{},"\"Cai melhor\" precisa virar número. O professor implementa três métricas na unha, a mesma trinca que já apareceu ",[112,293,295],{"href":294},"\u002Fplaylists\u002Fmachine-learning-specialization\u002Fw2-lab05-scikit-learn","na playlist da especialização"," (se você já leu aquela, pode passar os olhos rápido):",[298,299,300,311,321],"ul",{},[301,302,303,306,307,310],"li",{},[28,304,305],{},"MAE"," (erro absoluto médio): a média de ",[23,308,309],{},"|previsto - real|",". Fácil de interpretar (tá em unidade de paciente), mas trata todo erro do mesmo jeito.",[301,312,313,316,317,320],{},[28,314,315],{},"MSE"," (erro quadrático médio): a média de ",[23,318,319],{},"(previsto - real)²",". Eleva ao quadrado, então um erro grande pesa desproporcionalmente mais que vários erros pequenos.",[301,322,323,326],{},[28,324,325],{},"RMSE",": a raiz do MSE, pra voltar pra unidade original depois de ter quadrado tudo.",[33,328,330],{"className":35,"code":329,"language":37,"meta":38,"style":38},"def mae(y, ypred):\n    return np.sum(np.abs(y - ypred)) \u002F len(y)\n\ndef mse(y, ypred):\n    return np.sum((y - ypred)**2) \u002F len(y)\n\ndef rmse(y, ypred):\n    return np.sqrt(mse(y, ypred))\n",[23,331,332,337,342,346,351,356,361,367],{"__ignoreMap":38},[42,333,334],{"class":44,"line":45},[42,335,336],{},"def mae(y, ypred):\n",[42,338,339],{"class":44,"line":51},[42,340,341],{},"    return np.sum(np.abs(y - ypred)) \u002F len(y)\n",[42,343,344],{"class":44,"line":57},[42,345,241],{"emptyLinePlaceholder":240},[42,347,348],{"class":44,"line":63},[42,349,350],{},"def mse(y, ypred):\n",[42,352,353],{"class":44,"line":249},[42,354,355],{},"    return np.sum((y - ypred)**2) \u002F len(y)\n",[42,357,359],{"class":44,"line":358},6,[42,360,241],{"emptyLinePlaceholder":240},[42,362,364],{"class":44,"line":363},7,[42,365,366],{},"def rmse(y, ypred):\n",[42,368,370],{"class":44,"line":369},8,[42,371,372],{},"    return np.sqrt(mse(y, ypred))\n",[374,375,376],"blockquote",{},[11,377,378,381],{},[28,379,380],{},"Saída no dataset inteiro (442 pacientes):"," chute (1000, 100) → MAE 64.93, MSE 6614.14, RMSE 81.33. Chute (1500, 150) → MAE 53.93, MSE 4580.80, RMSE 67.68. O segundo chute é melhor nas três métricas.",[11,383,384,385,390],{},"O Bishop chama isso de ",[386,387,389],"glossary-term",{"definition":388},"a conta que resume, num número só, o quão longe o modelo está dos dados de treino","função de erro",", e define ela quase igual ao MSE, só que sem dividir pela quantidade de pontos e com um fator 1\u002F2 de bônus:",[11,392,393],{},[42,394,396,490],{"className":395},[87],[42,397,399],{"className":398},[91],[93,400,401],{"xmlns":95},[97,402,403,487],{},[100,404,405,408,412,415,418,420,430,448,451,453,455,462,465,467,469,472,479],{},[103,406,407],{},"E",[107,409,411],{"stretchy":410},"false","(",[103,413,258],{"mathvariant":414},"bold",[107,416,417],{"stretchy":410},")",[107,419,109],{},[421,422,423,427],"mfrac",{},[424,425,426],"mn",{},"1",[424,428,429],{},"2",[431,432,433,436,445],"msubsup",{},[107,434,435],{},"∑",[100,437,438,441,443],{},[103,439,440],{},"n",[107,442,109],{},[424,444,426],{},[103,446,447],{},"N",[107,449,450],{"stretchy":410},"{",[103,452,105],{},[107,454,411],{"stretchy":410},[456,457,458,460],"msub",{},[103,459,118],{},[103,461,440],{},[107,463,464],{"separator":134},",",[103,466,258],{"mathvariant":414},[107,468,417],{"stretchy":410},[107,470,471],{},"−",[456,473,474,477],{},[103,475,476],{},"t",[103,478,440],{},[480,481,482,485],"msup",{},[107,483,484],{"stretchy":410},"}",[424,486,429],{},[126,488,489],{"encoding":128},"E(\\mathbf{w}) = \\frac{1}{2}\\sum_{n=1}^{N}\\{y(x_n,\\mathbf{w}) - t_n\\}^2",[42,491,493,526,773],{"className":492,"ariaHidden":134},[133],[42,494,496,500,504,508,513,517,520,523],{"className":495},[138],[42,497],{"className":498,"style":499},[142],"height:1em;vertical-align:-0.25em;",[42,501,407],{"className":502,"style":503},[147,148],"margin-right:0.0576em;",[42,505,411],{"className":506},[507],"mopen",[42,509,258],{"className":510,"style":512},[147,511],"mathbf","margin-right:0.016em;",[42,514,417],{"className":515},[516],"mclose",[42,518],{"className":519,"style":154},[153],[42,521,109],{"className":522},[158],[42,524],{"className":525,"style":154},[153],[42,527,529,533,621,625,699,702,705,708,751,755,758,761,764,767,770],{"className":528},[138],[42,530],{"className":531,"style":532},[142],"height:1.3262em;vertical-align:-0.345em;",[42,534,536,540,618],{"className":535},[147],[42,537],{"className":538},[507,539],"nulldelimiter",[42,541,543],{"className":542},[421],[42,544,548,609],{"className":545},[546,547],"vlist-t","vlist-t2",[42,549,552,604],{"className":550},[551],"vlist-r",[42,553,557,578,589],{"className":554,"style":556},[555],"vlist","height:0.8451em;",[42,558,560,565],{"style":559},"top:-2.655em;",[42,561],{"className":562,"style":564},[563],"pstrut","height:3em;",[42,566,572],{"className":567},[568,569,570,571],"sizing","reset-size6","size3","mtight",[42,573,575],{"className":574},[147,571],[42,576,429],{"className":577},[147,571],[42,579,581,584],{"style":580},"top:-3.23em;",[42,582],{"className":583,"style":564},[563],[42,585],{"className":586,"style":588},[587],"frac-line","border-bottom-width:0.04em;",[42,590,592,595],{"style":591},"top:-3.394em;",[42,593],{"className":594,"style":564},[563],[42,596,598],{"className":597},[568,569,570,571],[42,599,601],{"className":600},[147,571],[42,602,426],{"className":603},[147,571],[42,605,608],{"className":606},[607],"vlist-s","​",[42,610,612],{"className":611},[551],[42,613,616],{"className":614,"style":615},[555],"height:0.345em;",[42,617],{},[42,619],{"className":620},[516,539],[42,622],{"className":623,"style":624},[153],"margin-right:0.1667em;",[42,626,629,635],{"className":627},[628],"mop",[42,630,435],{"className":631,"style":634},[628,632,633],"op-symbol","small-op","position:relative;top:0em;",[42,636,639],{"className":637},[638],"msupsub",[42,640,642,690],{"className":641},[546,547],[42,643,645,687],{"className":644},[551],[42,646,649,671],{"className":647,"style":648},[555],"height:0.9812em;",[42,650,652,656],{"style":651},"top:-2.4003em;margin-left:0em;margin-right:0.05em;",[42,653],{"className":654,"style":655},[563],"height:2.7em;",[42,657,659],{"className":658},[568,569,570,571],[42,660,662,665,668],{"className":661},[147,571],[42,663,440],{"className":664},[147,148,571],[42,666,109],{"className":667},[158,571],[42,669,426],{"className":670},[147,571],[42,672,674,677],{"style":673},"top:-3.2029em;margin-right:0.05em;",[42,675],{"className":676,"style":655},[563],[42,678,680],{"className":679},[568,569,570,571],[42,681,683],{"className":682},[147,571],[42,684,447],{"className":685,"style":686},[147,148,571],"margin-right:0.109em;",[42,688,608],{"className":689},[607],[42,691,693],{"className":692},[551],[42,694,697],{"className":695,"style":696},[555],"height:0.2997em;",[42,698],{},[42,700,450],{"className":701},[507],[42,703,105],{"className":704,"style":149},[147,148],[42,706,411],{"className":707},[507],[42,709,711,714],{"className":710},[147],[42,712,118],{"className":713},[147,148],[42,715,717],{"className":716},[638],[42,718,720,742],{"className":719},[546,547],[42,721,723,739],{"className":722},[551],[42,724,727],{"className":725,"style":726},[555],"height:0.1514em;",[42,728,730,733],{"style":729},"top:-2.55em;margin-left:0em;margin-right:0.05em;",[42,731],{"className":732,"style":655},[563],[42,734,736],{"className":735},[568,569,570,571],[42,737,440],{"className":738},[147,148,571],[42,740,608],{"className":741},[607],[42,743,745],{"className":744},[551],[42,746,749],{"className":747,"style":748},[555],"height:0.15em;",[42,750],{},[42,752,464],{"className":753},[754],"mpunct",[42,756],{"className":757,"style":624},[153],[42,759,258],{"className":760,"style":512},[147,511],[42,762,417],{"className":763},[516],[42,765],{"className":766,"style":175},[153],[42,768,471],{"className":769},[179],[42,771],{"className":772,"style":175},[153],[42,774,776,780,820],{"className":775},[138],[42,777],{"className":778,"style":779},[142],"height:1.0641em;vertical-align:-0.25em;",[42,781,783,786],{"className":782},[147],[42,784,476],{"className":785},[147,148],[42,787,789],{"className":788},[638],[42,790,792,812],{"className":791},[546,547],[42,793,795,809],{"className":794},[551],[42,796,798],{"className":797,"style":726},[555],[42,799,800,803],{"style":729},[42,801],{"className":802,"style":655},[563],[42,804,806],{"className":805},[568,569,570,571],[42,807,440],{"className":808},[147,148,571],[42,810,608],{"className":811},[607],[42,813,815],{"className":814},[551],[42,816,818],{"className":817,"style":748},[555],[42,819],{},[42,821,823,826],{"className":822},[516],[42,824,484],{"className":825},[516],[42,827,829],{"className":828},[638],[42,830,832],{"className":831},[546],[42,833,835],{"className":834},[551],[42,836,839],{"className":837,"style":838},[555],"height:0.8141em;",[42,840,842,845],{"style":841},"top:-3.063em;margin-right:0.05em;",[42,843],{"className":844,"style":655},[563],[42,846,848],{"className":847},[568,569,570,571],[42,849,429],{"className":850},[147,571],[11,852,853],{},"O 1\u002F2 existe só por conveniência: quando você deriva essa função pra achar o mínimo, o quadrado desce multiplicando e cancela o 1\u002F2 exatamente. Detalhe estético, não muda pra onde o mínimo aponta. E a versão \"raiz\" que ele usa pra comparar datasets de tamanhos diferentes,",[11,855,856],{},[42,857,859,906],{"className":858},[87],[42,860,862],{"className":861},[91],[93,863,864],{"xmlns":95},[97,865,866,903],{},[100,867,868,876,878],{},[456,869,870,872],{},[103,871,407],{},[873,874,875],"mtext",{},"RMS",[107,877,109],{},[879,880,881],"msqrt",{},[100,882,883,885,887,889,896,898,901],{},[424,884,429],{},[103,886,407],{},[107,888,411],{"stretchy":410},[480,890,891,893],{},[103,892,258],{"mathvariant":414},[107,894,895],{},"∗",[107,897,417],{"stretchy":410},[103,899,259],{"mathvariant":900},"normal",[103,902,447],{},[126,904,905],{"encoding":128},"E_{\\text{RMS}} = \\sqrt{2E(\\mathbf{w}^*)\u002FN}",[42,907,909,974],{"className":908,"ariaHidden":134},[133],[42,910,912,916,965,968,971],{"className":911},[138],[42,913],{"className":914,"style":915},[142],"height:0.8333em;vertical-align:-0.15em;",[42,917,919,922],{"className":918},[147],[42,920,407],{"className":921,"style":503},[147,148],[42,923,925],{"className":924},[638],[42,926,928,957],{"className":927},[546,547],[42,929,931,954],{"className":930},[551],[42,932,935],{"className":933,"style":934},[555],"height:0.3283em;",[42,936,938,941],{"style":937},"top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;",[42,939],{"className":940,"style":655},[563],[42,942,944],{"className":943},[568,569,570,571],[42,945,947],{"className":946},[147,571],[42,948,951],{"className":949},[147,950,571],"text",[42,952,875],{"className":953},[147,571],[42,955,608],{"className":956},[607],[42,958,960],{"className":959},[551],[42,961,963],{"className":962,"style":748},[555],[42,964],{},[42,966],{"className":967,"style":154},[153],[42,969,109],{"className":970},[158],[42,972],{"className":973,"style":154},[153],[42,975,977,981],{"className":976},[138],[42,978],{"className":979,"style":980},[142],"height:1.24em;vertical-align:-0.305em;",[42,982,985],{"className":983},[147,984],"sqrt",[42,986,988,1083],{"className":987},[546,547],[42,989,991,1080],{"className":990},[551],[42,992,995,1057],{"className":993,"style":994},[555],"height:0.935em;",[42,996,1000,1004],{"className":997,"style":999},[998],"svg-align","top:-3.2em;",[42,1001],{"className":1002,"style":1003},[563],"height:3.2em;",[42,1005,1008,1011,1014,1017,1048,1051,1054],{"className":1006,"style":1007},[147],"padding-left:1em;",[42,1009,429],{"className":1010},[147],[42,1012,407],{"className":1013,"style":503},[147,148],[42,1015,411],{"className":1016},[507],[42,1018,1020,1023],{"className":1019},[147],[42,1021,258],{"className":1022,"style":512},[147,511],[42,1024,1026],{"className":1025},[638],[42,1027,1029],{"className":1028},[546],[42,1030,1032],{"className":1031},[551],[42,1033,1036],{"className":1034,"style":1035},[555],"height:0.6147em;",[42,1037,1039,1042],{"style":1038},"top:-2.989em;margin-right:0.05em;",[42,1040],{"className":1041,"style":655},[563],[42,1043,1045],{"className":1044},[568,569,570,571],[42,1046,895],{"className":1047},[179,571],[42,1049,417],{"className":1050},[516],[42,1052,259],{"className":1053},[147],[42,1055,447],{"className":1056,"style":686},[147,148],[42,1058,1060,1063],{"style":1059},"top:-2.895em;",[42,1061],{"className":1062,"style":1003},[563],[42,1064,1068],{"className":1065,"style":1067},[1066],"hide-tail","min-width:1.02em;height:1.28em;",[1069,1070,1076],"svg",{"xmlns":1071,"width":1072,"height":1073,"viewBox":1074,"preserveAspectRatio":1075},"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","400em","1.28em","0 0 400000 1296","xMinYMin slice",[1077,1078],"path",{"d":1079},"M263,681c0.7,0,18,39.7,52,119\nc34,79.3,68.167,158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120\nc340,-704.7,510.7,-1060.3,512,-1067\nl0 -0\nc4.7,-7.3,11,-11,19,-11\nH40000v40H1012.3\ns-271.3,567,-271.3,567c-38.7,80.7,-84,175,-136,283c-52,108,-89.167,185.3,-111.5,232\nc-22.3,46.7,-33.8,70.3,-34.5,71c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1\ns-109,-253,-109,-253c-72.7,-168,-109.3,-252,-110,-252c-10.7,8,-22,16.7,-34,26\nc-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26s76,-59,76,-59s76,-60,76,-60z\nM1001 80h400000v40h-400000z",[42,1081,608],{"className":1082},[607],[42,1084,1086],{"className":1085},[551],[42,1087,1090],{"className":1088,"style":1089},[555],"height:0.305em;",[42,1091],{},[11,1093,1094,1095,1097,1098,1100],{},"é a mesma RMSE que a gente acabou de calcular, com a mesma divisão por ",[23,1096,447],{}," escondida atrás do fator 2 (porque a função dele não divide por ",[23,1099,447],{},", só a nossa MSE já divide).",[15,1102,1104],{"id":1103},"o-modelo-idiota-que-vira-régua","O modelo idiota que vira régua",[11,1106,1107,1108,1111,1112,1115,1116,1119],{},"Antes de qualquer regressão de verdade, o segundo notebook (",[23,1109,1110],{},"aula02a",") faz uma coisa esperta: separa 20% dos dados pra teste (",[23,1113,1114],{},"train_test_split"," implementado na mão, ",[23,1117,1118],{},"random_state=42"," pra dar sempre o mesmo resultado) e define o modelo mais preguiçoso que existe, chutar sempre a média:",[33,1121,1123],{"className":35,"code":1122,"language":37,"meta":38,"style":38},"def modelo_media(y):\n    media = np.mean(y)\n    return np.ones_like(y) * media\n",[23,1124,1125,1130,1135],{"__ignoreMap":38},[42,1126,1127],{"class":44,"line":45},[42,1128,1129],{},"def modelo_media(y):\n",[42,1131,1132],{"class":44,"line":51},[42,1133,1134],{},"    media = np.mean(y)\n",[42,1136,1137],{"class":44,"line":57},[42,1138,1139],{},"    return np.ones_like(y) * media\n",[374,1141,1142],{},[11,1143,1144,1147],{},[28,1145,1146],{},"Saída (353 pacientes de treino):"," MSE do chute (1500, 150) = 4646.20. MSE do \"sempre a média\" = 5978.59.",[11,1149,1150,1151,1155],{},"Por que eu preciso disso? Porque um MSE de 4646 sozinho não diz nada, é só um número. Comparado com o baseline da média, ele fica menor, então o modelo tá aprendendo alguma coisa. Isso é literalmente a definição de ",[386,1152,1154],{"definition":1153},"fração da variância do alvo que o modelo explica, comparado a só chutar a média sempre, onde 1 é perfeito, 0 é igual a chutar a média, negativo é pior que chutar a média","R²",":",[33,1157,1159],{"className":35,"code":1158,"language":37,"meta":38,"style":38},"def r2_score(y, ypred):\n    ss_res = mse(y, ypred)\n    ss_tot = mse(y, modelo_media(y))\n    return 1 - (ss_res \u002F ss_tot)\n",[23,1160,1161,1166,1171,1176],{"__ignoreMap":38},[42,1162,1163],{"class":44,"line":45},[42,1164,1165],{},"def r2_score(y, ypred):\n",[42,1167,1168],{"class":44,"line":51},[42,1169,1170],{},"    ss_res = mse(y, ypred)\n",[42,1172,1173],{"class":44,"line":57},[42,1174,1175],{},"    ss_tot = mse(y, modelo_media(y))\n",[42,1177,1178],{"class":44,"line":63},[42,1179,1180],{},"    return 1 - (ss_res \u002F ss_tot)\n",[11,1182,1183],{},[42,1184,1186,1219],{"className":1185},[87],[42,1187,1189],{"className":1188},[91],[93,1190,1191],{"xmlns":95},[97,1192,1193,1216],{},[100,1194,1195,1202,1204,1206,1208],{},[480,1196,1197,1200],{},[103,1198,1199],{},"R",[424,1201,429],{},[107,1203,109],{},[424,1205,426],{},[107,1207,471],{},[421,1209,1210,1213],{},[873,1211,1212],{},"MSE do modelo",[873,1214,1215],{},"MSE do baseline",[126,1217,1218],{"encoding":128},"R^2 = 1 - \\frac{\\text{MSE do modelo}}{\\text{MSE do baseline}}",[42,1220,1222,1267,1286],{"className":1221,"ariaHidden":134},[133],[42,1223,1225,1228,1258,1261,1264],{"className":1224},[138],[42,1226],{"className":1227,"style":838},[142],[42,1229,1231,1235],{"className":1230},[147],[42,1232,1199],{"className":1233,"style":1234},[147,148],"margin-right:0.0077em;",[42,1236,1238],{"className":1237},[638],[42,1239,1241],{"className":1240},[546],[42,1242,1244],{"className":1243},[551],[42,1245,1247],{"className":1246,"style":838},[555],[42,1248,1249,1252],{"style":841},[42,1250],{"className":1251,"style":655},[563],[42,1253,1255],{"className":1254},[568,569,570,571],[42,1256,429],{"className":1257},[147,571],[42,1259],{"className":1260,"style":154},[153],[42,1262,109],{"className":1263},[158],[42,1265],{"className":1266,"style":154},[153],[42,1268,1270,1274,1277,1280,1283],{"className":1269},[138],[42,1271],{"className":1272,"style":1273},[142],"height:0.7278em;vertical-align:-0.0833em;",[42,1275,426],{"className":1276},[147],[42,1278],{"className":1279,"style":175},[153],[42,1281,471],{"className":1282},[179],[42,1284],{"className":1285,"style":175},[153],[42,1287,1289,1293],{"className":1288},[138],[42,1290],{"className":1291,"style":1292},[142],"height:1.2251em;vertical-align:-0.345em;",[42,1294,1296,1299,1365],{"className":1295},[147],[42,1297],{"className":1298},[507,539],[42,1300,1302],{"className":1301},[421],[42,1303,1305,1357],{"className":1304},[546,547],[42,1306,1308,1354],{"className":1307},[551],[42,1309,1312,1329,1337],{"className":1310,"style":1311},[555],"height:0.8801em;",[42,1313,1314,1317],{"style":559},[42,1315],{"className":1316,"style":564},[563],[42,1318,1320],{"className":1319},[568,569,570,571],[42,1321,1323],{"className":1322},[147,571],[42,1324,1326],{"className":1325},[147,950,571],[42,1327,1215],{"className":1328},[147,571],[42,1330,1331,1334],{"style":580},[42,1332],{"className":1333,"style":564},[563],[42,1335],{"className":1336,"style":588},[587],[42,1338,1339,1342],{"style":591},[42,1340],{"className":1341,"style":564},[563],[42,1343,1345],{"className":1344},[568,569,570,571],[42,1346,1348],{"className":1347},[147,571],[42,1349,1351],{"className":1350},[147,950,571],[42,1352,1212],{"className":1353},[147,571],[42,1355,608],{"className":1356},[607],[42,1358,1360],{"className":1359},[551],[42,1361,1363],{"className":1362,"style":615},[555],[42,1364],{},[42,1366],{"className":1367},[516,539],[11,1369,1370,1371,1374],{},"Com o chute (1500, 150): R² = 1 - 4646.20\u002F5978.59 = ",[28,1372,1373],{},"0.2229",". Só uma variável explicando 22% da variação já é um começo, considerando que a diabetes depende de um monte de coisa que não tá nem nessas 10 colunas. E o R² do próprio baseline, por definição, é sempre zero.",[15,1376,1378],{"id":1377},"a-api-do-scikit-learn-construída-por-dentro","A API do scikit-learn, construída por dentro",[11,1380,1381,1382,1385,1386,1389],{},"Aqui que a aula fica interessante de verdade. Em vez de só chamar ",[23,1383,1384],{},"LinearRegression()"," pronto, o professor ensina a ",[28,1387,1388],{},"construir um estimador que segue a mesma convenção"," do scikit-learn, herdando de duas classes-base:",[33,1391,1393],{"className":35,"code":1392,"language":37,"meta":38,"style":38},"from sklearn.base import BaseEstimator, RegressorMixin\n\nclass AverageRegressor(BaseEstimator, RegressorMixin):\n    def fit(self, X, y):\n        self.media_ = np.mean(y)\n        return self\n    def predict(self, X):\n        return np.ones(shape=(X.shape[0],)) * self.media_\n",[23,1394,1395,1400,1404,1409,1414,1419,1424,1429],{"__ignoreMap":38},[42,1396,1397],{"class":44,"line":45},[42,1398,1399],{},"from sklearn.base import BaseEstimator, RegressorMixin\n",[42,1401,1402],{"class":44,"line":51},[42,1403,241],{"emptyLinePlaceholder":240},[42,1405,1406],{"class":44,"line":57},[42,1407,1408],{},"class AverageRegressor(BaseEstimator, RegressorMixin):\n",[42,1410,1411],{"class":44,"line":63},[42,1412,1413],{},"    def fit(self, X, y):\n",[42,1415,1416],{"class":44,"line":249},[42,1417,1418],{},"        self.media_ = np.mean(y)\n",[42,1420,1421],{"class":44,"line":358},[42,1422,1423],{},"        return self\n",[42,1425,1426],{"class":44,"line":363},[42,1427,1428],{},"    def predict(self, X):\n",[42,1430,1431],{"class":44,"line":369},[42,1432,1433],{},"        return np.ones(shape=(X.shape[0],)) * self.media_\n",[11,1435,1436,1439,1440,1443,1444,1447,1448,1451,1452,1455,1456,1459,1460,1463,1464,1467,1468,1475,1476,1478],{},[23,1437,1438],{},"BaseEstimator"," dá de graça um monte de infraestrutura (comparação de parâmetros, clonagem, integração com ",[23,1441,1442],{},"Pipeline"," e ",[23,1445,1446],{},"GridSearchCV",", coisas que vão aparecer só lá na frente da matéria). ",[23,1449,1450],{},"RegressorMixin"," adiciona o método ",[23,1453,1454],{},".score()"," padrão. E repara na convenção do underscore: ",[23,1457,1458],{},"self.media_",", terminando em ",[23,1461,1462],{},"_",", marca \"isso foi ",[28,1465,1466],{},"aprendido"," dos dados\", diferente de um parâmetro configurado na mão. É o mesmo detalhe que eu já tinha visto de fora, ",[112,1469,1470,1471,1474],{"href":294},"usando ",[23,1472,1473],{},"SGDRegressor"," na outra playlist",", só que agora eu tô escrevendo o ",[23,1477,1462],{}," com a própria mão.",[11,1480,1481,1482,1485],{},"O próximo passo mostra algo sutil: um regressor com coeficientes ",[28,1483,1484],{},"fixos",", passados no construtor, sem aprender nada:",[33,1487,1489],{"className":35,"code":1488,"language":37,"meta":38,"style":38},"class LinearRegressor(BaseEstimator, RegressorMixin):\n    def __init__(self, a, b):\n        self.a_ = a\n        self.b_ = b\n    def fit(self, X, y):\n        return self  # não aprende nada, os coeficientes já vieram prontos\n    def predict(self, X):\n        return (self.a_*X + self.b_).reshape(X.shape[0],)\n",[23,1490,1491,1496,1501,1506,1511,1515,1520,1524],{"__ignoreMap":38},[42,1492,1493],{"class":44,"line":45},[42,1494,1495],{},"class LinearRegressor(BaseEstimator, RegressorMixin):\n",[42,1497,1498],{"class":44,"line":51},[42,1499,1500],{},"    def __init__(self, a, b):\n",[42,1502,1503],{"class":44,"line":57},[42,1504,1505],{},"        self.a_ = a\n",[42,1507,1508],{"class":44,"line":63},[42,1509,1510],{},"        self.b_ = b\n",[42,1512,1513],{"class":44,"line":249},[42,1514,1413],{},[42,1516,1517],{"class":44,"line":358},[42,1518,1519],{},"        return self  # não aprende nada, os coeficientes já vieram prontos\n",[42,1521,1522],{"class":44,"line":363},[42,1523,1428],{},[42,1525,1526],{"class":44,"line":369},[42,1527,1528],{},"        return (self.a_*X + self.b_).reshape(X.shape[0],)\n",[11,1530,1531,1532,1155],{},"E depois, a versão que ",[28,1533,1534],{},"inicializa aleatório",[33,1536,1538],{"className":35,"code":1537,"language":37,"meta":38,"style":38},"class LinearRegressor(BaseEstimator, RegressorMixin):\n    def fit(self, X, y):\n        self.a_ = np.random.rand()\n        self.b_ = np.random.rand()\n        return self\n    # ...\n",[23,1539,1540,1544,1548,1553,1558,1562],{"__ignoreMap":38},[42,1541,1542],{"class":44,"line":45},[42,1543,1495],{},[42,1545,1546],{"class":44,"line":51},[42,1547,1413],{},[42,1549,1550],{"class":44,"line":57},[42,1551,1552],{},"        self.a_ = np.random.rand()\n",[42,1554,1555],{"class":44,"line":63},[42,1556,1557],{},"        self.b_ = np.random.rand()\n",[42,1559,1560],{"class":44,"line":249},[42,1561,1423],{},[42,1563,1564],{"class":44,"line":358},[42,1565,1566],{},"    # ...\n",[374,1568,1569],{},[11,1570,1571,1574],{},[28,1572,1573],{},"Saída:"," MSE do chute (1500, 150) do professor = 4646.20. MSE do coeficiente aleatório = 29993.30.",[11,1576,1577,1578,1581],{},"Isso rende um R² de ",[28,1579,1580],{},"-4.02"," para o chute aleatório. Negativo: pior que simplesmente chutar a média toda vez. É a prova de que \"aprender\" não é mágica, é sair de um lugar ruim (aleatório) na direção de um lugar melhor, e um número aleatório sozinho não tem nenhum motivo pra ser bom.",[15,1583,1585],{"id":1584},"do-chute-aleatório-ao-gradiente","Do chute aleatório ao gradiente",[11,1587,1588],{},"A última versão da classe substitui \"aleatório e parado\" por \"aleatório e caminhando\":",[33,1590,1592],{"className":35,"code":1591,"language":37,"meta":38,"style":38},"class LinearRegressor(BaseEstimator, RegressorMixin):\n    def __init__(self, max_iter=1000, learning_rate=0.001):\n        self.max_iter = max_iter\n        self.learning_rate = learning_rate\n\n    def fit(self, X, y):\n        self.coefs_ = np.random.rand(X.shape[1])\n        self.intercept_ = np.random.rand()\n        for i in range(self.max_iter):\n            y_pred = self.predict(X)\n            error = y - y_pred\n            self.coefs_ += X.T @ error * self.learning_rate\n            self.intercept_ += error.sum() * self.learning_rate\n        return self\n\n    def predict(self, X):\n        return (X @ self.coefs_ + self.intercept_).reshape(X.shape[0],)\n",[23,1593,1594,1598,1603,1608,1613,1617,1621,1626,1631,1637,1643,1649,1655,1661,1666,1671,1676],{"__ignoreMap":38},[42,1595,1596],{"class":44,"line":45},[42,1597,1495],{},[42,1599,1600],{"class":44,"line":51},[42,1601,1602],{},"    def __init__(self, max_iter=1000, learning_rate=0.001):\n",[42,1604,1605],{"class":44,"line":57},[42,1606,1607],{},"        self.max_iter = max_iter\n",[42,1609,1610],{"class":44,"line":63},[42,1611,1612],{},"        self.learning_rate = learning_rate\n",[42,1614,1615],{"class":44,"line":249},[42,1616,241],{"emptyLinePlaceholder":240},[42,1618,1619],{"class":44,"line":358},[42,1620,1413],{},[42,1622,1623],{"class":44,"line":363},[42,1624,1625],{},"        self.coefs_ = np.random.rand(X.shape[1])\n",[42,1627,1628],{"class":44,"line":369},[42,1629,1630],{},"        self.intercept_ = np.random.rand()\n",[42,1632,1634],{"class":44,"line":1633},9,[42,1635,1636],{},"        for i in range(self.max_iter):\n",[42,1638,1640],{"class":44,"line":1639},10,[42,1641,1642],{},"            y_pred = self.predict(X)\n",[42,1644,1646],{"class":44,"line":1645},11,[42,1647,1648],{},"            error = y - y_pred\n",[42,1650,1652],{"class":44,"line":1651},12,[42,1653,1654],{},"            self.coefs_ += X.T @ error * self.learning_rate\n",[42,1656,1658],{"class":44,"line":1657},13,[42,1659,1660],{},"            self.intercept_ += error.sum() * self.learning_rate\n",[42,1662,1664],{"class":44,"line":1663},14,[42,1665,1423],{},[42,1667,1669],{"class":44,"line":1668},15,[42,1670,241],{"emptyLinePlaceholder":240},[42,1672,1674],{"class":44,"line":1673},16,[42,1675,1428],{},[42,1677,1679],{"class":44,"line":1678},17,[42,1680,1681],{},"        return (X @ self.coefs_ + self.intercept_).reshape(X.shape[0],)\n",[11,1683,1684,1685,1689,1690,1694,1695,1698,1699,1702,1703,1706],{},"Se você já passou pela ",[112,1686,1688],{"href":1687},"\u002Fplaylists\u002Fmachine-learning-specialization\u002Flab04-gradient-descent","playlist da especialização",", essa conta te é familiar: é o mesmo ",[386,1691,1693],{"definition":1692},"algoritmo que ajusta os parâmetros repetidamente, na direção que mais reduz o erro, até parar de melhorar","gradiente descendente"," batch de sempre, ",[23,1696,1697],{},"coeficiente += X.T @ erro * taxa",", só que sem dividir pela quantidade de exemplos (o que só empurra o efeito pra dentro da ",[23,1700,1701],{},"learning_rate",", um pouco menor compensa a falta da divisão). Esse formato específico, atualizar o peso proporcionalmente ao erro vezes a entrada, tem nome próprio na literatura: ",[28,1704,1705],{},"regra delta"," (ou regra de Widrow-Hoff), um dos algoritmos de aprendizado mais antigos que existem, décadas antes do termo \"gradiente descendente\" pegar.",[11,1708,1709],{},"Roda ao vivo abaixo, na mesma amostra de 45 pacientes, e repara como ele sai de longe e converge pra perto do ajuste ideal:",[1711,1712],"gradient-descent-simulator",{":alpha-presets":1713,":alpha-slider-max":1714,":alpha-slider-min":1715,":alpha-slider-step":1715,":b-range":1716,":initial-alpha":1717,":initial-b":272,":initial-w":272,":w-range":1718,":x-train":278,":y-train":279,"b-label":124,"w-label":112},"[0.01, 0.1, 0.5, 1, 1.5]","1.8","0.01","[-100, 300]","0.5","[0, 1000]",[11,1720,1721,1722,1725,1726,1729,1730,1732,1733,1735,1736,1738,1739,1741],{},"Nessa amostra de 45 pontos (menor que os 353 do treino inteiro, então o ajuste ideal aqui não é exatamente igual ao número que a aula reporta), com ",[23,1723,1724],{},"alpha=0.5"," clicando em \"Rodar 2000\" ele já pousa bem perto do fundo do vale. Testa também um ",[23,1727,1728],{},"alpha"," maior, tipo 1.5: o ",[23,1731,124],{}," começa a oscilar antes de convergir, porque a escala de ",[23,1734,112],{}," (multiplicado por um ",[23,1737,118],{}," minúsculo, entre -0.09 e 0.17) e a escala de ",[23,1740,124],{}," (que soma direto) são bem diferentes, o mesmo problema de escala que a normalização resolve, só que aqui apareceu escondido dentro do próprio dataset já normalizado.",[11,1743,1744],{},"No dataset de treino inteiro (353 pacientes), rodando essa mesma classe com uma única feature (o índice de massa corporal):",[374,1746,1747],{},[11,1748,1749,73,1751,1754,1755,1758],{},[28,1750,1573],{},[23,1752,1753],{},"coefs_ = [529.65]",", ",[23,1756,1757],{},"intercept_ = 154.82",", MSE = 4302.16.",[11,1760,1761,1762,1765,1766,1443,1768,1770],{},"Isso já bate o melhor chute manual (4646.20 → 4302.16) e rende R² = 1 - 4302.16\u002F5978.59 = ",[28,1763,1764],{},"0.2804",". Sem eu escolher ",[23,1767,112],{},[23,1769,124],{}," na mão, o gradiente achou um ajuste melhor sozinho.",[15,1772,1774],{"id":1773},"de-uma-variável-pra-dez","De uma variável pra dez",[11,1776,1777,1778,1781],{},"O dataset tem 10 colunas, e até agora eu só usei uma (o índice de massa corporal). A mesma classe, sem nenhuma mudança de código, aceita ",[23,1779,1780],{},"X_train"," inteiro:",[33,1783,1785],{"className":35,"code":1784,"language":37,"meta":38,"style":38},"regressor = LinearRegressor()\nregressor.fit(X_train, y_train)  # agora com as 10 colunas\n",[23,1786,1787,1792],{"__ignoreMap":38},[42,1788,1789],{"class":44,"line":45},[42,1790,1791],{},"regressor = LinearRegressor()\n",[42,1793,1794],{"class":44,"line":51},[42,1795,1796],{},"regressor.fit(X_train, y_train)  # agora com as 10 colunas\n",[374,1798,1799],{},[11,1800,1801,1803,1804,1807],{},[28,1802,1573],{}," MSE = 3027.12 (contra 4302.16 usando só uma variável). RMSE cai de 65.59 para 55.02. R² sobe de 0.2804 para ",[28,1805,1806],{},"0.4937",".",[11,1809,1810],{},"Quase o dobro de variância explicada, só por deixar o modelo enxergar as outras 9 variáveis (idade, sexo, pressão, as seis medidas de sangue) que ele simplesmente não tinha acesso antes. Ninguém mudou o algoritmo, só a quantidade de informação que ele recebeu.",[15,1812,1814],{"id":1813},"fechando","Fechando",[1816,1817,1818,1832],"table",{},[1819,1820,1821],"thead",{},[1822,1823,1824,1829],"tr",{},[1825,1826,1828],"th",{"align":1827},"left","O que eu já sabia",[1825,1830,1831],{"align":1827},"O que essa aula assentou",[1833,1834,1835,1849,1857],"tbody",{},[1822,1836,1837,1841],{},[1838,1839,1840],"td",{"align":1827},"Regressão linear é ajustar uma reta que minimiza o erro",[1838,1842,1843,1844,259,1846,1848],{"align":1827},"O ",[23,1845,1438],{},[23,1847,1450],{}," é o contrato que faz qualquer classe minha se comportar como um estimador de verdade do scikit-learn",[1822,1850,1851,1854],{},[1838,1852,1853],{"align":1827},"MAE, MSE, RMSE medem o quão errado o modelo está",[1838,1855,1856],{"align":1827},"Sem comparar com um baseline (tipo chutar a média), esses números não dizem nada sozinhos: R² resolve isso",[1822,1858,1859,1862],{},[1838,1860,1861],{"align":1827},"Gradiente descendente ajusta pesos na direção que reduz o erro",[1838,1863,1864],{"align":1827},"Esse ajuste tem nome próprio na literatura clássica (regra delta), e \"aprender\" nada mais é que sair de um chute ruim andando na direção certa",[11,1866,1867,1868,1876,1877,1880],{},"Duas coisas ficaram em aberto de propósito. Primeiro: resolver isso tudo iterando, passo a passo, funciona, mas regressão linear tem solução exata, fechada, numa única conta, e é isso que ",[112,1869,1871,1872,1875],{"href":1870},"\u002Fplaylists\u002Fpattern-recognition\u002Fnormal-equation","a próxima aula (",[23,1873,1874],{},"aula02b",", equação normal) resolve",". Segundo: eu não toquei nos outros modelos que a aula compara (",[23,1878,1879],{},"aula02c","), fica pro próximo post também.",[15,1882,1884],{"id":1883},"aplicação-prática","Aplicação Prática",[11,1886,1887],{},"Uso o mesmo dataset de diabetes que já apareceu o post inteiro, sem introduzir nada de novo: o objetivo aqui é só visualizar o quão bom ficou o ajuste de 10 variáveis que acabei de mostrar.",[33,1889,1891],{"className":35,"code":1890,"language":37,"meta":38,"style":38},"regressor = LinearRegressor(max_iter=1000, learning_rate=0.001)\nregressor.fit(X_train, y_train)\ny_pred = regressor.predict(X_train)\n",[23,1892,1893,1898,1903],{"__ignoreMap":38},[42,1894,1895],{"class":44,"line":45},[42,1896,1897],{},"regressor = LinearRegressor(max_iter=1000, learning_rate=0.001)\n",[42,1899,1900],{"class":44,"line":51},[42,1901,1902],{},"regressor.fit(X_train, y_train)\n",[42,1904,1905],{"class":44,"line":57},[42,1906,1907],{},"y_pred = regressor.predict(X_train)\n",[11,1909,1910,1911,1914],{},"Reproduzi essa mesma classe (com uma semente aleatória diferente, então os coeficientes batem só na segunda casa decimal com os do professor, o MSE final ficou em 3027.43, praticamente idêntico ao 3027.12 reportado na aula) pra extrair os pares de valor real contra valor previsto de 40 pacientes do treino. Cada ponto é um paciente: quanto mais perto da linha pontilhada (a previsão perfeita, ",[23,1912,1913],{},"previsto = real","), melhor o modelo acertou aquele caso.",[1916,1917],"predicted-vs-actual-scatter",{":actual":1918,":predicted":1919,"point-label":280,"x-label":1920,"y-label":1921},"[42, 51, 52, 59, 60, 67, 71, 72, 72, 77, 77, 78, 83, 89, 96, 102, 104, 144, 146, 150, 150, 150, 170, 171, 172, 174, 179, 190, 198, 212, 219, 262, 265, 275, 276, 281, 292, 308, 317, 341]","[143.2, 80.1, 78.4, 120.6, 140.3, 183.2, 95.9, 94.7, 92.1, 91.1, 174.5, 86.5, 138.4, 157.2, 132.4, 125.7, 94.1, 165.1, 157.4, 163.9, 111.3, 204.9, 172.6, 183.3, 140.6, 172.7, 175.6, 122.7, 192.1, 198.0, 160.9, 177.3, 185.5, 198.8, 143.2, 236.4, 209.2, 234.2, 230.8, 242.5]","progressão real da diabetes","progressão prevista",[11,1923,1924],{},"Dá pra ver a nuvem de pontos seguindo a diagonal, mas com bastante espalhamento, exatamente o que um R² de 0.49 significa na prática: o modelo capturou boa parte do padrão, mas ainda erra bastante caso a caso. Nada mau pra um modelo linear simples, sem nenhuma feature nova, sem regularização, só 10 números crus e 1000 passos de gradiente.",[1926,1927,1928],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":38,"searchDepth":51,"depth":51,"links":1930},[1931,1932,1933,1934,1935,1936,1937,1938,1939],{"id":17,"depth":51,"text":18},{"id":80,"depth":51,"text":81},{"id":287,"depth":51,"text":288},{"id":1103,"depth":51,"text":1104},{"id":1377,"depth":51,"text":1378},{"id":1584,"depth":51,"text":1585},{"id":1773,"depth":51,"text":1774},{"id":1813,"depth":51,"text":1814},{"id":1883,"depth":51,"text":1884},null,"2026-08-19","Primeira aula da matéria de Reconhecimento de Padrões: o professor pega um dataset real de diabetes, chuta coeficientes na mão, e constrói um estimador próprio seguindo a API do scikit-learn. Eu reconto o porquê de cada passo, com o Bishop do lado.","md",{},"\u002Fpt\u002Fplaylists\u002Fpattern-recognition\u002Flinear-regression-estimator","pattern-recognition",{"title":6,"description":1942},"published","pt\u002Fplaylists\u002Fpattern-recognition\u002Flinear-regression-estimator",[1951,1952,1953],"regressao-linear","scikit-learn","gradiente-descendente","hoaj3uts_Gr2n11tQErHx5mqUvvuDxuJfR_v79r23no",1787338982957]