-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathProgram.cs
142 lines (132 loc) · 6.69 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using Microsoft.ML;
namespace poker_estimator
{
class Program
{
private static string AppPath =>
Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);
private static string TrainDataInputPath =>
Path.Combine(AppPath, "..", "..", "..", "Data", "jira.xml");
private static string DataInputPath =>
Path.Combine(AppPath, "..", "..", "..", "Data", "to_estimate.xml");
private static MLContext _mlContext;
private static ThreePointPokerPredictor _predictionEngine;
private static void Main(string[] args)
{
_mlContext = new MLContext(seed: 0);
Console.WriteLine("=== Training ===");
var fromXml = LoadXml(TrainDataInputPath).ToList();
var pipeline = ProcessData();
_predictionEngine = new ThreePointPokerPredictor(_mlContext, fromXml, pipeline);
Console.WriteLine("=== Estimation ===");
var toEstimate = LoadXml(DataInputPath);
foreach (var issue in toEstimate)
{
var prediction = _predictionEngine.Predict(issue);
Console.WriteLine($"{issue.Key}: {prediction.Min}/{prediction.Mean}/{prediction.Max} = {prediction.Time}");
}
}
private static IEnumerable<JiraIssue> LoadXml(string path)
{
Console.WriteLine($"Loading file: {path}");
var trainingData = new XmlDocument();
trainingData.Load(path);
var result = trainingData.GetElementsByTagName("item").Cast<XmlNode>()
.Select(item => new JiraIssue
{
Key = GetValue(item, "key"),
Id = GetAttribute(GetChild(item, "key"), "id"),
ParentId = GetAttribute(GetChild(item, "parent"), "id"),
Title = GetValue(item, "title"),
Description = GetValue(item, "description"),
Type = GetValue(item, "type"),
Time = new SecondPokerizer(GetAttribute(GetChild(item, "timespent"), "seconds")).ToPokerDays(),
Environment = GetValue(item, "environment"),
Reporter = GetValue(item, "reporter"),
Version = GetValue(item, "version"),
Priority = GetValue(item, "priority"),
OriginalEstimate = new SecondPokerizer(GetAttribute(GetChild(item, "timeestimate"), "seconds")).ToPokerDays(),
CreatedTime = GetValue(item, "created"),
//TODO more fields
}).ToList();
foreach (var issue in result)
{
var parent = result.Where(r => r.Id == issue.ParentId && !string.IsNullOrEmpty(issue.ParentId))
.DefaultIfEmpty(new JiraIssue())
.FirstOrDefault();
issue.ParentTitle = parent?.Title;
issue.ParentDescription = parent?.Description;
}
Console.WriteLine($"{result.Count} issues loaded");
return result;
}
private static string GetAttribute(XmlNode node, string attributeKey)
{
return node?.Attributes.Cast<XmlAttribute>()
.Where(attribute => attribute.Name == attributeKey)
.Select(attribute => attribute.Value)
.DefaultIfEmpty(null)
.FirstOrDefault();
}
private static XmlNode GetChild(XmlNode item, string nodeName)
{
return item.ChildNodes.Cast<XmlNode>()
.Where(child => child.Name == nodeName)
.DefaultIfEmpty(null)
.FirstOrDefault();
}
private static string GetValue(XmlNode item, string nodeName)
{
return GetChild(item, nodeName)?.InnerText;
}
private static IEstimator<ITransformer> ProcessData()
{
return _mlContext.Transforms.Conversion.MapValueToKey(
inputColumnName: "Time", outputColumnName: "PokerValue")
.Append(_mlContext.Transforms.Text.FeaturizeText(
inputColumnName: "Type",
outputColumnName: "TypeFeaturized"))
.Append(_mlContext.Transforms.Text.FeaturizeText(
inputColumnName: "Title",
outputColumnName: "TitleFeaturized"))
.Append(_mlContext.Transforms.Text.FeaturizeText(
inputColumnName: "Description",
outputColumnName: "DescriptionFeaturized"))
.Append(_mlContext.Transforms.Text.FeaturizeText(
inputColumnName: "Environment",
outputColumnName: "EnvironmentFeaturized"))
.Append(_mlContext.Transforms.Text.FeaturizeText(
inputColumnName: "Reporter",
outputColumnName: "ReporterFeaturized"))
.Append(_mlContext.Transforms.Text.FeaturizeText(
inputColumnName: "Version",
outputColumnName: "VersionFeaturized"))
.Append(_mlContext.Transforms.Text.FeaturizeText(
inputColumnName: "Priority",
outputColumnName: "PriorityFeaturized"))
.Append(_mlContext.Transforms.Text.FeaturizeText(
inputColumnName: "OriginalEstimate",
outputColumnName: "OriginalEstimateFeaturized"))
.Append(_mlContext.Transforms.Text.FeaturizeText(
inputColumnName: "CreatedTime",
outputColumnName: "CreatedTimeFeaturized"))
.Append(_mlContext.Transforms.Text.FeaturizeText(
inputColumnName: "ParentTitle",
outputColumnName: "ParentTitleFeaturized"))
.Append(_mlContext.Transforms.Text.FeaturizeText(
inputColumnName: "ParentDescription",
outputColumnName: "ParentDescriptionFeaturized"))
.Append(_mlContext.Transforms.Concatenate(
"Features", "TypeFeaturized", "TitleFeaturized",
"DescriptionFeaturized", "EnvironmentFeaturized", "ReporterFeaturized", "VersionFeaturized",
"PriorityFeaturized", "OriginalEstimateFeaturized", "CreatedTimeFeaturized",
"ParentTitleFeaturized", "ParentDescriptionFeaturized"))
.AppendCacheCheckpoint(_mlContext);
}
}
}