Browse Source

Merge pull request #251 from kparrigan/jaccard

Jaccard Distance
pull/252/head
Christoph Ruegg 12 years ago
parent
commit
ea37efe082
  1. 92
      src/Numerics/Distance.cs
  2. 67
      src/UnitTests/DistanceTests.cs

92
src/Numerics/Distance.cs

@ -388,5 +388,97 @@ namespace MathNet.Numerics
{
return 1.0 - Correlation.Pearson(a, b);
}
/// <summary>
/// Jaccard distance, i.e. 1 - the Jaccard index.
/// </summary>
/// <exception cref="ArgumentNullException">Thrown if a or b are null.</exception>
/// <exception cref="ArgumentException">Throw if a and b are of different lengths.</exception>
/// <returns>Jaccard distance.</returns>
public static double Jaccard(double[] a, double[] b)
{
Int32 intersection = 0, union = 0;
if (a == null)
{
throw new ArgumentNullException("a");
}
if (b == null)
{
throw new ArgumentNullException("b");
}
if (a.Length != b.Length)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
}
if ((a.Length == 0 && b.Length == 0) || (a == null && b == null))
{
return 0;
}
for (Int32 x = 0, len = a.Length; x < len; x++)
{
if (a[x] != 0 && b[x] != 0)
{
if (a[x] == b[x])
{
intersection++;
}
union++;
}
}
return 1.0 - ((double)intersection / (double)union);
}
/// <summary>
/// Jaccard distance, i.e. 1 - the Jaccard index.
/// </summary>
/// <exception cref="ArgumentNullException">Thrown if a or b are null.</exception>
/// <exception cref="ArgumentException">Throw if a and b are of different lengths.</exception>
/// <returns>Jaccard distance.</returns>
public static double Jaccard(float[] a, float[] b)
{
Int32 intersection = 0, union = 0;
if (a == null)
{
throw new ArgumentNullException("a");
}
if (b == null)
{
throw new ArgumentNullException("b");
}
if (a.Length != b.Length)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
}
if ((a.Length == 0 && b.Length == 0) || (a == null && b == null))
{
return 0;
}
for (Int32 x = 0, len = a.Length; x < len; x++)
{
if (a[x] != 0 && b[x] != 0)
{
if (a[x] == b[x])
{
intersection++;
}
union++;
}
}
return 1.0 - ((float)intersection / (float)union);
}
}
}

67
src/UnitTests/DistanceTests.cs

@ -1,4 +1,5 @@
using NUnit.Framework;
using System;
namespace MathNet.Numerics.UnitTests
{
@ -15,5 +16,71 @@ namespace MathNet.Numerics.UnitTests
Assert.That(Distance.Hamming(new[] { 0.0, 0.0 }, new[] { 1.0, 1.0 }), Is.EqualTo(2.0));
Assert.That(Distance.Hamming(new[] { 1.0, 0.0 }, new[] { 0.0, 1.0 }), Is.EqualTo(2.0));
}
[Test]
public void Jaccard_Double()
{
double[] p0 = new double[] { 1, 0.5 };
double[] q0 = new double[] { 0.5, 1 };
double[] p1 = new double[] { 4.5, 1 };
double[] q1 = new double[] { 4, 2 };
double[] p2 = new double[] { 0, 0, 0 };
double[] q2 = new double[] { 0, 0, 0 };
double[] p3 = new double[] { 1, 1, 1 };
double[] q3 = new double[] { 1, 1, 1 };
double[] p4 = new double[] { 2.5, 3.5, 3.0, 3.5, 2.5, 3.0 };
double[] q4 = new double[] { 3.0, 3.5, 1.5, 5.0, 3.5, 3.0 };
double[] p5 = new double[] { 1, 3, 5, 6, 8, 9, 6, 4, 3, 2 };
double[] q5 = new double[] { 2, 5, 6, 6, 7, 7, 5, 3, 1, 1 };
Assert.Throws<ArgumentException>(() => Distance.Jaccard(p0, q4));
Assert.Throws<ArgumentNullException>(() => Distance.Jaccard(null, q4));
Assert.Throws<ArgumentNullException>(() => Distance.Jaccard(p0, null));
Assert.That(Distance.Jaccard(p0, q0), Is.EqualTo(1));
Assert.That(Distance.Jaccard(p1, q1), Is.EqualTo(1));
Assert.That(Distance.Jaccard(p2, q2), Is.EqualTo(Double.NaN));
Assert.That(Distance.Jaccard(p3, q3), Is.EqualTo(0));
Assert.That(Distance.Jaccard(p4, q4), Is.EqualTo(0.66666).Within(0.00001));
Assert.That(Distance.Jaccard(p5, q5), Is.EqualTo(0.9).Within(0.1));
}
[Test]
public void Jaccard_Float()
{
float[] p0 = new float[] { 1, 0.5f };
float[] q0 = new float[] { 0.5f, 1 };
float[] p1 = new float[] { 4.5f, 1 };
float[] q1 = new float[] { 4, 2 };
float[] p2 = new float[] { 0, 0, 0 };
float[] q2 = new float[] { 0, 0, 0 };
float[] p3 = new float[] { 1, 1, 1 };
float[] q3 = new float[] { 1, 1, 1 };
float[] p4 = new float[] { 2.5f, 3.5f, 3.0f, 3.5f, 2.5f, 3.0f };
float[] q4 = new float[] { 3.0f, 3.5f, 1.5f, 5.0f, 3.5f, 3.0f };
float[] p5 = new float[] { 1, 3, 5, 6, 8, 9, 6, 4, 3, 2 };
float[] q5 = new float[] { 2, 5, 6, 6, 7, 7, 5, 3, 1, 1 };
Assert.Throws<ArgumentException>(() => Distance.Jaccard(p0, q4));
Assert.Throws<ArgumentNullException>(() => Distance.Jaccard(null, q4));
Assert.Throws<ArgumentNullException>(() => Distance.Jaccard(p0, null));
Assert.That(Distance.Jaccard(p0, q0), Is.EqualTo(1));
Assert.That(Distance.Jaccard(p1, q1), Is.EqualTo(1));
Assert.That(Distance.Jaccard(p2, q2), Is.EqualTo(float.NaN));
Assert.That(Distance.Jaccard(p3, q3), Is.EqualTo(0));
Assert.That(Distance.Jaccard(p4, q4), Is.EqualTo(0.66666).Within(0.00001));
Assert.That(Distance.Jaccard(p5, q5), Is.EqualTo(0.9).Within(0.1));
}
}
}

Loading…
Cancel
Save