[{"data":1,"prerenderedAt":826},["ShallowReactive",2],{"lang-switch-post-\u002Fplaylists\u002Fpattern-recognition\u002Ftitanic":3,"post-pt-pattern-recognition-titanic":4},"\u002Fen\u002Fplaylists\u002Fpattern-recognition\u002Ftitanic",{"id":5,"title":6,"body":7,"cover":811,"date":812,"description":813,"extension":814,"meta":815,"navigation":306,"order":339,"path":816,"playlist":817,"seo":818,"status":819,"stem":820,"tags":821,"__hash__":825},"posts\u002Fpt\u002Fplaylists\u002Fpattern-recognition\u002Ftitanic.md","O Titanic: Meu Primeiro Dado Sujo de Verdade",{"type":8,"value":9,"toc":801},"minimark",[10,14,19,49,91,100,115,119,134,150,164,184,197,201,237,257,269,273,292,349,364,419,426,459,466,472,530,534,549,556,569,584,591,594,598,605,612,629,636,643,647,692,696,699,724,790,797],[11,12,13],"p",{},"Aula 7, e o professor muda de regime: até aqui todo dataset já chegava pronto, sem buraco, sem coluna inútil, sem texto solto. O Titanic (o dataset mais famoso do Kaggle, provavelmente o primeiro projeto de todo mundo que começa em ciência de dados) não tem esse luxo.",[15,16,18],"h2",{"id":17},"o-dado-sujo-891-passageiros-nem-toda-coluna-serve","O dado sujo: 891 passageiros, nem toda coluna serve",[20,21,26],"pre",{"className":22,"code":23,"language":24,"meta":25,"style":25},"language-python shiki shiki-themes github-light github-dark","df = pd.read_csv('train.csv')\ny = df['Survived']\nX = df.drop('Survived', axis=1)\n","python","",[27,28,29,37,43],"code",{"__ignoreMap":25},[30,31,34],"span",{"class":32,"line":33},"line",1,[30,35,36],{},"df = pd.read_csv('train.csv')\n",[30,38,40],{"class":32,"line":39},2,[30,41,42],{},"y = df['Survived']\n",[30,44,46],{"class":32,"line":45},3,[30,47,48],{},"X = df.drop('Survived', axis=1)\n",[11,50,51,52,55,56,59,60,63,64,63,67,63,70,73,74,77,78,63,81,63,84,63,87,90],{},"891 passageiros, ",[27,53,54],{},"Survived"," (0 ou 1) como alvo, e um punhado de colunas de entrada bem misturadas: ",[27,57,58],{},"Pclass"," (classe do bilhete), ",[27,61,62],{},"Name",", ",[27,65,66],{},"Sex",[27,68,69],{},"Age",[27,71,72],{},"SibSp"," (irmãos\u002Fcônjuge a bordo), ",[27,75,76],{},"Parch"," (pais\u002Ffilhos a bordo), ",[27,79,80],{},"Ticket",[27,82,83],{},"Fare",[27,85,86],{},"Cabin",[27,88,89],{},"Embarked"," (porto de embarque). O professor descarta quatro delas de cara:",[20,92,94],{"className":22,"code":93,"language":24,"meta":25,"style":25},"caracteristicas_indesejadas = ['PassengerId', 'Name', 'Ticket', 'Cabin']\n",[27,95,96],{"__ignoreMap":25},[30,97,98],{"class":32,"line":33},[30,99,93],{},[11,101,102,105,106,108,109,111,112,114],{},[27,103,104],{},"PassengerId"," é só um número sequencial, não carrega informação nenhuma sobre a pessoa. ",[27,107,62],{}," e ",[27,110,80],{}," são texto livre, quase todo valor é único (891 nomes diferentes pra 891 passageiros), então um modelo não tem como generalizar nada a partir disso sem processar o texto primeiro (extrair título, tipo \"Mr.\"\u002F\"Mrs.\", seria um jeito válido, mas é trabalho extra que a aula não fez). ",[27,113,86],{}," falta em boa parte das linhas e também é bem específica demais.",[15,116,118],{"id":117},"dado-faltando-é-a-regra-não-a-exceção","Dado faltando é a regra, não a exceção",[20,120,122],{"className":22,"code":121,"language":24,"meta":25,"style":25},"for col in Xnum.columns:\n    print(f\"{col:>12} {Xnum[col].isnull().sum():2}\")\n",[27,123,124,129],{"__ignoreMap":25},[30,125,126],{"class":32,"line":33},[30,127,128],{},"for col in Xnum.columns:\n",[30,130,131],{"class":32,"line":39},[30,132,133],{},"    print(f\"{col:>12} {Xnum[col].isnull().sum():2}\")\n",[135,136,137],"blockquote",{},[11,138,139,143,144,146,147,149],{},[140,141,142],"strong",{},"Saída:"," ",[27,145,69],{}," falta em 177 dos 891 passageiros (quase 20%). ",[27,148,89],{}," falta em 2.",[11,151,152,153,156,157,159,160,163],{},"Isso nunca tinha acontecido nessa playlist até agora: todo dataset anterior já vinha completo. Aqui, quase 1 em cada 5 idades é ",[27,154,155],{},"NaN",". Descartar essas linhas jogaria fora 20% dos dados, e descartar a coluna ",[27,158,69],{}," inteira jogaria fora uma variável provavelmente importante (criança tinha prioridade no resgate). A solução do professor é ",[140,161,162],{},"imputação",": preencher o buraco com um valor estimado.",[20,165,167],{"className":22,"code":166,"language":24,"meta":25,"style":25},"from sklearn.impute import SimpleImputer\nimputer = SimpleImputer(strategy='median')\nXnumTratado = imputer.fit_transform(Xnum)\n",[27,168,169,174,179],{"__ignoreMap":25},[30,170,171],{"class":32,"line":33},[30,172,173],{},"from sklearn.impute import SimpleImputer\n",[30,175,176],{"class":32,"line":39},[30,177,178],{},"imputer = SimpleImputer(strategy='median')\n",[30,180,181],{"class":32,"line":45},[30,182,183],{},"XnumTratado = imputer.fit_transform(Xnum)\n",[11,185,186,187,189,190,192,193,196],{},"Pra variáveis numéricas, a mediana (não a média): a distribuição de idade e de tarifa (",[27,188,83],{},") tem gente bem fora da curva (bebê de meses, tarifas de primeira classe bem altas), e a mediana não se deixa puxar por esses extremos do jeito que a média se deixa. Pra variáveis categóricas (",[27,191,89],{},"), não existe \"mediana\" de porto, então a estratégia vira ",[27,194,195],{},"'most_frequent'",", o valor que mais aparece.",[15,198,200],{"id":199},"categoria-não-é-número-mesmo-quando-parece","Categoria não é número, mesmo quando parece",[11,202,203,108,205,207,208,211,212,63,215,211,218,211,221,224,225,228,229,232,233,236],{},[27,204,66],{},[27,206,89],{}," são texto (",[27,209,210],{},"\"male\"","\u002F",[27,213,214],{},"\"female\"",[27,216,217],{},"\"S\"",[27,219,220],{},"\"C\"",[27,222,223],{},"\"Q\"","). Um modelo só entende número, mas simplesmente numerar (",[27,226,227],{},"male=0, female=1",", ou ",[27,230,231],{},"S=0, C=1, Q=2",") inventaria uma ordem que não existe: por que \"Q\" seria \"maior\" que \"S\"? O jeito certo é o ",[140,234,235],{},"one-hot encoding",": cada categoria vira sua própria coluna binária.",[20,238,240],{"className":22,"code":239,"language":24,"meta":25,"style":25},"from sklearn.preprocessing import OneHotEncoder\nencoder = OneHotEncoder()\nXcatTratadoHot = encoder.fit_transform(XcatTratado)\n",[27,241,242,247,252],{"__ignoreMap":25},[30,243,244],{"class":32,"line":33},[30,245,246],{},"from sklearn.preprocessing import OneHotEncoder\n",[30,248,249],{"class":32,"line":39},[30,250,251],{},"encoder = OneHotEncoder()\n",[30,253,254],{"class":32,"line":45},[30,255,256],{},"XcatTratadoHot = encoder.fit_transform(XcatTratado)\n",[135,258,259],{},[11,260,261,263,264,63,266,268],{},[140,262,142],{}," as 2 colunas categóricas (",[27,265,66],{},[27,267,89],{},") viram 5 colunas binárias (2 pra sexo, já que uma sobra redundante com a outra, e 3 pra porto de embarque). Nenhuma delas tem uma ordem numérica implícita, só \"é\" ou \"não é\" aquela categoria.",[15,270,272],{"id":271},"meu-próprio-transformer-nem-tudo-é-classificador","Meu próprio Transformer: nem tudo é classificador",[11,274,275,276,279,280,283,284,287,288,291],{},"Até aqui, toda classe própria dessa playlist herdava de ",[27,277,278],{},"ClassifierMixin"," ou ",[27,281,282],{},"RegressorMixin",", porque sempre terminava em ",[27,285,286],{},".predict()",". Aqui o objetivo é diferente: só transformar o dado, sem prever nada. Pra isso existe o ",[27,289,290],{},"TransformerMixin",":",[20,293,295],{"className":22,"code":294,"language":24,"meta":25,"style":25},"from sklearn.base import BaseEstimator, TransformerMixin\n\nclass AtributosDesejados(BaseEstimator, TransformerMixin):\n    def __init__(self):\n        self.colunas_indesejadas = ['PassengerId', 'Name', 'Ticket', 'Cabin']\n    def fit(self, X, y=None):\n        return self\n    def transform(self, X, y=None):\n        return X.drop(self.colunas_indesejadas, axis=1)\n",[27,296,297,302,308,313,319,325,331,337,343],{"__ignoreMap":25},[30,298,299],{"class":32,"line":33},[30,300,301],{},"from sklearn.base import BaseEstimator, TransformerMixin\n",[30,303,304],{"class":32,"line":39},[30,305,307],{"emptyLinePlaceholder":306},true,"\n",[30,309,310],{"class":32,"line":45},[30,311,312],{},"class AtributosDesejados(BaseEstimator, TransformerMixin):\n",[30,314,316],{"class":32,"line":315},4,[30,317,318],{},"    def __init__(self):\n",[30,320,322],{"class":32,"line":321},5,[30,323,324],{},"        self.colunas_indesejadas = ['PassengerId', 'Name', 'Ticket', 'Cabin']\n",[30,326,328],{"class":32,"line":327},6,[30,329,330],{},"    def fit(self, X, y=None):\n",[30,332,334],{"class":32,"line":333},7,[30,335,336],{},"        return self\n",[30,338,340],{"class":32,"line":339},8,[30,341,342],{},"    def transform(self, X, y=None):\n",[30,344,346],{"class":32,"line":345},9,[30,347,348],{},"        return X.drop(self.colunas_indesejadas, axis=1)\n",[11,350,351,352,355,356,359,360,363],{},"Junto com ",[27,353,354],{},"AtributosNumericos"," (separa só as colunas numéricas) e ",[27,357,358],{},"AtributosCategoricos"," (separa só as categóricas), o professor monta dois ",[27,361,362],{},"Pipeline"," paralelos, um pra cada tipo de dado:",[20,365,367],{"className":22,"code":366,"language":24,"meta":25,"style":25},"pipenum = Pipeline([\n    ('atributos_numericos', AtributosNumericos()),\n    ('imputer', SimpleImputer(strategy='median')),\n    ('scaler', StandardScaler())\n])\npipecat = Pipeline([\n    ('atributos_categoricos', AtributosCategoricos()),\n    ('imputer', SimpleImputer(strategy='most_frequent')),\n    ('encoder', OneHotEncoder())\n])\n",[27,368,369,374,379,384,389,394,399,404,409,414],{"__ignoreMap":25},[30,370,371],{"class":32,"line":33},[30,372,373],{},"pipenum = Pipeline([\n",[30,375,376],{"class":32,"line":39},[30,377,378],{},"    ('atributos_numericos', AtributosNumericos()),\n",[30,380,381],{"class":32,"line":45},[30,382,383],{},"    ('imputer', SimpleImputer(strategy='median')),\n",[30,385,386],{"class":32,"line":315},[30,387,388],{},"    ('scaler', StandardScaler())\n",[30,390,391],{"class":32,"line":321},[30,392,393],{},"])\n",[30,395,396],{"class":32,"line":327},[30,397,398],{},"pipecat = Pipeline([\n",[30,400,401],{"class":32,"line":333},[30,402,403],{},"    ('atributos_categoricos', AtributosCategoricos()),\n",[30,405,406],{"class":32,"line":339},[30,407,408],{},"    ('imputer', SimpleImputer(strategy='most_frequent')),\n",[30,410,411],{"class":32,"line":345},[30,412,413],{},"    ('encoder', OneHotEncoder())\n",[30,415,417],{"class":32,"line":416},10,[30,418,393],{},[11,420,421,422,425],{},"E o ",[27,423,424],{},"FeatureUnion"," junta a saída dos dois num só conjunto de colunas, lado a lado:",[20,427,429],{"className":22,"code":428,"language":24,"meta":25,"style":25},"from sklearn.pipeline import FeatureUnion\n\nunecaracteristicas = FeatureUnion([\n    ('pipenum', pipenum),\n    ('pipecat', pipecat)\n])\n",[27,430,431,436,440,445,450,455],{"__ignoreMap":25},[30,432,433],{"class":32,"line":33},[30,434,435],{},"from sklearn.pipeline import FeatureUnion\n",[30,437,438],{"class":32,"line":39},[30,439,307],{"emptyLinePlaceholder":306},[30,441,442],{"class":32,"line":45},[30,443,444],{},"unecaracteristicas = FeatureUnion([\n",[30,446,447],{"class":32,"line":315},[30,448,449],{},"    ('pipenum', pipenum),\n",[30,451,452],{"class":32,"line":321},[30,453,454],{},"    ('pipecat', pipecat)\n",[30,456,457],{"class":32,"line":327},[30,458,393],{},[135,460,461],{},[11,462,463,465],{},[140,464,142],{}," as 7 colunas originais (depois de descartar as 4 inúteis) viram 10 colunas tratadas: 5 numéricas (já imputadas e normalizadas) mais 5 categóricas (já imputadas e viradas one-hot).",[11,467,468,469,291],{},"O pipeline final encadeia tudo, do dado cru até o classificador, numa única chamada de ",[27,470,471],{},".fit()",[20,473,475],{"className":22,"code":474,"language":24,"meta":25,"style":25},"preproc = Pipeline([\n    ('atributos_desejados', AtributosDesejados()),\n    ('unecaracteristicas', unecaracteristicas),\n    ('to_dense', DenseTransformer())\n])\n\nclf = Pipeline([\n    ('preproc', preproc),\n    ('classificador', RandomForestClassifier())\n])\nclf.fit(X, y)\n",[27,476,477,482,487,492,497,501,505,510,515,520,524],{"__ignoreMap":25},[30,478,479],{"class":32,"line":33},[30,480,481],{},"preproc = Pipeline([\n",[30,483,484],{"class":32,"line":39},[30,485,486],{},"    ('atributos_desejados', AtributosDesejados()),\n",[30,488,489],{"class":32,"line":45},[30,490,491],{},"    ('unecaracteristicas', unecaracteristicas),\n",[30,493,494],{"class":32,"line":315},[30,495,496],{},"    ('to_dense', DenseTransformer())\n",[30,498,499],{"class":32,"line":321},[30,500,393],{},[30,502,503],{"class":32,"line":327},[30,504,307],{"emptyLinePlaceholder":306},[30,506,507],{"class":32,"line":333},[30,508,509],{},"clf = Pipeline([\n",[30,511,512],{"class":32,"line":339},[30,513,514],{},"    ('preproc', preproc),\n",[30,516,517],{"class":32,"line":345},[30,518,519],{},"    ('classificador', RandomForestClassifier())\n",[30,521,522],{"class":32,"line":416},[30,523,393],{},[30,525,527],{"class":32,"line":526},11,[30,528,529],{},"clf.fit(X, y)\n",[15,531,533],{"id":532},"o-mesmo-erro-de-sempre-com-consequência-de-verdade","O mesmo erro de sempre, com consequência de verdade",[20,535,537],{"className":22,"code":536,"language":24,"meta":25,"style":25},"y_pred = clf.predict(X)\naccuracy_score(y, y_pred)\n",[27,538,539,544],{"__ignoreMap":25},[30,540,541],{"class":32,"line":33},[30,542,543],{},"y_pred = clf.predict(X)\n",[30,545,546],{"class":32,"line":39},[30,547,548],{},"accuracy_score(y, y_pred)\n",[135,550,551],{},[11,552,553,555],{},[140,554,142],{}," 0.9798. Quase 98% de acerto.",[11,557,558,559,564,565,568],{},"Se você ",[560,561,563],"a",{"href":562},"\u002Fplaylists\u002Fpattern-recognition\u002Fpipeline-cross-validation","já leu o post sobre validação cruzada"," dessa playlist, essa acurácia deveria acender um alerta: é medida no ",[140,566,567],{},"mesmo"," dado que treinou. A prova de que é decoreba, não aprendizado:",[20,570,572],{"className":22,"code":571,"language":24,"meta":25,"style":25},"from sklearn.model_selection import cross_val_score\nscores = cross_val_score(clf, X, y)\n",[27,573,574,579],{"__ignoreMap":25},[30,575,576],{"class":32,"line":33},[30,577,578],{},"from sklearn.model_selection import cross_val_score\n",[30,580,581],{"class":32,"line":39},[30,582,583],{},"scores = cross_val_score(clf, X, y)\n",[135,585,586],{},[11,587,588,590],{},[140,589,142],{}," 0.807 de média (0.765, 0.815, 0.854, 0.775, 0.826 nas 5 dobras).",[11,592,593],{},"Uma queda de quase 17 pontos percentuais entre \"acurácia no treino\" e \"acurácia honesta\". A Random Forest, sem limite de árvore nenhum, memoriza boa parte dos 891 passageiros individualmente, e o número de 98% não media capacidade de generalizar, media capacidade de decorar.",[15,595,597],{"id":596},"tentando-bater-o-80-stacking-e-uma-rede-neural","Tentando bater o 80%: stacking e uma rede neural",[11,599,600,601,604],{},"O professor tenta duas coisas pra melhorar o 0.807 honesto. Primeiro, ",[27,602,603],{},"StackingClassifier"," com 8 modelos bem diferentes entre si de uma vez (Random Forest, Extra Trees, uma rede neural, SGD, Ridge, KNN, Naive Bayes, regressão logística):",[135,606,607],{},[11,608,609,611],{},[140,610,142],{}," 0.824 de validação cruzada. Uma melhora real, ainda que pequena.",[11,613,614,615,618,619,623,624,628],{},"Depois, uma rede neural sozinha (",[27,616,617],{},"MLPClassifier",", sigla de ",[620,621,622],"em",{},"Multi-Layer Perceptron",", um Perceptron ",[560,625,627],{"href":626},"\u002Fplaylists\u002Fpattern-recognition\u002Fensembles","que eu já vi antes nessa playlist"," empilhado em várias camadas, o assunto de uma matéria própria que ainda não é o foco aqui):",[135,630,631],{},[11,632,633,635],{},[140,634,142],{}," 0.822 de validação cruzada, praticamente empatada com o stacking de 8 modelos.",[11,637,638,639,642],{},"Nenhum dos dois é um salto gigante sobre o 0.807 da floresta sozinha, mas os dois batem, de forma consistente, a versão mais simples. Diferente ",[560,640,641],{"href":626},"do post anterior"," (onde um modelo simples bateu todo ensemble tentado), aqui a complexidade extra realmente ajudou, um pouco. A lição de antes continua valendo: não dá pra saber qual vai ganhar sem medir os dois com a mesma régua.",[15,644,646],{"id":645},"fechando","Fechando",[648,649,650,664],"table",{},[651,652,653],"thead",{},[654,655,656,661],"tr",{},[657,658,660],"th",{"align":659},"left","O que eu já sabia",[657,662,663],{"align":659},"O que essa aula assentou",[665,666,667,676,684],"tbody",{},[654,668,669,673],{},[670,671,672],"td",{"align":659},"Todo dataset até aqui já vinha completo",[670,674,675],{"align":659},"Dado faltando é normal em dado real, e a solução (imputação) precisa de uma estratégia pensada, não só \"descartar a linha\"",[654,677,678,681],{},[670,679,680],{"align":659},"Categoria vira número de algum jeito",[670,682,683],{"align":659},"One-hot encoding evita inventar uma ordem que não existe entre categorias",[654,685,686,689],{},[670,687,688],{"align":659},"Validação cruzada é mais honesta que medir no treino",[670,690,691],{"align":659},"Mesmo alerta de sempre, mas dessa vez numa Random Forest real: 98% no treino contra 81% de verdade",[15,693,695],{"id":694},"aplicação-prática","Aplicação Prática",[11,697,698],{},"Reproduzi o pipeline inteiro com semente fixa (o notebook original não fixa nenhuma), pra ter um número estável e poder comparar as três abordagens sob o mesmo critério exato de validação cruzada.",[20,700,702],{"className":22,"code":701,"language":24,"meta":25,"style":25},"cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\nscores_rf = cross_val_score(clf_rf, X, y, cv=cv)\nscores_stacking = cross_val_score(clf_stacking, X, y, cv=cv)\nscores_mlp = cross_val_score(clf_mlp, X, y, cv=cv)\n",[27,703,704,709,714,719],{"__ignoreMap":25},[30,705,706],{"class":32,"line":33},[30,707,708],{},"cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\n",[30,710,711],{"class":32,"line":39},[30,712,713],{},"scores_rf = cross_val_score(clf_rf, X, y, cv=cv)\n",[30,715,716],{"class":32,"line":45},[30,717,718],{},"scores_stacking = cross_val_score(clf_stacking, X, y, cv=cv)\n",[30,720,721],{"class":32,"line":315},[30,722,723],{},"scores_mlp = cross_val_score(clf_mlp, X, y, cv=cv)\n",[648,725,726,743],{},[651,727,728],{},[654,729,730,733,737,740],{},[657,731,732],{"align":659},"Modelo",[657,734,736],{"align":735},"right","Acurácia (treino, decoreba)",[657,738,739],{"align":735},"Acurácia (validação cruzada)",[657,741,742],{"align":735},"Desvio padrão",[665,744,745,759,777],{},[654,746,747,750,753,756],{},[670,748,749],{"align":659},"Random Forest",[670,751,752],{"align":735},"0.9798",[670,754,755],{"align":735},"0.8092",[670,757,758],{"align":735},"0.0268",[654,760,761,764,767,772],{},[670,762,763],{"align":659},"Stacking (8 modelos)",[670,765,766],{"align":735},"(não medi)",[670,768,769],{"align":735},[140,770,771],{},"0.8283",[670,773,774],{"align":735},[140,775,776],{},"0.0077",[654,778,779,782,784,787],{},[670,780,781],{"align":659},"Rede neural (MLP)",[670,783,766],{"align":735},[670,785,786],{"align":735},"0.8182",[670,788,789],{"align":735},"0.0197",[11,791,792,793,796],{},"Os números batem de perto com os do notebook original (0.807, 0.824, 0.822), confirmando que a diferença entre os três não foi sorte de uma rodada específica. E repara no desvio padrão: o stacking não é só o que teve a melhor média, é também o mais ",[140,794,795],{},"estável"," de dobra pra dobra (0.0077 contra 0.0268 da floresta sozinha), sinal de que combinar vários modelos diferentes amorteceu parte da variação que cada um sozinho carrega.",[798,799,800],"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":25,"searchDepth":39,"depth":39,"links":802},[803,804,805,806,807,808,809,810],{"id":17,"depth":39,"text":18},{"id":117,"depth":39,"text":118},{"id":199,"depth":39,"text":200},{"id":271,"depth":39,"text":272},{"id":532,"depth":39,"text":533},{"id":596,"depth":39,"text":597},{"id":645,"depth":39,"text":646},{"id":694,"depth":39,"text":695},null,"2026-08-20","Aula 7: o professor monta um pipeline completo de pré-processamento em cima do dataset clássico do Titanic, dado faltando e tudo, e mostra o mesmo erro de medir no dado de treino que já vimos antes, só que dessa vez com consequência real.","md",{},"\u002Fpt\u002Fplaylists\u002Fpattern-recognition\u002Ftitanic","pattern-recognition",{"title":6,"description":813},"published","pt\u002Fplaylists\u002Fpattern-recognition\u002Ftitanic",[822,823,824],"dados-faltantes","one-hot-encoding","pipeline","719_Oxdjy5LSzenMUePhyEOi3IYw5ZxAq8hA0dD52WY",1787338983332]