using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; namespace F_measure_test { class Program { static void GetMaxMatrixElement(double[,] matrix, int size, ref int row, ref int col) { row = 0; col = 0; double max = matrix[row, col]; for (int i = 0; i < size; ++i) { for (int j = 0; j < size; ++j) { if (matrix[i, j] > max) { row = i; col = j; max = matrix[i, j]; } } } } static double formula(double recall, double precision) { if (recall <= 0.0 && precision <= 0.0) return 0.0; else return (2.0 * recall * precision / (recall + precision)); } static double Compute_F_Measure(int[] expectedCats, int[] actualCats, bool showMatrix) { double f_measure = -1.0; //Verification of passed data. if (expectedCats.Length != actualCats.Length) { Console.WriteLine("Error, the sizes of expected and actual data arrays mismatch."); return f_measure; } int min = expectedCats[0]; int max = expectedCats[0]; foreach (int x in expectedCats) { if (x < min) min = x; if (x > max) max = x; } if (min != 0) { Console.WriteLine("Error, minimum value of expected category should be 0."); return f_measure; } int[] contentTest = new int[max + 1]; for (int i = 0; i < max + 1; ++i) { contentTest[i] = 0; } foreach (int x in expectedCats) { ++contentTest[x]; } foreach (int x in contentTest) { if (x == 0) { Console.WriteLine("Error, expected categories should be in contiguous range 0 to max."); return f_measure; } } foreach (int x in actualCats) { if (x < min || x > max) { Console.WriteLine("Error, range for actual categories is different from expected."); return f_measure; } } //End of verification of passed data. int size = max + 1; double[,] matrix = new double[size, size]; for (int i = 0; i < size; ++i) { for (int j = 0; j < size; ++j) { matrix[i, j] = 0.0; } } for (int i = 0; i < size; ++i) { for (int j = 0; j < expectedCats.Length; ++j) { if (expectedCats[j] == i) { matrix[i, actualCats[j]] += 1.0; } } } double[] totalInRows = new double[size]; double[] totalInCols = new double[size]; for (int i = 0; i < size; ++i) { totalInRows[i] = 0.0; totalInCols[i] = 0.0; } for (int i = 0; i < size; ++i) { for (int j = 0; j < size; ++j) { totalInRows[i] += matrix[i, j]; } } for (int j = 0; j < size; ++j) { for (int i = 0; i < size; ++i) { totalInCols[j] += matrix[i, j]; } } for (int i = 0; i < size; ++i) { for (int j = 0; j < size; ++j) { double recall = 0.0; double precision = 0.0; if (totalInRows[i] > 0.0) recall = matrix[i, j] / totalInRows[i]; if (totalInCols[j] > 0.0) precision = matrix[i, j] / totalInCols[j]; matrix[i, j] = formula(recall, precision); } } int[] lookup = new int[size]; double[] fm = new double[size]; for (int counter = 0; counter < size; ++counter) { int row = -1; int col = -1; GetMaxMatrixElement(matrix, size, ref row, ref col); lookup[col] = row; fm[row] = matrix[row, col]; for (int i = 0; i < size; ++i) matrix[row, i] = -1.0; for (int j = 0; j < size; ++j) matrix[j, col] = -1.0; } for (int i = 0; i < actualCats.Length; ++i) { actualCats[i] = lookup[actualCats[i]]; } f_measure = 0.0; for (int i = 0; i < size; ++i) { f_measure += fm[i]; } f_measure /= (double)(size); if (showMatrix) { for (int i = 0; i < size; ++i) { for (int j = 0; j < size; ++j) { matrix[i, j] = 0.0; } } for (int i = 0; i < size; ++i) { for (int j = 0; j < expectedCats.Length; ++j) { if (expectedCats[j] == i) { matrix[i, actualCats[j]] += 1.0; } } } Console.WriteLine("The matrix of actual results"); Console.WriteLine("The correctly recognized categories are shown on the main diagonal\n"); for (int i = 0; i < size; ++i) { for (int j = 0; j < size; ++j) { Console.Write(" {0} ", matrix[i, j]); } Console.WriteLine(); } Console.WriteLine(); } return f_measure; } static void Main(string[] args) { int[] expectedCats = { 2, 1, 0, 0, 0, 1, 4, 4, 3, 2, 0, 1 }; //int[] actualCats = { 2, 3, 4, 4, 4, 3, 0, 0, 1, 2, 4, 3 }; int[] actualCats = { 0, 0, 1, 3, 4, 0, 1, 1, 2, 2, 4, 1 }; double f_measure = Compute_F_Measure(expectedCats, actualCats, true); if (f_measure >= 0.0) { Console.WriteLine("Expected and reassigned actual categories:"); foreach (int x in expectedCats) { Console.Write(" {0} ", x); } Console.WriteLine(); foreach (int x in actualCats) { Console.Write(" {0} ", x); } Console.WriteLine('\n'); Console.WriteLine("F-measure {0}", f_measure); Console.WriteLine(); } } } }