一种简单的方法是使用Accord ID3决策树。关键在于确定要使用哪些输入 - 你不能仅仅训练X - 树将无法从中学习到X未来的值 - 然而,你可以构建一些从X(或Y的先前值)派生的特征,这将非常有用。
通常对于这样的问题 - 你会基于先前Y的值派生的特征进行每个预测,而不是X。然而,这假设你可以在每个预测之间按顺序观察Y(然后你就无法为任意X进行预测),所以我将坚持原问题。
下面是我尝试构建Accord ID3决策树来解决此问题的代码。我使用了几个不同的x%n值作为特征 - 希望树可以从中找出答案。实际上,如果我将(x-1)%4添加为一个特征,则可以在单个级别中仅使用该属性完成它 - 但我想重点是让树发现模式。
以下是该代码:
int[] ysequence = new int[] { 1, 2, 3, 2 };
int CalcY(int x) => ysequence[(x - 1) % 4];
int[] CalcInputs(int x) => new int[] { x % 2, x % 3, x % 4, x % 5, x % 6 };
[TestMethod]
public void AccordID3TestStackOverFlowQuestion2()
{
int numtrainingcases = 12;
int[][] inputs = new int[numtrainingcases][];
int[] outputs = new int[numtrainingcases];
Console.WriteLine("\t\t\t\t x \t y");
for (int x = 1; x <= numtrainingcases; x++)
{
int y = CalcY(x);
inputs[x-1] = CalcInputs(x);
outputs[x-1] = y;
Console.WriteLine("TrainingData \t " +x+"\t "+y);
}
DecisionVariable[] attributes =
{
new DecisionVariable("Mod2",2),
new DecisionVariable("Mod3",3),
new DecisionVariable("Mod4",4),
new DecisionVariable("Mod5",5),
new DecisionVariable("Mod6",6)
};
int classCount = outputs.Max()+1;
DecisionTree tree = new DecisionTree(attributes, classCount);
ID3Learning id3learning = new ID3Learning(tree);
id3learning.Learn(inputs, outputs);
Console.WriteLine();
for (int x = numtrainingcases+1; x <= 2* numtrainingcases; x++)
{
int[] query = CalcInputs(x);
int answer = tree.Decide(query);
Assert.AreEqual(CalcY(x), answer);
Console.WriteLine("Prediction \t\t " + x+"\t "+answer);
}
}
这是它生成的输出结果:
x y
TrainingData 1 1
TrainingData 2 2
TrainingData 3 3
TrainingData 4 2
TrainingData 5 1
TrainingData 6 2
TrainingData 7 3
TrainingData 8 2
TrainingData 9 1
TrainingData 10 2
TrainingData 11 3
TrainingData 12 2
Prediction 13 1
Prediction 14 2
Prediction 15 3
Prediction 16 2
Prediction 17 1
Prediction 18 2
Prediction 19 3
Prediction 20 2
Prediction 21 1
Prediction 22 2
Prediction 23 3
Prediction 24 2
希望对你有所帮助。
编辑:根据评论,下面的示例被修改为在目标变量(Y)的先前值上进行训练 - 而不是从时间索引(X)派生的特征。这意味着您不能从系列的开始开始训练 - 因为您需要先前的Y值的历史记录。在此示例中,我从x = 9开始,只是因为这样保持了相同的序列。
int[] ysequence = new int[] { 1, 2, 3, 2 };
int CalcY(int x) => ysequence[(x - 1) % 4];
int[] CalcInputs(int x) => new int[] { CalcY(x-1), CalcY(x-2), CalcY(x-3), CalcY(x-4), CalcY(x - 5) };
[TestMethod]
public void AccordID3TestTestStackOverFlowQuestion2()
{
int numtrainingcases = 12;
int starttrainingat = 9;
int[][] inputs = new int[numtrainingcases][];
int[] outputs = new int[numtrainingcases];
Console.WriteLine("\t\t\t\t x \t y");
for (int x = starttrainingat; x < numtrainingcases + starttrainingat; x++)
{
int y = CalcY(x);
inputs[x- starttrainingat] = CalcInputs(x);
outputs[x- starttrainingat] = y;
Console.WriteLine("TrainingData \t " +x+"\t "+y);
}
DecisionVariable[] attributes =
{
new DecisionVariable("y-1",4),
new DecisionVariable("y-2",4),
new DecisionVariable("y-3",4),
new DecisionVariable("y-4",4),
new DecisionVariable("y-5",4)
};
int classCount = outputs.Max()+1;
DecisionTree tree = new DecisionTree(attributes, classCount);
ID3Learning id3learning = new ID3Learning(tree);
id3learning.Learn(inputs, outputs);
Console.WriteLine();
for (int x = starttrainingat+numtrainingcases; x <= starttrainingat + 2 * numtrainingcases; x++)
{
int[] query = CalcInputs(x);
int answer = tree.Decide(query);
Assert.AreEqual(CalcY(x), answer);
Console.WriteLine("Prediction \t\t " + x+"\t "+answer);
}
}
您还可以考虑对Y的以前值之间的差异进行培训 - 这在绝对值不如相对变化重要的情况下效果更好。