#c# #tree #random-forest #accord.net
#c# #дерево #случайный лес #accord.net
Вопрос:
Вопрос: Существует ли пример случайного леса, который разделяет обучающий и тестовый наборы? Текущий пример, который я нашел в тестовом проекте Accord-Net ML, использует те же самые данные для обучения и тестирования.
По-видимому, проблема, с которой я сталкиваюсь, заключается в синхронизации сгенерированных меток (целых чисел) в наборах тестов и поездов. Я генерирую метки поездов как таковые:
int[] trainOutputs = trainCodebook.Translate("Output", trainLabels);
And the test labels similarly:
int[] testOutputs = testCodebook.Translate("Output", testLabels);
Finally I train with the train data and test with the test data:
var forest = teacher.Learn(trainVectors, trainOutputs);
int[] predicted = forest.Decide(testVectors);
Если первые три строки не совпадают как в обучающем, так и в тестовом наборах, метки разные, и, соответственно, это приводит к очень высокому уровню ошибок.
Я попытался просто создать свою кодовую книгу вручную с помощью троичных строк:
new Codification("-1","0","1");
К сожалению, это приводит к ошибке времени выполнения, указывающей, что данного ключа не было в словаре. Я уверен, что есть способ синхронизировать генерацию ключей в двух отдельных кодовых книгах. Я могу заставить это работать с приведенным ниже кодом, ЕСЛИ добавлю три строки моих обучающих данных, содержащих все три ключа, в начало моих тестовых данных. Не мое предпочтительное решение; =)
Вот весь тест, который я запускаю:
[Test]
public void test_learn()
{
Accord.Math.Random.Generator.Seed = 1;
/////////// TRAINING SET ///////////
// First, let's load the TRAINING set into an array of text that we can process
string[][] text = Resources.train.Split(new[] { "rn" },
StringSplitOptions.RemoveEmptyEntries).Apply(x => x.Split(','));
int length = text[0].Length;
List<int> columns = new List<int>();
for (int i = 1; i < length; i )
{
columns.Add(i);
}
double[][] trainVectors = text.GetColumns(columns.ToArray()).To<double[][]>();
// The first column contains the expected ternary category (i.e. -1, 0, or 1)
string[] trainLabels = text.GetColumn(0);
var trainCodebook = new Codification("Output", trainLabels);
int[] trainOutputs = trainCodebook.Translate("Output", trainLabels);
////////// TEST SET ////////////
text = Resources.test.Split(new[] { "rn" },
StringSplitOptions.RemoveEmptyEntries).Apply(x => x.Split(','));
double[][] testVectors = text.GetColumns(columns.ToArray()).To<double[][]>();
string[] testLabels = text.GetColumn(0);
var testCodebook = new Codification("Output", testLabels);
int[] testOutputs = testCodebook.Translate("Output", testLabels);
var teacher = new RandomForestLearning()
{
NumberOfTrees = 10,
};
var forest = teacher.Learn(trainVectors, trainOutputs);
int[] predicted = forest.Decide(testVectors);
int lineNum = 1;
foreach (int prediction in predicted)
{
Console.WriteLine("Prediction " lineNum ": "
trainCodebook.Translate("Output", prediction));
lineNum ;
}
// I'm using the test vectors to calculate the error rate
double error = new ZeroOneLoss(testOutputs).Loss(forest.Decide(testVectors));
Console.WriteLine("Error term is " error);
Assert.IsTrue(error < 0.20); // humble expectations ;-)
}
Комментарии:
1. На самом деле у вас должна быть только одна кодовая книга, созданная из обучающего набора, и вы должны использовать ее для предварительной обработки данных как из обучающего , так и из тестового набора.
Ответ №1:
Хорошо, я разобрался. Смотрите код ниже:
Ладно, я думаю, что смог это исправить. Проблема заключалась в ошибочной реализации сериализации в DecisionTree. К счастью, у нас есть код — смотрите исправление ниже:
namespace Accord.MachineLearning.DecisionTrees
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using Accord.Statistics.Filters;
using Accord.Math;
using AForge;
using Accord.Statistics;
using System.Threading;
/// <summary>
/// Random Forest.
/// </summary>
///
/// <remarks>
/// <para>
/// Represents a random forest of <see cref="DecisionTree"/>s. For
/// sample usage and example of learning, please see the documentation
/// page for <see cref="RandomForestLearning"/>.</para>
/// </remarks>
///
/// <seealso cref="DecisionTree"/>
/// <seealso cref="RandomForestLearning"/>
///
[Serializable]
public class RandomForest : MulticlassClassifierBase, IParallel
{
private DecisionTree[] trees;
**[NonSerialized]
private ParallelOptions parallelOptions;**
/// <summary>
/// Gets the trees in the random forest.
/// </summary>
///
public DecisionTree[] Trees
{
get { return trees; }
}
/// <summary>
/// Gets the number of classes that can be recognized
/// by this random forest.
/// </summary>
///
[Obsolete("Please use NumberOfOutputs instead.")]
public int Classes { get { return NumberOfOutputs; } }
/// <summary>
/// Gets or sets the parallelization options for this algorithm.
/// </summary>
///
**public ParallelOptions ParallelOptions { get { return parallelOptions; } set { parallelOptions = value; } }**
/// <summary>
/// Gets or sets a cancellation token that can be used
/// to cancel the algorithm while it is running.
/// </summary>
///
public CancellationToken Token
{
get { return ParallelOptions.CancellationToken; }
set { ParallelOptions.CancellationToken = value; }
}
/// <summary>
/// Creates a new random forest.
/// </summary>
///
/// <param name="trees">The number of trees in the forest.</param>
/// <param name="classes">The number of classes in the classification problem.</param>
///
public RandomForest(int trees, int classes)
{
this.trees = new DecisionTree[trees];
this.NumberOfOutputs = classes;
this.ParallelOptions = new ParallelOptions();
}
/// <summary>
/// Computes the decision output for a given input vector.
/// </summary>
///
/// <param name="data">The input vector.</param>
///
/// <returns>The forest decision for the given vector.</returns>
///
[Obsolete("Please use Decide() instead.")]
public int Compute(double[] data)
{
return Decide(data);
}
/// <summary>
/// Computes a class-label decision for a given <paramref name="input" />.
/// </summary>
/// <param name="input">The input vector that should be classified into
/// one of the <see cref="ITransform.NumberOfOutputs" /> possible classes.</param>
/// <returns>A class-label that best described <paramref name="input" /> according
/// to this classifier.</returns>
public override int Decide(double[] input)
{
int[] responses = new int[NumberOfOutputs];
Parallel.For(0, trees.Length, ParallelOptions, i =>
{
int j = trees[i].Decide(input);
Interlocked.Increment(ref responses[j]);
});
return responses.ArgMax();
}
[OnDeserializing()]
internal void OnDeserializingMethod(StreamingContext context)
{
this.ParallelOptions = new ParallelOptions();
}
}
}