/// <summary> /// Перестройка индексов для определения объектов, которые плохо классифицтрованы /// </summary> private void RefreshIndexes() { int rowsCnt = _trainResult.Count; // находим разницы между реальными значениями и прогнозными в train-set _errors = new Dictionary<string, double>(); var rlist = new RocItem[rowsCnt]; // массив для оценки результата double sumdiff = 0; int i = 0; foreach (var k in _trainResult.Keys) { double tprob = _trainProbAvg[k]; int targ = _trainResult[k]; double diff = Math.Abs(tprob - targ); sumdiff += diff; _errors.Add(k, diff); rlist[i] = new RocItem(); rlist[i].Prob = tprob; rlist[i].Target = targ; rlist[i].Predicted = tprob > 0.5 ? 1 : 0; i++; } Array.Sort(rlist, (o1, o2) => (1 - o1.Prob).CompareTo(1 - o2.Prob)); var clres = ResultCalc.GetResult(rlist, 0.05); Logger.Log("cl auc=" + clres.AUC.ToString("F10") + "; loss=" + clres.LogLoss.ToString("F10") + "; sumdiff=" + sumdiff); // сортируем индексы KeyValuePair<string, double>[] sarr = null; if (IndexSortOrder==null || (IndexSortOrder.ToLower()!="desc" && IndexSortOrder.ToLower()!="asc")) { sarr = new KeyValuePair<string, double>[rowsCnt]; for (int l=0;l<sarr.Length;l++) sarr[l] = new KeyValuePair<string, double>(l.ToString(), l); } else { if (IndexSortOrder.ToLower() == "desc") { sarr = _errors.OrderByDescending(t => t.Value).ToArray(); int outliersCnt = (int)(sarr.Length * OutliersPrct); for (int s = 0; s < outliersCnt; s++) sarr[s] = new KeyValuePair<string, FType>(sarr[s].Key, -1); sarr = sarr.OrderByDescending(t => t.Value).ToArray(); } if (IndexSortOrder.ToLower() == "asc") sarr = _errors.OrderBy(t => t.Value).ToArray(); } _indexes = new int[rowsCnt]; i = 0; if (sarr == null) { Logger.Log("sarr is null"); return; } foreach (var kvp in sarr) _indexes[i++] = Convert.ToInt32(double.Parse(kvp.Key)); }
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> /// 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 *= (1 - clsRes.AUC); 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; }
public override ClassifierResult Build() { //For this example (and indeed, many scenarios), the default //parameters will suffice. Parameter parameters = new Parameter(); double C; double Gamma; //This will do a grid optimization to find the best parameters //and store them in C and Gamma, outputting the entire //search to params.txt. ParameterSelection.Grid(_trainProblem, parameters, "params.txt", out C, out Gamma); parameters.C = C; parameters.Gamma = Gamma; //Train the model using the optimal parameters. _model = Training.Train(_trainProblem, parameters); // пробегаем по всем клиентски данным и сохраняем результат var probDictList = new Dictionary<string, Dictionary<int, double>>(); foreach (string id in _testDataDict.Keys) { if (!probDictList.ContainsKey(id)) probDictList.Add(id, new Dictionary<int, double>()); foreach (var sarr in _testDataDict[id]) { var y = PredictProba(sarr); double prob = y.Probs[1]; int kmax = probDictList[id].Keys.Count == 0 ? 0 : probDictList[id].Keys.Max() + 1; probDictList[id].Add(kmax, prob); } } // вероятность дефолта определяется как среднее по записям для клиента var probDict = new Dictionary<string, double>(); foreach (var id in probDictList.Keys) { int cnt = probDictList[id].Keys.Count(); double prob = 0; foreach (var d in probDictList[id].Keys) { prob += probDictList[id][d]; } if (!probDict.ContainsKey(id)) probDict.Add(id, prob / cnt); } // находим статистики классификации var rlist = new RocItem[_resultDict.Count]; // массив для оценки результата int idx = 0; foreach (string id in probDict.Keys) { if (rlist[idx] == null) rlist[idx] = new RocItem(); rlist[idx].Prob = probDict[id]; // среднее по наблюдениям rlist[idx].Target = _resultDict[id]; rlist[idx].Predicted = 0; idx++; } Array.Sort(rlist, (o1, o2) => (1 - o1.Prob).CompareTo(1 - o2.Prob)); var cres = ResultCalc.GetResult(rlist, 0.05); var clsRes = new ClassifierResult(); clsRes.BestResult = cres; clsRes.LastResult = cres; clsRes.ResDict.Add(0, cres); return clsRes; }