Время прочтения: 4 мин.
Каждый раз, выполняя анализ данных методами машинного обучения традиционными средствами в виде Python, возникает вопрос: «Неужели это единственный рабочий инструмент для подобного рода задач, не имеющий аналогов?». Определённо нет. В данной статье рассмотрим ещё один пример использования функционального программирования для задач машинного обучения, в частности, реализацию применения нейронной сети на языке F# с использованием библиотеки numl.
В последние десятилетия с ростом объёмов данных и увеличением темпов развития технологий для решения задач становятся доступными разнообразные варианты инструментария и алгоритмов. Среди этих вариантов есть как специфические, так и универсальные, покрывающие максимальное количество потребностей аналитиков в различных предметных областях. Но стоит помнить о том, что универсальное решение всегда работает хуже, чем узконаправленное, подходящее для конкретной задачи. Поэтому важно иметь опыт работы с различными инструментами, а главное, знать назначение и сильные стороны каждого из них.
У большинства начинающих аналитиков словосочетание «машинное обучение» сразу же ассоциируется с языком Python и его библиотеками (Pandas, SkLearn и т.д.). Происходит это, конечно же, из-за того, что данный набор программных средств стал массово применяться в Data Science одним из первых. И на фоне его популярности альтернативные разработки незаслуженно остаются незамеченными и малоиспользуемыми. Например, для .NET-разработчиков существует библиотека ML.NET, позволяющая пользоваться всеми преимуществами Python без необходимости изучения ещё одного языка программирования.
Рассмотрим пример использования функционального программирования для задач машинного обучения, а именно, реализацию применения нейронной сети на языке F#. Для демонстрации работы нейронной сети будет использован предобработанный датасет с пассажирами Титаника.
Создадим консольный проект и добавим нужные ссылки на библиотеки, в данном случае это библиотека numl. Также создадим тип (класс) Passenger, в который будут загружаться данные для обучения и предсказания:
open System
open numl
open numl.Model
open numl.Supervised.NeuralNetwork
let trainFile = "./Train.csv"
type Passenger = {
[<Label>] mutable Survived: bool;
[<Feature>]Pclass: float;
[<Feature>]Sex: float;
[<Feature>]Age: float;
[<Feature>]SibSp: float;
[<Feature>]Parch: float}
В качестве признаков выбраны класс, пол, возраст, количество родственников на борту и количество детей. Следует отметить, что эти атрибуты имеют неизменяемый тип, а атрибут Survived (то, что нам нужно предсказать) имеет инструкцию mutable, что говорит о возможности изменения значения атрибута.
Далее в вызываемой функции (main) пишем следующий код:
[<EntryPoint>]
let main argv =
let data = System.IO.File.ReadLines(trainFile)
let data' = data |> Seq.map box
let descriptor = Descriptor.Create<Passenger>()
let generator = NeuralNetworkGenerator()
generator.Descriptor <- descriptor
let curd = DateTime.Now
printfn "Start learning %A" curd
let model = Learner.Learn(data', 0.80, 100, generator)
printfn "Learning complete %A" ed
printfn "Learning time: %A" (ed-curd)
printfn "Accuary %A" accuracy
В данном фрагменте происходит чтение тренировочного датасета из файла и создание на его основе массива экземпляров класса Passenger (Descriptor). После этого создаётся генератор нейронов и подстановка в него дескриптора. На основе этого генератора и происходит обучение модели. Также добавим вывод времени начала и окончания обучения для контроля процесса обучения.
Как только модель становится обученной, можно приступать к предсказанию на тестовом датасете. Ниже приведён пример предсказания по одному человеку. Поскольку указание всех атрибутов обязательно, предсказываемый атрибут Survived имеет значение true:
printfn "Start predict"
let testData = {Survived=true; Pclass =3.0; Sex =1.0; Age =47.0; SibSp =1.0; Parch = 0.0}
let predict = model.Model.Predict(testData)
printfn "Predict complete"
printfn "Predicted data: %A" predict
Console.ReadLine() |> ignore
В результате выполнения предсказания видно, что Survived принял значение false:
Следует отметить, что данный результат был получен при условии, что объём обучающей выборки равен 80% и количество повторений 100. Если изменить эти настройки, например, увеличить количество повторов, то увеличится и время обучения. При этом метрика accuracy изменится в меньшую сторону.
Укажем в настройках модели 200 повторов вместо 100:
let model = Learner.Learn(data', 0.80, 200, generator)
Получаем результат, описанный выше:
Если же поменять объём выборки, то время обучения также уменьшится:
let model = Learner.Learn(data', 0.60, 200, generator)
Вот так выглядит простейший пример построения нейронной сети с помощью языка F#. Учитывая, небольшое количество строк кода, сопоставимое с количеством строк при решении той же задачи средствами Python, F# для машинного обучения достоин внимания и места в наборе инструментов аналитиков.