// an extra randomness reduction was helpful; see http://neuralsniffer.wordpress.com/2010/12/13/combining-the-3-inputs-1-black-box-or-3-black-boxes-with-confidence/ public double GetEnsembleRepeatForecast(int p_nEnsembleRepeat, EnsembleGroupSetup[] p_ensembleGroups, EnsembleAggregationStrategy p_ensembleAggregation, int p_maxEpoch, int p_iRebalance, int p_lookbackWindowSize, double p_outputOutlierThreshold, double p_inputOutlierClipInSD, double p_inputNormalizationBoost, double p_outputNormalizationBoost, int p_notNNStrategyType, double[] p_dateWeekDays, double[] p_barChanges, bool p_isLogForecast, out double p_avgTrainError) { double[] forecasts = new double[p_nEnsembleRepeat]; double[] trainErrors = new double[p_nEnsembleRepeat]; for (int i = 0; i < forecasts.Length; i++) { double trainError = Double.NaN; forecasts[i] = GetEnsembleForecast(p_ensembleGroups, p_ensembleAggregation, p_maxEpoch, p_iRebalance, p_lookbackWindowSize, p_outputOutlierThreshold, p_inputOutlierClipInSD, p_inputNormalizationBoost, p_outputNormalizationBoost, p_notNNStrategyType, p_dateWeekDays, p_barChanges, p_isLogForecast, out trainError); trainErrors[i] = trainError; } p_avgTrainError = trainErrors.Average(); if (p_isLogForecast) Utils.Logger.Info("Forecast%: GetEnsembleRepeatForecast(): " + String.Concat(forecasts.Select(r => (r * 100).ToString("F4") + "%,").ToArray())); return forecasts.Select(r => Math.Sign(r)).Sum(); }
double GetEnsembleForecast(EnsembleGroupSetup[] p_ensembleGroups, EnsembleAggregationStrategy p_ensembleAggregation, int p_maxEpoch, int p_iRebalance, int p_lookbackWindowSize, double p_outputOutlierThreshold, double p_inputOutlierClipInSD, double p_inputNormalizationBoost, double p_outputNormalizationBoost, int p_notNNStrategyType, double[] p_dateWeekDays, double[] p_barChanges, bool p_isLogForecast, out double p_avgTrainError) { List<double>[] forecasts = new List<double>[p_ensembleGroups.Length]; List<double>[] trainErrors = new List<double>[p_ensembleGroups.Length]; for (int i = 0; i < p_ensembleGroups.Length; i++) { EnsembleGroupSetup group = p_ensembleGroups[i]; forecasts[i] = new List<double>(); trainErrors[i] = new List<double>(); //PrepareMemberForecast(); TODO: prepare input/output only once int nMembersInGroup = group.NensembleGroupMembers; for (int m = 0; m < nMembersInGroup; m++) { double trainError = Double.NaN; forecasts[i].Add(GetMemberForecast(group.NNInputDesc, group.Nneurons, p_maxEpoch, p_iRebalance, p_lookbackWindowSize, group.BarChangeLookbackDaysInds, p_outputOutlierThreshold, p_inputOutlierClipInSD, p_inputNormalizationBoost, p_outputNormalizationBoost, p_notNNStrategyType, p_dateWeekDays, p_barChanges, out trainError)); trainErrors[i].Add(trainError); } if (p_isLogForecast) Utils.Logger.Info("Forecast%: GetEnsembleForecast(): " + String.Concat(forecasts[i].Select(r => (r * 100).ToString("F4") + "%,").ToArray())); } int nTotalMember = p_ensembleGroups.Select(r => r.NensembleGroupMembers).Sum(); StrongAssert.True(nTotalMember > 0 && p_ensembleGroups.Length != 0); p_avgTrainError = trainErrors.Select(r => r.Sum()).Sum() / (double)nTotalMember; switch (p_ensembleAggregation) // instead of returning Sum(), return SIGN(Sum()), because the Meta mechanism will repeat this thing again: OK; we don't need; the Meta will take the Sign() at first { case EnsembleAggregationStrategy.ReturnTheFirstForecast: return forecasts[0][0]; case EnsembleAggregationStrategy.SumSignForecasts: return forecasts.Select(r => r.Select(p => Math.Sign(p)).Sum()).Sum(); // SumSign() has lowest STD in the end than Avg() (I measured it) case EnsembleAggregationStrategy.AvgForecasts: return forecasts.Select(r => r.Sum()).Sum() / (double)nTotalMember; case EnsembleAggregationStrategy.PlayOnlyIfAllMemberAgree: { int nPosForecasts = forecasts.Select(r => r.Count(p => p > 0)).Sum(); int nNegForecasts = forecasts.Select(r => r.Count(p => p < 0)).Sum(); StrongAssert.True(nPosForecasts + nNegForecasts <= nTotalMember); if (nPosForecasts == nTotalMember || nNegForecasts == nTotalMember) // we asserted that nTotalMember != 0 return forecasts.Select(r => r.Sum()).Sum() / (double)nTotalMember; // % average is OK, because they are the same sign else return 0; // if sign differs, go to cash } case EnsembleAggregationStrategy.PlayOnlyIfAllGroupAgree_onGroupSumSign: // if sign differs, go to cash { int nPosGroupForecasts = forecasts.Select(r => r.Select(p => Math.Sign(p)).Sum()).Count(k => k > 0); int nNegGroupForecasts = forecasts.Select(r => r.Select(p => Math.Sign(p)).Sum()).Count(k => k < 0); StrongAssert.True(nPosGroupForecasts + nNegGroupForecasts <= p_ensembleGroups.Length); if (nPosGroupForecasts == p_ensembleGroups.Length || nNegGroupForecasts == p_ensembleGroups.Length) // we asserted that p_ensembleGroups.Length != 0 return forecasts[0].Select(r => Math.Sign(r)).Sum(); // % the groups are the same sign. Return the first group sign; no point averaging the SumSign values; if 5 items gives negative, it will return '-5' else return 0; // if sign differs, go to cash } default: throw new NotImplementedException(); } throw new NotImplementedException(); }