Caret срещу tidymodels — създайте многократно използвани работни процеси за машинно обучение

Битка за HR анализ между двата пакета

Защо tidymodels?

Ако използвате модели за машинно обучение в R, вероятно използвате caret или tidymodels. Интересното е, че и двата пакета са разработени от един и същи автор, сред много други: Макс Кун. Но как се сравняват помежду си по отношение на осъществимост и ефективност?

Може да се чудите кой пакет трябва да научите за предсказуемо моделиране в R. Едно нещо точно напред: Caret е традиционният пакет за машинно обучение на R, докато tidymodels е доста непознат за части от R общността. Съответно, това беше ново за мен: интелигентен медиен потребител ми препоръча tidymodels, за да автоматизирам секцията за предварителна обработка на функции, която бях показал в последния си урок. Въпреки че бях малко скептичен, опитах го, за да разбера дали е по-добър от caret. Наскоро предизвиках себе си да предскажа оттеглянето на служителите на малък симулиран набор от данни с caret – перфектен случай да опитам това и с tidymodels. Това също е доста реалистичен пример, тъй като някои от големите играчи от индустрията вече прилагат прогнозни анализи, за да намалят отпадането и да увеличат задържането на своите ценни таланти. Използвайки техники за извличане на данни, историческите и етикетирани данни за служителите могат да се използват за откриване на характеристики, които са свързани с текучеството (последно увеличение на заплатата, служебно пътуване, съответствие между лицето и работата, разстояние от дома и т.н.). Следователно алгоритъмът се обучава с данни от миналото, за да предскаже бъдещето. Това също може да бъде сериозен проблем, защото позволява лесно дискриминационни пристрастия. По този начин, когато се прилага предсказуем модел, той трябва постоянно да се оценява, преди да е вече остарял и да направи дълбоки грешки. И все пак, ако ги използваме внимателно, аз съм убеден, че използването на анализ на данни може да бъде мощен инструмент за подобряване на работното място завинаги.

Първи стъпки с известния набор от данни за анализ на човешки ресурси на IBM

Тъй като потребителите леко се различават в начина си на използване на разнообразието от алгоритми за машинно обучение, налични в R, Макс Кун имаше за цел да разработи еднаква платформа за машинно обучение, която позволява последователен и репликируем код. В R общността добрият стар caret вече играе ролята на най-съвременния пакет за известно време, когато Макс Кун също разработи tidymodels през 2020 г. — така да се каже tidyverse версията на caret. Подобно на dplyr-синтаксиса (включително %›%, mutate() и т.н.), tidymodels се основава на идеята да структурирате вашия код в работни потоци, в които всяка стъпка е изрично дефинирана. Това е интуитивно и ви позволява последователно да следвате какво всъщност прави вашата програма. Много функции са заимствани от няколко основни пакета, които вече са включени в tidymodels, следователно може да се счита за мета-пакет:

  • рецепти: за предварителна обработка
  • пащърнак: за указване на модела
  • мерило: за оценка на модела
  • циферблати: за настройка на хиперпараметър
  • работен поток: за създаване на ML тръбопроводи
  • метла: за подреждане на резултатите от модела
  • Данните за обучение трябва да се използват, за да се поберат нашите модели и да се настроят нашите хиперпараметри, докато ние запазваме някои данни от тестване за нашата окончателна оценка на модела. Защо? Можем да се сблъскаме с проблема, за да съобразим твърде много нашия модел с нашите специфични за извадката данни, така че да не можем да го приложим към нови данни за служители по-късно. Проблем, който често се нарича пренастройване - феномен, който може да обясни защо понякога вече не можем да възпроизведем вече открити ефекти. За моделите на машинно обучение ние често разделяме нашите данни на набори за обучение и валидиране/тест, за да преодолеем този проблем. Учебният комплект се използва за обучение на модела. Наборът за валидиране служи за оценка на производителността на модела, за да се настроят съответно хиперпараметрите. И накрая, наборът от тестове се запазва, за да оспори точността на прогнозиране на данни, които моделът никога не е виждал преди. За tidymodels първото грубо разделяне може да се направи с помощта на initial_split(), което предоставя списък с индекси за разделяне, които са свързани с основния набор от данни. Ние използваме 70% от нашите данни за обучение и запазваме останалите 30% за тестване. Стратификацията се използва с целевата променлива. Това означава, че даваме възможност на всеки модел да бъде както обучен, така и тестван в една и съща част от класовете (напр. 16% да и 84% не). По подобен начин функцията createDataPartionining() на caret автоматично използва променливата за резултат, за да балансира разпределенията на класовете в разделянията. Като зададем list = FALSE, гарантираме, че функцията връща матрица вместо списък. По този начин можем да използваме произволно събраните индекси в нашия основен набор от данни, като използваме познатия синтаксис data.table. За да направим модела още по-обобщаем към нови данни, можем да използваме друг магически трик от нашия статистически инструментариум: кръстосано валидиране с различни разделяния. По-късно прилагаме нашия обучен кандидат модел(и) към допълнителен набор от наблюдения и многократно коригираме параметрите, за да намалим грешката при прогнозиране. Тези допълнителни наблюдения са няколко произволни извадки от данните за обучението, като всеки път пропускат някои от данните. Това прави множество сгъвания на данни за валидиране на хиперпараметрите. Повтаряме това 3 пъти и осредняваме производителността, за да получим предварителна оценка на производителността на нашия модел - техника за повторно вземане на проби, наречена 3-кратно кръстосано валидиране. vfold_cv() на Tidymodel върши работата вместо нас — ние определяме броя на гънките, които трябва да бъдат създадени, както и броя на повторенията, които трябва да се използват за повторна семплиране. Когато вместо това използваме каретка, можем да използваме функцията createFolds() за същата цел, но за нашето сравнение правим нещо по-добро: tidymodels включва функция, наречена rsample2caret(), която преобразува гънките, които вече сме направили в tidymodels, в познатия карет формат. Благодарение на командите rsample2caret()и caret2rsample() е лесно да използвате идентични повторни проби в пакета, който предпочитате. По този начин показателите за ефективност, които изчисляваме на нашите гънки с всяка от рамките, са по-малко предубедени и по-пряко сравними.

Тъй като tidymodels използва тези пакети, е по-лесно да научите, ако вече сте запознати с тях, но всъщност не е задължително.

Моля, обърнете внимание: Ако се интересувате само от частта за кодиране, можете да намерите пълни скриптове в моето хранилище на GitHub тук.

Разделяне на данни за обучение и тестване

Наборът от данни, който ще използваме за нашия казус, е симулиран набор от данни, създаден от IBM Watson Analytics, който може да бъде намерен на Kaggle. Той съдържа 1470 записа за служители и общи 38 функции (месечен доход, удовлетворение от работата, пол и т.н.) — една от които е нашата целева променлива (отпадане на служители) (ДА/НЕ). След като сме дефинирали R-проект, можем да използваме чистия тук-пакет, за да настроим нашите пътища по прост начин, който е по-устойчив на промени на вашата локална машина. Нека да разгледаме нашите необработени данни.

Отказ от отговорност: Всички графики са направени от автора, освен ако не е посочено друго.

Нито едно от наблюденията не липсва и обобщението, което функцията за преглед ни дава, показва някои описателни статистики, включително средна стойност, стандартно отклонение, процентили, както и хистограма на всяка от променливите (26 цифри; 9 знака). В реалния свят вероятно никога няма да имаме толкова чист и пълен набор от данни, но все пак имаме друг проблем, който е доста реалистичен: изглежда, че 237 служители (16%) са напуснали компанията, докато мнозинството (почти 84%) са останали, така че класовете не са еднакво балансирани. Дисбалансът на класа изисква специално отношение, тъй като е неудобно да се оптимизира и оценява производителността на модела с помощта на конвенционални показатели за производителност (точност, AUC ROC и др.). Причината за това е следната: Тъй като точността е съотношението на правилно класифицираните случаи от всички случаи, не би било голяма работа за алгоритъма да ни даде висок резултат, дори ако просто класифицира ВСИЧКИ случаи като мнозинствен клас ( напр. не) дори някои от тях действително принадлежат към малцинствената класа (напр. да). Но в нашия случай ние силно се интересуваме от положителните случаи, тъй като е по-пагубно да НЕ идентифицираме правилно, че даден служител ще напусне (напр. чувствителност или истински положителен процент), отколкото случайно да прогнозираме, че служител ще напусне, ако лицето действително остане (фалшиво положителен процент или 1 — специфичност). По този начин ще използваме F1-резултат като показател за точност за оптимизиране на обучението, тъй като той придава по-голямо значение на правилното класифициране на положителни случаи (напр. оттегляне на служители) и повишава производителността на модела в силно небалансирани набори от данни.

Като първа стъпка можем да изчислим всички допълнителни функции. плащане, което се възприема като несправедливо, може да повлияе на намерението на човек да напусне работа, за да потърси по-добро заплащане (Harden, Boakye & Ryan, 2018; Sarkar, 2018; Bryant & Allen, 2013). Ето защо бихме искали да създадем друга променлива, която представлява конкурентоспособността на плащането на месечния доход на всеки служител - причината зад това е, че служителите могат да сравняват доходите си с тези на колегите си, които споделят същото ниво на работа. Някой, който възприема заплащането си като справедливо, трябва да е по-малко вероятно да напусне компанията в сравнение с човек, който получава значително по-малко за подобна позиция. За да стигнем до там, ще използваме синтаксиса data.table, за да изчислим първо средното възнаграждение по ниво на работа и да съхраним подходящата стойност за всяко наблюдение. След това ще разделим месечния доход на всеки служител на средния доход, за да получим неговия или нейния коефициент на възнаграждение: мярка, която директно представлява плащането на лицето по отношение на това, което би се очаквало според нивото на работа. По този начин оценка 1 означава, че служителят точно отговаря на средното заплащане за тази позиция. Резултат от 1,2 означава, че на служителя се плаща с 20% над средното заплащане, а резултат от 0,8 означава, че лицето получава 20% по-малко от това, което би се очаквало при обичайното заплащане за ниво на работа. Като следваща стъпка премахваме всички променливи, които е много малко вероятно да имат някаква предсказваща сила. Например, Emploee-ID няма да обясни никаква значима вариация в текучеството на служителите, следователно трябва да бъде изтрито засега сред някои други променливи. Tidymodels ни предоставя възможността „да присвоим роли на променливи“, например такава колона с ID, за да запазим идентификатора, като същевременно го изключим от действителното моделиране по-късно. Но искаме да го направим ръчно тук, за да използваме същите данни за обучение за карета (в която не можем да присвоим роля). Други примери за променливи, които искаме да изключим, са тези, които очевидно са излишни и следователно могат да доведат до проблеми с мултиколинеарността (напр. почасова ставка и месечен доход). След това запазваме редуцирания набор от данни, като правилно преобразуваме всички низови променливи (напр. Отдел) във фактори едновременно.

Контролирайте стъпките за предварителна обработка

Сега използваме рецепти, за да подготвим нашите данни за моделиране с tidymodels: идеята е проста — създаваме обект, който съдържа всички стъпки за предварителна обработка, които служат като съставки за изпичане на добре подготвен набор от данни. По този начин нашите данни са готови да бъдат погълнати от модела. Тук трябва да се погрижим за реда на стъпките за предварителна обработка, тъй като те се изпълняват в реда, който са въвели (например, няма много смисъл да се нормализират числови предиктори, след като са създадени фиктивни променливи, тъй като 0 и 1 се третират като също числови стойности). Можете да мислите за рецепта като план, който скицира формулата на нашия модел, променливите кодировки и логиката на нашите стъпки за предварителна обработка преди действителното им изпълнение. Тази рецепта по-късно се включва в работен поток — структура, която може да се разглежда като един вид тръбопровод за анализ, който обединява вашите собствени предварително зададени инженерни стъпки на характеристиките със спецификацията на модела. За нашето проучване искаме да създадем фиктивни променливи, да премахнем променливи с почти до нулева дисперсия, както и тези, които вече са силно корелирани с подобна променлива за справяне с мултиколинеарността. Освен това, ние прилагаме произволно свръхсемплиране, за да се справим с класовия дисбаланс, заимстван от пакета «themis». Тъй като има значително повече отрицателни случаи, отколкото положителни случаи в нашия набор от данни, можем да предположим, че нашите модели няма да имат добър шанс да се научат как да идентифицират класа на малцинството. Алгоритъмът ROSE може да се справи с това чрез генериране на изкуствени допълнителни наблюдения с положителни резултати (напр. напускане на компанията), които имитират нашите истински позитиви. Така че класовете са по-добре балансирани. Ако се интересувате от това до каква степен дисбалансът на класа може да промени вашите показатели за ефективност, погледнете моето «GitHub repo» и стартирайте bal_log_example.Rкакто imbal_log_example.R.

Посочете моделите и настройте хиперпараметричната настройка

Caret се грижи за всички стъпки на проектиране на функции, докато тренира и дори автоматично обработва фиктивно кодиране, така че не е необходимо да указваме това в аргумента preProcess в нашето извикване train() по-късно. Недостатъкът на опцията preProcess на caret е, че няма опция за селективно трансформиране на специфични променливи (напр. определени числови променливи). За да използваме същата техника за повишаване на дискретизацията, както в нашия пример за tidymodels, трябва да използваме отделна функция върху данните за обучение, импортирани от ROSE пакета. Тук трябва да внимаваме — по някаква причина функцията разменя факторните нива на нашата целева променлива, което може да повлияе на показателите за ефективност по-късно. За да избегнем това, ние ръчно присвояваме факторните нива още веднъж по начин, че първото ниво е положителният клас.

За да създадем подходящите модели в tidymodels, първо използваме рецепта, която съдържа формула, както и логиката на нашите стъпки за предварителна обработка. Тази рецепта по-късно се включва в работен поток — структура, която може да се разглежда като един вид тръбопровод за анализ, който обединява вашите собствени предварително зададени инженерни стъпки на функции със спецификацията на модела. Пакетът parsnip ни помага да кажем на програмата кой конкретен модел да използва. Можете също така да свържете „двигател“ към спецификацията на модела, като извикате set_engine(), за да кажете на модела кой основен алгоритъм да използва (байесовците може би ще се радват да чуят, че можете да „дори използвате stan“). Като зададем хиперпараметрите на tune(), вече сме сигурни, че те са маркирани за настройка по-късно. Ако вече знаем коя настройка да използваме, защото е работила добре в миналото, можем също да я предадем директно към спецификацията на модела (напр. ако искаме да имаме 200 дървета). Тази стъпка не е необходима, ако използваме каретка, защото просто предаваме типа модел на аргумента на метода на нашата функция за влак. След това хиперпараметрите се настройват с „обхвата за настройка по подразбиране“ на каретката и обикновено дава много добри резултати. Да кажем, че се интересувате кой диапазон на настройка използва каретката за glmnet, можете да използвате getModelInfo(“glmnet")[[1]]$grid. Използвайки tidymodels, след това трябва да подготвим param обект, като използваме функцията parameters от parsnip. След това ги предаваме на функцията на мрежата по наш избор - тук съм приложил неправилна мрежа, за да намеря комбинации от параметри, близки до оптималните. За разлика от търсенето в решетка, за което ще преминем през всички възможни комбинации от параметри и ще оценим свързаната с тях производителност на модела, то може бързо да стане изчислително скъпо и неефективно, когато оптималното решение не е представено в мрежата. Използвайки неправилни мрежи, особено така наречените „дизайни за запълване на пространство“, шансовете са по-големи да намерим добра комбинация по-бързо, като същевременно покриваме цялото пространство на параметрите.

Комбинирайте няколко модела

Очевидно идеята за интегриране на множество модели в един обект не е нова за tidymodels! След като сме задали рецепта за предварителна обработка, както и спецификация на модела, ние създаваме работен поток, който обединява всички стъпки, които предварително сме дефинирали за подготовка и моделиране на данните, и ги поставяме в едно извикване. Но дори отиваме крачка по-далеч. Ние създаваме още по-богат обект, който съдържа множество работни потоци. Тези работни потоци (напр. рецепта, формула, модел) се кръстосват по начин, по който могат по-късно да бъдат монтирани и настроени в една заявка. В нашия случай пробваме няколко модела, xgboost и glmnet, но това може лесно да се разшири. Този набор от работни потоци вече е нашата основна структура за обучение на множество модели наведнъж. Като използваме option_add, ние предаваме нашите различни персонализирани мрежи в колоната с опции към нашия работен поток, за да променим диапазона на настройка по подразбиране. Можем да използваме кода на Github от parsnip, за да разберем кои параметри за настройка са налични и съответстват на параметрите, с които сме свикнали от каретката.

Сравнете производителността на модела

Преди да започнем да настройваме нашите подредени модели, ние запазваме набор от показатели за ефективност, които трябва да се използват за оценка на качеството на нашите модели. Сега ниеизползваме workflow_map за реално настройване на различни модели.

Проследяване на времето (по избор)

За да уточним нашата настройка на хиперпараметър в карета, ние обгръщаме всичко, включително всички стъпки на предварителна обработка, в trainControl-Object.

За съжаление, не е възможно да използваме F1 като наша метрика за оптимизация: следователно трябваше да напиша „персонализирана функция“, за да я накарам да работи.

За разлика от tidymodels, няма предварително определен начин за монтиране и настройка на различни модели наведнъж. По този начин можем да напишем наша собствена функция, която да свърши работата вместо нас: първо създаваме персонализирана функция, наречена train_model като обвивка за влака на caret, но с контейнер за метода. След това използваме lapply(), за да приложим нашата персонализирана функция към списък с методи. Те съдържат типовете модели, които искаме да сравним един с друг. Хубавото на този подход е, че можем лесно да адаптираме или разширим списъка по всяко време.

Както можем да видим в моделните обекти по-горе, имаме резултати от настройка за 108 комбинации от параметри за XGBoost и 9 за glmnet. Това е стойността по подразбиране, която беше избрана автоматично от каретката и причината, поради която преди това съм посочил същия размер на настройка за tidymodels, за да направя справедливо сравнение между двете. Нашите резултати от настройка от tidymodels имат подобна структура като вложената настройка на изхода от каретката, показана по-горе, с изключение на факта, че ни предоставят повече показатели за производителност. Просто се обадете на следното:

Докато експериментирах с двете рамки, разбрах, че процесът на настройка отнема много повече време в tidymodels в сравнение с caret. И двата пакета обработиха много кандидат-модели — 108 комбинации * 10 сгъвания * 3 повторения = 3240 итерации за XGBoost и 9 комбинации * 10 сгъвания * 3 повторения = 270 итерации за glmnet. Това така или иначе би трябвало да е много натоварващо процесора, но как пакетите се справят с тази задача? За да разбера, увих всяка тренировъчна команда в system.time(), за да сравня разликите във времето. Оказва се, че caret се нуждае само от част от времето, което tidymodels отделя за настройка, само около 2%за да бъдем точни. Докато изпълнението на командата workflow_map() на нашия tidymodel отне повече от 6 часа, caret изпълни същата задача за по-малко от 8 минути. Поне за моя малък експеримент tidymodels беше 48 пъти по-бавен от caret! Такава огромна разлика. Имайте предвид обаче, че това може отчасти да се дължи на старата ми машина и може леко да варира всеки път, когато проследявате часа. Ето защо силно ви препоръчвам да опитате пакета «microbenchmark» с двете функции: В случай че имате време да оцените функциите повече от веднъж, това трябва да ви даде по-точен и надежден резултат от system.time(). Въпреки това проблемът, че tidymodels изглежда много по-бавен от caret като цяло, не е нов: Макс Кун твърди, че рецептите забавят процеса на обучение, тъй като всички стъпки на предварителна обработка се „прилагат повторно във всяка повторна проба“. Друго възможно обяснение се свежда до „разликите в паралелните изчисления“ между tidymodels и caret.

Решете вашия печеливш модел

За да разберем кой метод работи най-добре при нашия проблем, трябва да измерим ефективността за всички тях. В нашия пример tidymodels сме запазили всички резултати от настройката от тренировъчните данни в model_race. Можем да използваме групиране по работния процес, за да събираме показатели по тип модел. Полученият тибъл ни предоставя няколко показателя за ефективност, които са изчислени за моделите, всеки от които опитва специфична конфигурация на хиперпараметър от нашата мрежа. В нашия случай той осигурява 10 сгъвания x 3 повторения = 30 резултата за показател за ефективност за всеки работен процес. Сега можем да изпълним autoplot на tidymodel, за да покажем класирана производителност на работния процес сред кандидат моделите.

Последното обратно броене: Изпълнение на нови проби

И така, какъв е нашият печеливш модел? Графиката показва, че сред всички показатели логистичната регресия (в синьо) превъзхожда XGBoost на всички кандидат-модели. За да сравним производителността на модела с каретка, използваме функцията resamples. Предоставя ни диапазон от F1 стойности във всичките 3 гънки, като ни дава оценка за това как моделът се представя на различни проби. Като визуализираме този изход с bwplot(resamples), можем да видим как производителността е разпределена между гънките и след това да изберем модела с най-висока средна производителност или най-ниска вариация в производителността. За разлика от tidymodels, ние не можем да видим производителността при тренировъчни гънки за всяка комбинация от параметри, но получаваме диапазона на производителност за най-добрия набор от хиперпараметри. Дори ако графиката предполага, че XGBoost дава малко по-добра производителност, по-късно ще направим прогнози с glmnet, за да направим валидно сравнение с логистичната регресия на tidymodels.

Изненадващо, caret като цяло осигурява много по-висок F1-резултат в сравнение с tidymodels, въпреки че «F1_Score function» от MLmetrics, както и «f_meas() function» от yardstick и двете изчисляват хармоничната средна стойност между припомняне и прецизност без добавяне на допълнителна тежест който и да е от показателите (балансиран F1-резултат). Следователно разликата в производителността е малко вероятна поради разлики в изчислението. В най-добрия случай разликата е резултат от по-целенасочен процес на оптимизация, тъй като caret обучи нашите модели, за да поддържа F1-резултата възможно най-висок.

Все още не сме приключили: за подредените модели трябва да се ангажираме с модел и след това да го финализираме по подходящ начин. В този случай ние извличаме всички glmnet кандидат модели от нашето сравнение на модели. Като стартираме select_best() върху резултатите от настройката на нашия работен поток за логистична регресия на tidymodels, ние получаваме показателите за ефективност за кандидат модела, който се класира най-високо в F1-резултата. За да продължим да се ангажираме с този модел, ние финализираме нашия печеливш работен процес: извличаме работния поток log_regот нашата надпревара на модела с набора от хиперпараметри, които работят най-добре числено. Ето как изглежда нашият финализиран работен процес:

Ако обаче погледнем крайния резултат от настройката на caret, получаваме други стойности за същите хиперпараметри, които може да се дължат на разлики в критериите за оптимизация: Може би това е така, защото glmnet моделът на tidymodel не е изрично обучен да максимизира F1-стойността?

За нашия подход tidymodels, ние използваме нашия финализиран работен процес и го приспособяваме към повторните проби, за да изчислим показателите за производителност през гънките. За тази цел можем да използваме fit_resamples() за оценка на ефективността на модела в различни гънки на данните. За разлика от приспособяването на финализирания работен процес към целия ни обучителен набор, повторното вземане на проби ни дава по-близка оценка за това как моделът ще се представи върху нови проби. За окончателно заключение за представянето му все пак трябва да изчакаме оценката на тестовите данни. Като следваща стъпка използваме last_fit() за генериране на крайните резултати от повторно вземане на проби, които се оценяват върху данните от теста. Можем да разгледаме ефективността на всеки модел върху данните за обучение, за да потвърдим това наблюдение.

print(model_glmnet)

Този обект last_fit включва не само финализирания работен процес заедно с нашите окончателни показатели за ефективност, но също така съдържа хубав раздел за нашите прогнози: прогнозираните класове, вероятностите за класове и действителните резултати. Те са вложени в обекта last_fit, така че когато ги конвертираме в data.frame, можем да визуализираме окончателните прогнози. Например, можем да начертаем разпределенията на плътността на прогнозираните вероятности, оцветени от действителните резултати от изтощение (вдъхновени от «публикация от Юлия Силге»).

Тъй като разпределенията се припокриват доста, изглежда, че има много случаи, в които моделът предвижда и двата резултата (да/не) да бъдат почти еднакво вероятни. Това също означава, че активните служители и напусналите не са били толкова лесно разделими, но нашите показатели за ефективност показват, че алгоритъмът приписва само малко по-голяма вероятност за правилния резултат в повечето случаи. За положителния клас класификаторът трябва да е открил по-голямата част от истинските напускащи, но също така неправилно е оставил около 30 % от тях на отрицателния клас (и обратно). Какво се случва, ако начертаем прогнозите от caret?

Уау, изглежда, че повече истински негативи получават вероятност за изчерпване, близка до нула, докато класификаторът има тенденция да присвоява висока вероятност за изчерпване на служители, които действително са напуснали. Но също така неправилно класифицира около една трета от истинските положителни резултати, както и истинските отрицателни резултати... Как това представяне се отразява на целия набор от обучения? След като монтираме модела върху данните за обучение, можем да правим прогнози, използвайки predict().

Според хипотезата, около 30% от данните са неправилно класифицирани във всеки клас, което също се отразява в сходните нива на чувствителност (TPR) спрямо специфичност (TNR). За да получим подобна информация за нашия карет класификатор, можем просто да извикаме predict.train()и да използваме нашия модел и данни за обучение като входни данни, след което обгръщаме прогнозите в команда ConfustionMatrix(). Сега имаме много добър преглед на ефективността на данните за обучението.

Резултатът подчертава нашето предположение, че каретката е била малко по-добра в разплитането на положителния от отрицателния клас. Освен това получаваме много по-малко фалшиви отрицания в сравнение с изхода на нашите tidymodels, което предполага, че припомнянето трябва да бъде относително подобрено (76 % срещу 71 %).

Бяхме достатъчно умни, за да запазим някои от данните за целите на тестването — сега е време моделите действително да покажат своите умения за прогнозиране! Причината за това е, че оценяването на производителността на едни и същи данни, на които са били обучени класификаторите, води до висок риск от пренастройване: моделът силно зависи от данните, върху които първоначално е обучен, така че показателите за производителност, изчислени на едни и същи данни, в никакъв случай не са независими . За да предизвикаме способността на модела да обработва нови наблюдения, трябва да го тестваме върху данни, които никога не са виждали преди. За да получим показатели за ефективността на тестовите данни за tidymodels, можем да извикаме нашия last_fit обект, който вече носи показатели на тестовите данни за удобство.

ROC-кривата, най-накрая обяснена

Оказва се, че оценката на данните от обучението наистина би надценила производителността на модела, тъй като с изключение на специфичността, всички показатели са малко по-ниски в данните от тестването (напр. 0,61 срещу 0,71 за чувствителност). Това може да бъде допълнително потвърдено с нашата необработена матрица на объркването върху данните от теста:

В caret можем просто да предадем модела заедно с целевата колона на нашите тестови данни към ConfusionMatrix() и също така да получим някои показатели за ефективност.

Резултатът предполага, че същите методи отново се представят малко по-добре в сравнение с tidymodels, въпреки че разликите са доста незначителни. Като цяло, това още веднъж показва колко логично е да запазите някои данни за тестване, за да избегнете прекаления оптимизъм относно представянето на модела.

Можем да го интерпретираме по следния начин: колкото по-близо линията прилича на ъгъл от 90°, толкова повече специфичност идва с висока чувствителност. Можете да мислите за чувствителността като 1 — FPR, така че това е вероятността моделът правилно да идентифицира всички истински положителни случаи като положителни (или истински положителен процент). Обратно, специфичността е 1 — FNR, така че е вероятността моделът да идентифицира правилно всички истински отрицателни случаи като отрицателни (или истински отрицателен процент). Тъй като чувствителността се изобразява срещу 1-специфичност, площта под кривата се увеличава, когато висока чувствителност идва с висока специфичност. Можете да мислите за ROC кривата като за вид мисловен експеримент: когато имаме чувствителност от 0,75, най-добрата възможна стойност за 1 — специфичност или фалшиво положителен процент би била 0,00. В този случай откриването на истински положителни резултати ще дойде с всички отрицателни случаи, които все още са идентифицирани като такива. Представете си, че ще имаме доста груб модел, който просто ще класифицира всички случаи като положителни: ще имаме перфектна чувствителност (TPR), но мизерна специфичност или FPR, защото истинските негативи (напр. лоялни служители) също ще получат положителен етикет. Това е лошо, ако ви е грижа и за отрицателните случаи и искате да ги разграничите от положителните. И така, колкото по-висока е чувствителността, толкова по-висок е рискът от ниска специфичност и обратно, представено от пунктирания диагонал на диаграмата. За спретнати модели чувствителността от 0,75 идва със специфичност от 0,6, което не е лош компромис. По този начин, тъй като нашият модел става достатъчно интелигентен, за да открива напускащи (изтощение = да), като същевременно идентифицира активни служители (изтощение = не), площта под кривата се увеличава.

Сега кой пакет спечели битката?

За да направим подобна ROC-крива в рамките на нашата карет-рамка, можем да използваме «MLeval», за да ни предостави набор от свързани с ROC изходи. Като цяло площта под кривата за glmnet изглежда е малко по-голяма в сравнение с изхода на tidymodels и няма огромна разлика в производителността между двете рамки.

Tidymodels се предлага с висока гъвкавост, тъй като е базиран на различни модерни пакети и има напълно адаптивна структура на работния процес. Това означава, че имате много степени на свобода, когато става въпрос за създаване на ваш собствен проект за машинно обучение. Но тъй като са включени толкова много стъпки и обекти, това със сигурност може да бъде малко объркващо за начинаещите. По време на собствения си проект почувствах, че разбрах по-добре какво прави програмата, тъй като заобиколих много съобщения за грешка, научавайки много теория по пътя. Но това може да се дължи и на факта, че tidymodels все още е в процес на разработка и следователно все още не е толкова стабилен. Ако искате бързо и кратко решение на вашия проблем с прогнозиране, вместо да създавате голям проект, бих ви препоръчал caret. Той е не само по-бърз по отношение на времето за изпълнение, но все още има повече ресурси и решени проблеми от опитни потребители. Caret пасва на много модели за вас с много малко работа по кодиране, като същевременно е възможно най-бърз благодарение на паралелната обработка. За разлика от tidymodels, най-добрият кандидат-модел в повторните проби се избира автоматично за вас, което може да бъде изрядно. Едно нещо е сигурно: Макс Кун със сигурност се е свършил чудесно с проектирането на тези пакети и имате късмет, че имате два мощни пакета с отворен код, от които да избирате.

Благодарности

Моите специални благодарности отиват на Робърт Лоне, консултант от Норвегия, който действаше като мой интелектуален спаринг партньор по време на този проект. Наистина ми хареса нашия съвместен обмен и се надявам, че учебното ни пътуване няма да спре до тук!

Препратки

[1] G. Harden, K. G. Boakye & S. Ryan, «Намерение за оборот на технологичните професионалисти: Перспектива на теорията за социалния обмен» (2018), Journal of Computer Information Systems, 58(4), 291–300.

rsample: за разделяне на проби (напр. обучение/тест или кръстосано валидиране)

[2] J. Sarkar, Свързване на компенсацията и текучеството: ретроспекция и бъдещи насоки (2018), IUP Journal of Organizational Behavior, 17(1).

[3] P.C. Bryant & D. G. Allen, Компенсации, ползи и текучество на служители: HR стратегии за задържане на най-добрите таланти (2013), Преглед на компенсациите и ползите, 45(3), 171– 175.

Caret срещу tidymodel — Създайте пълни работни процеси за машинно обучение за многократна употреба