/// <summary> /// Creates one classifier (batch of trees) /// </summary> /// <returns></returns> public static DecisionBatch CreateBatch(double[,] xy, int treesInBatch, int nclasses, double rfcoeff, double varscoeff, int[] idx, bool parallel, bool useLogit) { var batch = new DecisionBatch(); IEnumerable <int> source = Enumerable.Range(1, treesInBatch); List <DecisionTree> treeList; if (parallel) { treeList = (from n in source.AsParallel() select DecisionTree.CreateTree(idx, xy, nclasses, rfcoeff, varscoeff) ).ToList(); } else { treeList = (from n in source select DecisionTree.CreateTree(idx, xy, nclasses, rfcoeff, varscoeff) ).ToList(); } treeList.ForEach(batch.AddTree); CalcOutOfTheBagMetrics(treeList, xy, batch, useLogit); return(batch); }
/// <summary> /// Load trees from dump files /// </summary> public override int LoadClassifier() { string treesRoot = ConfigReader.Read("TreesRoot"); int bucketSize = int.Parse(ConfigReader.Read("BucketSize")); string treesDir = treesRoot ?? (Environment.CurrentDirectory + "\\batches"); if (!Directory.Exists(treesDir)) { Logger.Log("directory " + treesDir + " doesn't exists"); return(0); } var dinfo = new DirectoryInfo(treesDir); _classifiers.Clear(); var files = dinfo.GetFiles("*.dmp").OrderBy(f => f.Name).ToArray(); if (bucketSize > 0) { files = files.Skip(bucketSize * _bucketNum).Take(bucketSize).ToArray(); _bucketNum++; } int clid = 0; foreach (var finfo in files) { var cls = DecisionBatch.Load(finfo.FullName); _classifiers.Add(clid++, cls); Logger.Log(finfo.Name + " loaded;"); } Logger.Log("all trees loaded;"); return(clid); }
/// <summary> /// Расчет классификации по тестовому обучающему на одном классификаторе /// </summary> /// <param name="batch"></param> /// <returns>Количество деревьев, проголосовавших за каждый класс</returns> private Dictionary <string, double> GetTrainClassificationCounts(DecisionBatch batch) { var probDict = new Dictionary <string, double>(); int lines = _trainLoader.TotalDataLines; int vars = _trainLoader.NVars; // пробегаем по всем клиентски данным и сохраняем результат for (int i = 0; i < lines; i++) { var cdata = new double[vars]; for (int j = 0; j < vars; j++) { cdata[j] = _trainLoader.LearnRows[i, j]; } //var y = batch.PredictCounts(cdata); var y = batch.PredictProba(cdata); string id = i.ToString(); if (!probDict.ContainsKey(id)) { probDict.Add(id, y[1]); } } return(probDict); }
private FinalFuncResult GetMetricsAccumulated(DecisionBatch cls, Dictionary <string, double> probSum, Dictionary <string, double> probAvg, Dictionary <string, int> resultDict, int nbcount, Func <DecisionBatch, Dictionary <string, double> > getResult ) { // получаем результат по одному классификатору var result = getResult(cls); // сохраняем общую сумму голостов по идентификатору // т.е. добавляем результат голосований от очередного классификатора cls foreach (string id in result.Keys) { if (!probSum.ContainsKey(id)) { probSum.Add(id, 0); } probSum[id] += result[id]; } // находим вероятности, деля количество голосов на количеств деревьев во всех классификаторах foreach (var id in probSum.Keys) { if (!probAvg.ContainsKey(id)) { probAvg.Add(id, 0); } probAvg[id] = probSum[id] / nbcount; } var rlist = new RocItem[resultDict.Count]; // массив для оценки результата // находим статистики классификации int idx = 0; foreach (string id in result.Keys) { if (rlist[idx] == null) { rlist[idx] = new RocItem(); } rlist[idx].Prob = probAvg[id]; // среднее по наблюдениям rlist[idx].Target = resultDict[id]; rlist[idx].Predicted = probAvg[id] > 0.5 ? 1 : 0; idx++; } Array.Sort(rlist, (o1, o2) => (1 - o1.Prob).CompareTo(1 - o2.Prob)); var clsRes = ResultCalc.GetResult(rlist, 0.05); return(clsRes); }
/// <summary> /// Расчет классификации по тестовому множеству на одном классификаторе /// ипользуется в GetTestSetMetrics /// </summary> /// <param name="batch"></param> /// <returns>Количество деревьев, проголосовавших за каждый класс</returns> private Dictionary <string, double> GetTestClassificationCounts(DecisionBatch batch) { var probDict = new Dictionary <string, double>(); // пробегаем по всем клиентски данным и сохраняем результат foreach (string id in _testDataDict.Keys) { //var y = batch.PredictCounts(_testDataDict[id]); var y = batch.PredictProba(_testDataDict[id]); if (!probDict.ContainsKey(id)) { probDict.Add(id, y[1]); } } return(probDict); }
/// <summary> /// Creates one classifier (batch of trees) /// </summary> /// <returns></returns> public static DecisionBatch CreateBatch(double[,] xy, int treesInBatch, int nclasses, double rfcoeff, double varscoeff, int[] idx, bool parallel, bool useLogit) { var batch = new DecisionBatch(); IEnumerable<int> source = Enumerable.Range(1, treesInBatch); List<DecisionTree> treeList; if (parallel) treeList = (from n in source.AsParallel() select DecisionTree.CreateTree(idx, xy, nclasses, rfcoeff, varscoeff) ).ToList(); else treeList = (from n in source select DecisionTree.CreateTree(idx, xy, nclasses, rfcoeff, varscoeff) ).ToList(); treeList.ForEach(batch.AddTree); CalcOutOfTheBagMetrics(treeList, xy, batch, useLogit); return batch; }
public static DecisionBatch Load(string path) { DecisionBatch cls = null; FileStream fs = null; try { fs = new FileStream(path, FileMode.Open, FileAccess.Read); var formatter = new BinaryFormatter(); cls = (DecisionBatch)formatter.Deserialize(fs); cls.Id = NCls++; } catch (Exception e) { Logger.Log(e); } finally { fs?.Close(); } return(cls); }
private static void CalcOutOfTheBagMetrics(List <DecisionTree> treeList, double[,] xy, DecisionBatch batch, bool useLogit) { var rdict = new Dictionary <int, int>(); foreach (var tree in treeList) { foreach (int id in tree.RowIndexes) { if (!rdict.ContainsKey(id)) { rdict.Add(id, 0); } rdict[id]++; } } int npoints = xy.GetLength(0); int nvars = xy.GetLength(1) - 1; int tnpoints = npoints - rdict.Count; var rlist = new RocItem[tnpoints]; // массив для оценки результата var ntrain = new double[tnpoints, batch.CountTreesInBatch + 1]; // массив для оценки результата double accCoeff = rdict.Count / (double)npoints; for (int i = 0, k = 0; i < npoints; i++) { if (rdict.ContainsKey(i)) { continue; } var tobj = new double[nvars]; for (int j = 0; j < nvars; j++) { tobj[j] = xy[i, j]; } rlist[k] = new RocItem(); double[] tprob = batch.PredictProba(tobj); rlist[k].Prob = tprob[1]; rlist[k].Predicted = tprob[1] > 0.5?1:0; rlist[k].Target = Convert.ToInt32(xy[i, nvars]); double[] bytree = batch.PredictByTree(tobj); for (int j = 0; j < batch.CountTreesInBatch; j++) { ntrain[k, j] = bytree[j]; } ntrain[k, batch.CountTreesInBatch] = xy[i, nvars]; k++; } Array.Sort(rlist, (o1, o2) => (1 - o1.Prob).CompareTo(1 - o2.Prob)); batch.OutBagEstimations = ResultCalc.GetResult(rlist, 0.05); if (useLogit) { int info; alglib.mnlreport rep; alglib.mnltrainh(ntrain, tnpoints, batch.CountTreesInBatch, 2, out info, out batch._logitModel, out rep); for (int i = 0, k = 0; i < npoints; i++) { if (rdict.ContainsKey(i)) { continue; } var tobj = new double[nvars]; for (int j = 0; j < nvars; j++) { tobj[j] = xy[i, j]; } rlist[k] = new RocItem(); double[] tprob = batch.PredictProba(tobj); rlist[k].Prob = tprob[1]; rlist[k].Predicted = tprob[1] > 0.5 ? 1 : 0; rlist[k].Target = Convert.ToInt32(xy[i, nvars]); k++; } Array.Sort(rlist, (o1, o2) => (1 - o1.Prob).CompareTo(1 - o2.Prob)); batch.OutBagEstimationsLogit = ResultCalc.GetResult(rlist, 0.05); } Logger.Log("train used: " + accCoeff + "; out_of_bag:" + batch.OutBagEstimations.AUC + "; out_of_bag_logit:" + batch.OutBagEstimationsLogit?.AUC); }
/// <summary> /// Полный расчет метрик качества классификации на тестовом множестве /// c учетом очередного классификатора /// </summary> /// <returns>Результат классификации</returns> private FinalFuncResult GetTrainMetricsAccumulated(DecisionBatch cls) { _nbTrain += UseBatchLogit ? 1 : cls.CountTreesInBatch; // обновляем общее кол-во деревьев return GetMetricsAccumulated(cls, _trainProbSum, _trainProbAvg, _trainResult, _nbTrain, GetTrainClassificationCounts); }
/// <summary> /// Расчет классификации по тестовому обучающему на одном классификаторе /// </summary> /// <param name="batch"></param> /// <returns>Количество деревьев, проголосовавших за каждый класс</returns> private Dictionary<string, double> GetTrainClassificationCounts(DecisionBatch batch) { var probDict = new Dictionary<string, double>(); int lines = _trainLoader.TotalDataLines; int vars = _trainLoader.NVars; // пробегаем по всем клиентски данным и сохраняем результат for (int i = 0; i < lines; i++) { var cdata = new double[vars]; for (int j = 0; j < vars; j++) cdata[j] = _trainLoader.LearnRows[i, j]; //var y = batch.PredictCounts(cdata); var y = batch.PredictProba(cdata); string id = i.ToString(); if (!probDict.ContainsKey(id)) probDict.Add(id, y[1]); } return probDict; }
/// <summary> /// Расчет классификации по тестовому множеству на одном классификаторе /// ипользуется в GetTestSetMetrics /// </summary> /// <param name="batch"></param> /// <returns>Количество деревьев, проголосовавших за каждый класс</returns> private Dictionary<string, double> GetTestClassificationCounts(DecisionBatch batch) { var probDict = new Dictionary<string, double>(); // пробегаем по всем клиентски данным и сохраняем результат foreach (string id in _testDataDict.Keys) { //var y = batch.PredictCounts(_testDataDict[id]); var y = batch.PredictProba(_testDataDict[id]); if (!probDict.ContainsKey(id)) probDict.Add(id, y[1]); } return probDict; }
private FinalFuncResult GetMetricsAccumulated(DecisionBatch cls, Dictionary<string, double> probSum, Dictionary<string, double> probAvg, Dictionary<string, int> resultDict, int nbcount, Func<DecisionBatch, Dictionary<string, double>> getResult ) { // получаем результат по одному классификатору var result = getResult(cls); // сохраняем общую сумму голостов по идентификатору // т.е. добавляем результат голосований от очередного классификатора cls foreach (string id in result.Keys) { if (!probSum.ContainsKey(id)) probSum.Add(id, 0); probSum[id] += result[id]; } // находим вероятности, деля количество голосов на количеств деревьев во всех классификаторах foreach (var id in probSum.Keys) { if (!probAvg.ContainsKey(id)) probAvg.Add(id, 0); probAvg[id] = probSum[id] / nbcount; } var rlist = new RocItem[resultDict.Count]; // массив для оценки результата // находим статистики классификации int idx = 0; foreach (string id in result.Keys) { if (rlist[idx] == null) rlist[idx] = new RocItem(); rlist[idx].Prob = probAvg[id]; // среднее по наблюдениям rlist[idx].Target = resultDict[id]; rlist[idx].Predicted = probAvg[id] > 0.5 ? 1 : 0; idx++; } Array.Sort(rlist, (o1, o2) => (1 - o1.Prob).CompareTo(1 - o2.Prob)); var clsRes = ResultCalc.GetResult(rlist, 0.05); return clsRes; }
private static void CalcOutOfTheBagMetrics(List<DecisionTree> treeList, double[,] xy, DecisionBatch batch, bool useLogit) { var rdict = new Dictionary<int, int>(); foreach (var tree in treeList) { foreach (int id in tree.RowIndexes) { if (!rdict.ContainsKey(id)) rdict.Add(id, 0); rdict[id]++; } } int npoints = xy.GetLength(0); int nvars = xy.GetLength(1) - 1; int tnpoints = npoints - rdict.Count; var rlist = new RocItem[tnpoints]; // массив для оценки результата var ntrain = new double[tnpoints, batch.CountTreesInBatch+1]; // массив для оценки результата double accCoeff = rdict.Count / (double)npoints; for (int i=0, k=0; i < npoints; i++) { if (rdict.ContainsKey(i)) continue; var tobj = new double[nvars]; for (int j = 0; j < nvars; j++) tobj[j] = xy[i, j]; rlist[k] = new RocItem(); double[] tprob = batch.PredictProba(tobj); rlist[k].Prob = tprob[1]; rlist[k].Predicted = tprob[1]>0.5?1:0; rlist[k].Target = Convert.ToInt32(xy[i, nvars]); double[] bytree = batch.PredictByTree(tobj); for (int j = 0; j < batch.CountTreesInBatch; j++) ntrain[k, j] = bytree[j]; ntrain[k, batch.CountTreesInBatch] = xy[i, nvars]; k++; } Array.Sort(rlist, (o1, o2) => (1 - o1.Prob).CompareTo(1 - o2.Prob)); batch.OutBagEstimations = ResultCalc.GetResult(rlist, 0.05); if (useLogit) { int info; alglib.mnlreport rep; alglib.mnltrainh(ntrain, tnpoints, batch.CountTreesInBatch, 2, out info, out batch._logitModel, out rep); for (int i = 0, k = 0; i < npoints; i++) { if (rdict.ContainsKey(i)) continue; var tobj = new double[nvars]; for (int j = 0; j < nvars; j++) tobj[j] = xy[i, j]; rlist[k] = new RocItem(); double[] tprob = batch.PredictProba(tobj); rlist[k].Prob = tprob[1]; rlist[k].Predicted = tprob[1] > 0.5 ? 1 : 0; rlist[k].Target = Convert.ToInt32(xy[i, nvars]); k++; } Array.Sort(rlist, (o1, o2) => (1 - o1.Prob).CompareTo(1 - o2.Prob)); batch.OutBagEstimationsLogit = ResultCalc.GetResult(rlist, 0.05); } Logger.Log("accCoeff: " + accCoeff + "; bag:" + batch.OutBagEstimations.AUC + "; logit:" + batch.OutBagEstimationsLogit?.AUC); }
/// <summary> /// Полный расчет метрик качества классификации на тестовом множестве /// c учетом очередного классификатора /// </summary> /// <returns>Результат классификации</returns> private FinalFuncResult GetTrainMetricsAccumulated(DecisionBatch cls) { _nbTrain += UseBatchLogit ? 1 : cls.CountTreesInBatch; // обновляем общее кол-во деревьев return(GetMetricsAccumulated(cls, _trainProbSum, _trainProbAvg, _trainResult, _nbTrain, GetTrainClassificationCounts)); }
/// <summary> /// build and test classifier /// </summary> public override ClassifierResult Build() { if (_trainLoader?.LearnRows == null) { throw new InvalidOperationException("train set is empty"); } Clear(); var ret = new ClassifierResult(); using (var sw = new StreamWriter(new FileStream("auchist.csv", FileMode.Create, FileAccess.Write))) { sw.WriteLine("time;n;train auc;test auc;stype"); // создаем первые классификаторы (first step) for (int i = 0; i < BatchesInFirstStep; i++) { DecisionBatch cls; if (IsLoadFirstStepBatches) { cls = DecisionBatch.Load(Environment.CurrentDirectory + "\\batches\\" + "batch_" + $"{i:0000.#}" + ".dmp"); if (cls == null) { cls = DecisionBatch.CreateBatch(_trainLoader.LearnRows, TreesInBatch, _nclasses, RfCoeff, VarsCoeff, null, IsParallel, UseBatchLogit); if (IsSaveTrees) { cls.Save(); } } } else { cls = DecisionBatch.CreateBatch(_trainLoader.LearnRows, TreesInBatch, _nclasses, RfCoeff, VarsCoeff, null, IsParallel, UseBatchLogit); if (IsSaveTrees) { cls.Save(); } } // расчитываем метрики для тестового и обучающего множества (накопленные) var testRes = GetTestMetricsAccumulated(cls); var trainRes = GetTrainMetricsAccumulated(cls); Logger.Log("batch=" + i + " ok; train AUC=" + trainRes.AUC.ToString("F10") + " test AUC = " + testRes.AUC.ToString("F10")); sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ";" + i + ";" + trainRes.AUC + ";" + testRes.AUC + ";none"); sw.Flush(); ret.AddStepResult(testRes, i); } // далее создаем классификаторы с учетом ошибки предыдущих (second step) int totalBatches = BatchesInFirstStep + BatchesInSecondStep; for (int i = BatchesInFirstStep; i < totalBatches; i++) { DecisionBatch bestBatch = null; // перестраиваем индексы плохо классифицированных объектов (плохие сначала) RefreshIndexes(); double bestMetric = double.MaxValue; // строим классификаторы и выбираем лучший for (int k = 0; k < BatchesInBruteForce; k++) { var scls = DecisionBatch.CreateBatch(_trainLoader.LearnRows, TreesInBatch, _nclasses, RfCoeff, VarsCoeff, _indexes, IsParallel, UseBatchLogit); // расчитываем метрики для тестового множества var trainCntRes = GetTrainClassificationCounts(scls); int cnt = UseBatchLogit ? 1 : scls.CountTreesInBatch; var rlist = new RocItem[_trainResult.Count]; // массив для оценки результата // находим статистики классификации int idx = 0; double accerr = 0.0; foreach (string id in _trainResult.Keys) { if (rlist[idx] == null) { rlist[idx] = new RocItem(); } rlist[idx].Prob = trainCntRes[id] / cnt; // среднее по наблюдениям rlist[idx].Target = _trainResult[id]; rlist[idx].Predicted = rlist[idx].Prob > 0.5 ? 1 : 0; //accerr += Math.Pow(rlist[idx].Prob - rlist[idx].Target, 2); idx++; } Array.Sort(rlist, (o1, o2) => (1 - o1.Prob).CompareTo(1 - o2.Prob)); var clsRes = ResultCalc.GetResult(rlist, 0.05); accerr = clsRes.LogLoss; Logger.Log("sub cls #" + k + " auc=" + clsRes.AUC.ToString("F10") + " eps=" + accerr + (accerr < bestMetric ? " [best]" : "")); if (accerr < bestMetric) { bestMetric = accerr; bestBatch = scls; } } var testRes = GetTestMetricsAccumulated(bestBatch); var trainRes = GetTrainMetricsAccumulated(bestBatch); if (IsSaveTrees) { if (bestBatch != null) { bestBatch.Save(); } else { Logger.Log("best Batch is null"); } } ret.AddStepResult(testRes, i); Logger.Log("batch=" + i + " ok; train AUC=" + trainRes.AUC.ToString("F10") + "; test AUC = " + testRes.AUC.ToString("F10")); sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ";" + i + ";" + trainRes.AUC + ";" + testRes.AUC + ";" + IndexSortOrder); sw.Flush(); } sw.Close(); } return(ret); }