Главная » Язык программирования C#

Машинное обучение — простой пример программы на C#

Машинное обучение: что из себя представляет?

Чашка чая на столе, уже за полночь и хорошая музыка в наушниках — все это означает что далее последует довольно ощутимой величины статья о том, как я применил довольно примитивный способ машинного обучения для создания программы, которая, собственно и использовало бы машинное обучение. Ну а так как машинное обучение и того хуже экзистенциальные вопросы по поводу создания искусственного интеллекта уже занимают довольно обширный раздел математической и информационных дисциплин, я не буду углубляться далеко в эту сокровищницу(благо нечем особо и поделиться). Расскажу ка я лучше о поставленной задаче по созданию программы с элементами машинного обучения.

Задача состояла собственно в необходимости использования машинного обучения программе, а где и при каких обстоятельствах — уже решалось самостоятельно. Посему была выбрана близкая отрасль — web-сайты, а точнее оценка стоимости сайтов по нескольким параметрам. Но оценка должна была производится не отнюдь по формуле, взятому из закоулков головного мозга создателя программы. Иначе ни какого бы машинного обучения в этом не было. Именно формулу стоимости сайта и должна была нам выдать наша программа!

Машинное обучение Яндекса

А теперь я немного отойду в сторону от заданной темы и расскажу о машинном обучении, используемом в поисковой системе Яндекс, на основе работы(а точнее на описании работы) которого и был составлен принцип работы нашей программы.

Как известно поисковая система, в частности Яндекс, зарабатывает свой хлеб на том, что предоставляет пользователю услугу поиска определенных документов по всем проиндексированным роботом поисковой системы документов. И основная фишка любой поисковой системы состоит в том, чтобы выдать пользователю наиболее релевантный(наиболее подходящий под его запросы) ответ. Если бы поисковые системы(далее ПС) выдавали бы нам с ухты-барахты любые сайты(пусть и с каким-то совпадением по запросу), то они бы не пользовались той бешеной популярностью, которая есть у них сейчас.

Но вот какой дикий вопрос: как предоставить многим и многим миллионам пользователей, у каждого из которых свои тараканы в голове и свои запросы, релевантную выдачу, чтобы каждый из них был доволен. Разумеется, делать это не вручную(заебешься обрабатывать миллионы новых страниц каждый день). Нужно обучить этому компьютер. Однако для этого нужно статически указать определенное количество параметров(сейчас уже многие сотни как минимум), по которым компьютер будет ранжировать сайты. Но все же здесь до сих пор слишком много человеческих рук, которые постоянно подкручивают этот алгоритм, чтобы он работал как надо.

Уменьшить количество ненужных рук можно с помощью машинного обучения. Вот собственно ради чего весь сыр бор:

  1. Ассессоры(специально обученные люди, которые ползают по выдаче, оценивают сайты из выдачи по заранее выданным им критериям и выдают свою жестокую оценку реальности по поводу каждого из просмотренных сайтов) собственно делают свою работу. На выходе получаем выборку сайтов(как правило разные тематики обрабатываются по разному) для каждого из которых дана оценка специально обученного человека.
  2. Вся эта выборка(входные данные, если хотите) подается на корм Матрикснету(именно так нужно величать Великое и Ужасное Машинное обучение Яндекса).
  3. Специально обученный Матрикснет всю эту выборку обрабатывает и ищет какие-то закономерности, по которым ассессоры назвали «вот эти вот сайты хорошими и соответствующими запросу, а вот эти вот назвали плохими».

Естественно Матрикснет постоянно дрессируется, но для пользы дела хочу предложить элементарный критерий, по которому Матрикснет может принять свое решение: например, у хороших сайтов тексты начинаются на букву Ё. К этому он может прийти по ходу обработки выборки сайтов. Разумеется, Яндекс учит Матрикснет обращать внимание только на действительно стоящие параметры и поэтому мой примитивный пример имеет только обучающую задачу.

Вот вам и простейший алгоритм для машинного обучения — скармливаем программе какую-то выборку(предварительно проверенную настоящим искусственным интеллектом), на основе которого он должен решить как ему поступать с другими данными.

Машинное обучение для оценки стоимости сайтов

Основываясь на предыдущем абзаце, который в свою очередь основан на официальном заявлении компании Яндекса и который мог претерпеть изменения только по вине моей некомпетентности, я продолжу создание своего машинного обучения. Что нам нужно в первую очередь? Правильно, выборка.

Тащим выборку для машинного обучения

Так как мы имеем дело с оценкой стоимости сайтов, то нам нужна выборка в которой будут некоторые параметры сайта и его стоимость. Но тут нужно учитывать один важный момент — выборка должна проверенной специально обученным человеком. Конечно же можно было бы использовать свой разум, но я решил обратиться к обществу. Сайтов по продаже и покупке других сайтов достаточно. И имеются такие, на которых можно делать ставку за понравившийся сайт, который ты уже готов за какую-то сумму. А есть ли более честный человек, чем тот, который уже готов выложить(или даже уже обязался выложить) свои кровно заработанные деньги с такими-то параметрами? Вот вам и независимая оценка, которая может быть усилена наличием нескольких ставок. Далее, чтобы выборка была действительно репрезентативной, можно выборку составить только из сайтов одной тематики.

Вот вам и получается выборка, честная, независимая и так далее. Осталось все это дело перенести в базу данных. Сколько и какие параметры вы будете использовать — ваше дело. Вот пример моей базы данных, которая уже успешно добавлена в программу.

45425

Те, кто что-то смыслит в создании и продвижении сайтов сразу поймет какие параметры сайтов взяты. Так же имеется и последний столбец(стоимость), который является суммой(или результатом любого другого математического действия со всеми параметрами — это уже ваше решение и ваша задача) всех восьми параметров сайта(разумеется не только этих восьми, но я довольствовался тем, что можно получить в общем доступе).

На этом хотелось бы заявить что первый пункт закончен.

Собственно машинное обучение на основе выборки

Далее все это дело необходимо скормить нашей программе. Ее задача будет состоять в том, чтобы понять, почему сборище таких-то параметров дает в итоге такую стоимость сайта, а сборище вот таких параметров дает другую стоимость сайта. Для облегчения всего дела я предположил, что стоимость сайта является результатом суммы всех параметров, у каждого из которых имеется свой повышающий(или понижающий коэффицент). Учитывая все это, можно всю эту таблицу представить в виде системы линейных алгебраических уравнений(СЛАУ):

457687

Полностью переносить все значения не стал, думаю итак можно понять что к чему. Вот такую то и систему уравнений и необходимо решить нашей программе. На выходе она должна получить свободные члены (от X1 до X8). Когда программа получит эти свободные члены, то можно сказать, что машинное обучение на основе выборки завершено. Теперь программу готова для своей непосредственной работе — оценке стоимости сайтов.

Работа программы с машинным обучением

Ну и самая скучная часть всей программы: нужно распарсить все восемь параметров анализируемого сайта и решить линейное уравнение с этими восьми параметрами и уже ранее найденными свободными членами, в результате которой мы и получим приблизительную стоимость сайта.

Код программы, использующей машинное обучение, на языке C#

Приводить весь проект не буду, но предложу вашему вниманию отрезки наиболее значимых моментов кода. А начнем мы с того, что загрузим всю нашу базу данных, созданных в Microsoft Access, в DataGrivView сразу же по загрузке формы:

DataTable Таблица;
private void Form1_Load(object sender, EventArgs e)
        {
            this.Text = "Чтение таблицы из БД:";
            var Подключение = new
                      System.Data.OleDb.OleDbConnection(
                     "Data Source=\"E:\\name.mdb\";User " +
                     "ID=Admin;Provider=\"Microsoft.Jet.OLEDB.4.0\";");
            Подключение.Open();
            var Команда = new System.Data.OleDb.OleDbCommand(
                     "Select * From [Стоимость сайтов и параметры]", Подключение);
            var Адаптер = new System.Data.OleDb.OleDbDataAdapter(Команда);
            var НаборДанных = new System.Data.DataSet();
            Адаптер.Fill(НаборДанных, "Стоимость сайтов и параметры");
            var СтрокаXML = НаборДанных.GetXml();
            dataGridView1.DataSource = НаборДанных;
            dataGridView1.DataMember = "Стоимость сайтов и параметры";//название таблицы
            Подключение.Close();
            Таблица = new DataTable();
            
        }

Далее нам необходимо обработать всю эту выборку. Можете привязать этот момент к какой-либо кнопке либо вызывать сразу после загрузки таблицы в DataGridView. И первым делом всю эту таблицу необходимо преобразовать в массив:

public static DataTable ToDataTable(DataGridView dataGridView, string tableName)
 {
 DataGridView dgv = dataGridView;
 DataTable table = new DataTable(tableName);
 for (int iCol = 0; iCol < dgv.Columns.Count; iCol++)
 {
 table.Columns.Add(dgv.Columns[iCol].Name);
 }
 foreach (DataGridViewRow row in dgv.Rows)
 {
 DataRow datarw = table.NewRow();

 for (int iCol = 0; iCol < dgv.Columns.Count; iCol++)
 {
 datarw[iCol] = row.Cells[iCol].Value;
 }
 table.Rows.Add(datarw);
 }
 return table;
 }
private void is_tablicy_v_massiv()
        {
            Таблица = ToDataTable(dataGridView1, "Стоимость сайтов и параметры");
            int i, j;
            Double[,] A;
            Double[] L;
            // Признак ввода числовых данных:
            var Число_ли = false;

            // Теперь можем определиться с размерностью массивов:
            // Матрица коэффициентов линейных уравнений:
            A = new Double[n, n];
            // Вектор свободных членов:
            L = new Double[n];
            // Заполнение матрицы коэффициентов системы A[j, i]
            for (j = 0; j <= n - 1; j++)
            {
                for (i = 0; i <= n - 1; i++)
                {
                    A[j, i] = ВернутьЧисло(j, i, ref Число_ли);
                    //A[j, i] *= koef[i];
                    if (Число_ли == false) return;
                } // - конец тела внутреннего цикла по i
                // Правая часть системы B[j, 0]
                L[j] = ВернутьЧисло(j, i, ref Число_ли);
                if (Число_ли == false) return;
            } // - конец тела внешнего цикла по j
        }
Double ВернутьЧисло(int j, int i, ref Boolean Число_ли)
        {
            // j - номер строки, i - номер столбца
            // Передаем аргумент Число_ли по ссылке
            Double rab; // - рабочая переменная
            var tmp = Таблица.Rows[j][i].ToString();
            Число_ли = Double.TryParse(tmp,NumberStyles.Number,NumberFormatInfo.CurrentInfo,out rab);
            if (Число_ли == false)
            {
                tmp = String.Format("Номер строки {0}, номер столбца " +
                    "{1}," + "\n в данном поле - не число", j + 1, i + 1);
                MessageBox.Show(tmp);
            }
            return rab;
        }

Далее необходимо нам решить эту систему линейных уравнений, для чего был выбран метод Гаусса, но вы можете выбрать любой другой метод. В сети можно найти достаточно исходников каждого доступного метода. Вот метод, который использовался мною:

void gauss(int n, double[,] A, ref double[] LL)
        {
            // n  - размер матрицы
            // A  - матрица коэффициентов линейных уравнений
            // LL - правая часть, сюда же возвращаются значения неизвестных
            int i, j, l = 0;
            Double c1, c2, c3;
            for (i = 0; i <= n - 1; i++) // Цикл по элементам строки
            {
                c1 = 0;
                for (j = i; j <= n - 1; j++)
                {
                    c2 = A[j, i];
                    if (Math.Abs(c2) > Math.Abs(c1))
                    {
                        l = j; c1 = c2;
                    }
                }

                for (j = i; j <= n - 1; j++)
                {
                    c3 = A[l, j] / c1;
                    A[l, j] = A[i, j]; A[i, j] = c3;
                } // j

                c3 = LL[l] / c1; LL[l] = LL[i]; LL[i] = c3;

                for (j = 0; j <= n - 1; j++)
                {
                    if (j == i) continue;
                    for (l = i + 1; l <= n - 1; l++)
                    {
                        A[j, l] = A[j, l] - A[i, l] * A[j, i];
                    } // l
                    LL[j] = LL[j] - LL[i] * A[j, i];
                } // j
            } // i
        }

Этот метод на выходе даст массив свободных членов(в моем случае, восемь чисел). С помощью этих данных можно уже задействовать нашу программу для выполнения непосредственного задания — оценка стоимости сайта. Для этого программа, должна для введенного сайта получить его параметры. Парсить 8 параметров из различных официальных источников — довольно трудоемкое занятие. Благо уже давно существуют специальные сервисы для оценки показателей сайтов и у которых есть API. В моем случае использовался API сайта pr-cy:

w.DownloadString("//api.pr-cy.ru/analysis.json?domain=" + url);

Полученные данные от подобного сервиса нужно распарсить и получить значения всех наших параметров, после чего передать их, а так же массив свободных членов на вычисление приблизительного значения стоимости сайта. Вот и все.

Выводы относительно машинного обучения

Хотелось бы заострить внимание читателей на то, что вышеописанное не претендует на абсолютную достоверность и автор не берется с до последнего дыхания доказывать, что вышеописанное является машинным обучением. Статья(да и сама работа по созданию программы с машинным обучением) является лишь результатом прочтения нескольких статей про Машинное обучение Яндекса и логического мышления, с помощью которого алгоритм действия вышеописанного МО от Яши был адаптирован под решение заданной задачи.

Кроме этого, хотелось бы поделиться результатами действия данной программы и с некоторыми наработками, которые появились по ходу решения этой задачи.

Во-первых, это катастрофически маленькая выборка(всего лишь 8 сайтов), что не дает рассчитывать на какой-либо серьезный результат и стоимость анализируемых сайтов может разниться в дичайших пределах.

Во-вторых, выборка должна быть репрезентативной. Например, если отталкиваться от моей выборки, то программа может посчитать, что наличие сайта в каталоге DMOZ и в Яндекс Каталоге может являться наоборот отрицательным моментом и отрицательно влиять на его стоимость(так как два сайта которые присутствует в том или ином каталоге отнюдь не блещут своей стоимостью).

В-третьих, использованная здесь формула для решения СЛАУ да и само представление всей таблицы в виде СЛАУ, возможно, является не самым лучшим решением и скорее всего можно подобрать другую, более подходящую формулу.

В-четвертых, не все же делать только программе, а значит мы всегда можем добавить свои коэффиценты для того чтобы усилить или наоборот ослабить влияние каких-либо параметров.

Думаю на этом можно завершить эту статью.

Добавить комментарий

Ваш комментарий появится после модерации.