#region License Information /* HeuristicLab * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using HeuristicLab.Core.Views; using HeuristicLab.Data; using HeuristicLab.MainForm; using HeuristicLab.Optimization; using HeuristicLab.Optimization.Views; namespace HeuristicLab.Analysis.Statistics { [View("RunCollection Statistical Testing")] [Content(typeof(RunCollection), false)] public sealed partial class StatisticalTestingView : ItemView { private double[][] data; public StatisticalTestingView() { InitializeComponent(); } public new RunCollection Content { get { return (RunCollection)base.Content; } set { base.Content = value; } } public override bool ReadOnly { get { return true; } set { /*not needed because results are always readonly */} } protected override void OnContentChanged() { base.OnContentChanged(); if (Content != null) { UpdateResultComboBox(); UpdateGroupsComboBox(); FillCompComboBox(); RebuildDataTable(); } } #region events protected override void RegisterContentEvents() { base.RegisterContentEvents(); } protected override void DeregisterContentEvents() { base.DeregisterContentEvents(); } #endregion private void UpdateGroupsComboBox() { groupComboBox.Items.Clear(); var parameters = (from run in Content where run.Visible from param in run.Parameters select param.Key).Distinct().ToArray(); foreach (var p in parameters) { var variations = (from run in Content where run.Visible && run.Parameters.ContainsKey(p) && (run.Parameters[p] is IntValue || run.Parameters[p] is DoubleValue || run.Parameters[p] is StringValue || run.Parameters[p] is BoolValue) select ((dynamic)run.Parameters[p]).Value).Distinct(); if (variations.Count() > 1) { groupComboBox.Items.Add(p); } } if (groupComboBox.Items.Count > 0) { //try to select something different than "Seed" or "Algorithm Name" as this makes no sense //and takes a long time to group List possibleIndizes = new List(); for (int i = 0; i < groupComboBox.Items.Count; i++) { if (groupComboBox.Items[i].ToString() != "Seed" && groupComboBox.Items[i].ToString() != "Algorithm Name") { possibleIndizes.Add(i); } } if (possibleIndizes.Count > 0) { groupComboBox.SelectedItem = groupComboBox.Items[possibleIndizes.First()]; } else { groupComboBox.SelectedItem = groupComboBox.Items[0]; } } } private string[] GetColumnNames(IEnumerable runs) { string parameterName = (string)groupComboBox.SelectedItem; var r = runs.Where(x => x.Parameters.ContainsKey(parameterName)); return r.Select(x => ((dynamic)x.Parameters[parameterName]).Value).Distinct().Select(x => (string)x.ToString()).ToArray(); } private void UpdateResultComboBox() { resultComboBox.Items.Clear(); var results = (from run in Content where run.Visible from result in run.Results where result.Value is IntValue || result.Value is DoubleValue select result.Key).Distinct().ToArray(); resultComboBox.Items.AddRange(results); if (resultComboBox.Items.Count > 0) resultComboBox.SelectedItem = resultComboBox.Items[0]; } private void FillCompComboBox() { string parameterName = (string)groupComboBox.SelectedItem; if (parameterName != null) { string resultName = (string)resultComboBox.SelectedItem; if (resultName != null) { var runs = Content.Where(x => x.Results.ContainsKey(resultName) && x.Visible); var columnNames = GetColumnNames(runs).ToList(); groupCompComboBox.Items.Clear(); columnNames.ForEach(x => groupCompComboBox.Items.Add(x)); if (groupCompComboBox.Items.Count > 0) groupCompComboBox.SelectedItem = groupCompComboBox.Items[0]; } } } private void RebuildDataTable() { string parameterName = (string)groupComboBox.SelectedItem; if (parameterName != null) { string resultName = (string)resultComboBox.SelectedItem; var runs = Content.Where(x => x.Results.ContainsKey(resultName) && x.Visible); var columnNames = GetColumnNames(runs); var groups = GetGroups(columnNames, runs); data = new double[columnNames.Count()][]; DoubleMatrix dt = new DoubleMatrix(groups.Select(x => x.Count()).Max(), columnNames.Count()); dt.ColumnNames = columnNames; int i = 0; int j = 0; foreach (string columnName in columnNames) { j = 0; data[i] = new double[groups[i].Count()]; foreach (IRun run in groups[i]) { dt[j, i] = (double)((dynamic)run.Results[resultName]).Value; data[i][j] = dt[j, i]; j++; } i++; } stringConvertibleMatrixView.Content = dt; } } private List> GetGroups(string[] columnNames, IEnumerable runs) { List> runCols = new List>(); string parameterName = (string)groupComboBox.SelectedItem; foreach (string cn in columnNames) { var tmpRuns = runs.Where(x => ((string)((dynamic)x.Parameters[parameterName]).Value.ToString()) == cn); runCols.Add(tmpRuns); } return runCols; } private void ResetUI() { normalityLabel.Image = null; groupCompLabel.Image = null; pairwiseLabel.Image = null; pValTextBox.Text = string.Empty; equalDistsTextBox.Text = string.Empty; } private void testButton_Click(object sender, EventArgs e) { double pval = KruskalWallis.Test(data); pValTextBox.Text = pval.ToString(); if (pval < 0.05) { groupCompLabel.Image = HeuristicLab.Analysis.Statistics.Resources.Default; } else { groupCompLabel.Image = HeuristicLab.Common.Resources.VSImageLibrary.Warning; } } private void normalDistButton_Click(object sender, EventArgs e) { double val; List res = new List(); for (int i = 0; i < data.Length; i++) { alglib.jarqueberatest(data[i], data[i].Length, out val); res.Add(val); } for (int i = 0; i < res.Count(); i++) { if (res[i] < 0.1) { normalityLabel.Image = HeuristicLab.Common.Resources.VSImageLibrary.Warning; } else { normalityLabel.Image = HeuristicLab.Analysis.Statistics.Resources.Default; } } } private void resultComboBox_SelectedValueChanged(object sender, EventArgs e) { RebuildDataTable(); ResetUI(); } private void groupComboBox_SelectedValueChanged(object sender, EventArgs e) { FillCompComboBox(); RebuildDataTable(); ResetUI(); } private void normalityDetails_Click(object sender, EventArgs e) { DoubleMatrix pValsMatrix = new DoubleMatrix(1, stringConvertibleMatrixView.Content.Columns); pValsMatrix.ColumnNames = stringConvertibleMatrixView.Content.ColumnNames; pValsMatrix.RowNames = new string[] { "p-Value" }; double val; for (int i = 0; i < data.Length; i++) { alglib.jarqueberatest(data[i], data[i].Length, out val); pValsMatrix[0, i] = val; } MainFormManager.MainForm.ShowContent(pValsMatrix); } private void pairwiseTestButton_Click(object sender, EventArgs e) { string curItem = (string)groupCompComboBox.SelectedItem; int colIndex = 0; foreach (string col in stringConvertibleMatrixView.Content.ColumnNames) { if (col == curItem) { break; } colIndex++; } DoubleMatrix pValsMatrix = new DoubleMatrix(5, stringConvertibleMatrixView.Content.Columns); pValsMatrix.ColumnNames = stringConvertibleMatrixView.Content.ColumnNames; pValsMatrix.RowNames = new string[] { "p-Value of Mann-Whitney U", "p-Value of T-Test", "Necessary Sample Size for T-Test", "Cohen's d", "Hedges' g" }; double mwuBothtails; double mwuLefttail; double mwuRighttail; double ttestLefttail; for (int i = 0; i < data.Length; i++) { alglib.mannwhitneyutest(data[colIndex], data[colIndex].Length, data[i], data[i].Length, out mwuBothtails, out mwuLefttail, out mwuRighttail); ttestLefttail = TTest.Test(data[colIndex], data[i]); pValsMatrix[0, i] = mwuBothtails; pValsMatrix[1, i] = ttestLefttail; pValsMatrix[2, i] = TTest.GetOptimalSampleSize(data[colIndex], data[i]); pValsMatrix[3, i] = SampleSizeDetermination.CalculateCohensD(data[colIndex], data[i]); pValsMatrix[4, i] = SampleSizeDetermination.CalculateHedgesG(data[colIndex], data[i]); } MainFormManager.MainForm.ShowContent(pValsMatrix); } private void infoLabel_DoubleClick(object sender, EventArgs e) { using (InfoBox dialog = new InfoBox("Description of Statistical Tests", typeof(StatisticalTestingView).Namespace + ".InfoResources.StatisticalTestsInfo.rtf")) { dialog.ShowDialog(this); } } private void openBoxPlotToolStripMenuItem_Click(object sender, EventArgs e) { RunCollectionBoxPlotView boxplotView = new RunCollectionBoxPlotView(); boxplotView.Content = Content; // TODO: enable as soon as we move to HeuristicLab.Optimization.Views // boxplotView.xAxisComboBox.SelectedItem = xAxisComboBox.SelectedItem; // boxplotView.yAxisComboBox.SelectedItem = yAxisComboBox.SelectedItem; boxplotView.Show(); } private void pairwiseCheckDataButton_Click(object sender, EventArgs e) { string curItem = (string)groupCompComboBox.SelectedItem; int colIndex = 0; foreach (string col in stringConvertibleMatrixView.Content.ColumnNames) { if (col == curItem) { break; } colIndex++; } double mwuBothtails; double mwuLefttail; double mwuRighttail; int cnt = 0; for (int i = 0; i < data.Length; i++) { if (i != colIndex) { alglib.mannwhitneyutest(data[colIndex], data[colIndex].Length, data[i], data[i].Length, out mwuBothtails, out mwuLefttail, out mwuRighttail); if (mwuBothtails > 0.05) { cnt++; } } } double ratio = ((double)cnt) / (data.Length - 1) * 100.0; equalDistsTextBox.Text = ratio.ToString() + " %"; if (cnt == 0) { pairwiseLabel.Image = HeuristicLab.Analysis.Statistics.Resources.Default; } else { pairwiseLabel.Image = HeuristicLab.Common.Resources.VSImageLibrary.Warning; } } } }