두 시퀀스를 비교하는 알고리즘을 찾고 있습니다.두 목록 간의 순서 차이를 평가하는 알고리즘
시퀀스 A -
시퀀스 B 최적 위해 정수 ID 목록 것 - 다를 수 순서로 동일한 ID 목록 것이다.
두 목록 간의 순서 차이를 감지하고 싶습니다.
그리고 이와 같이 알고리즘을 찾고 있습니다. 이것이 당신이 단지 그들이 얼마나 다른을 측정 할 경우
두 시퀀스를 비교하는 알고리즘을 찾고 있습니다.두 목록 간의 순서 차이를 평가하는 알고리즘
시퀀스 A -
시퀀스 B 최적 위해 정수 ID 목록 것 - 다를 수 순서로 동일한 ID 목록 것이다.
두 목록 간의 순서 차이를 감지하고 싶습니다.
그리고 이와 같이 알고리즘을 찾고 있습니다. 이것이 당신이 단지 그들이 얼마나 다른을 측정 할 경우
전에 해결 된 일반적인 문제 있는지 궁금하고 있지만, 차이가 발생하는 경우, 당신은 Kendall's correlation coefficient를 사용할 수 있습니다 당신은 상관하지 않습니다. 그것은 -1 점 (목록은 역순)에서 +1 점 (목록은 같은 순서 임)의 점수를줍니다.
int[] a = { 1, 2, 3, 4, 5, 6, 7, 8 };
int[] b = { 3, 4, 1, 8, 6, 7, 2, 5 };
double numer = 0;
for (int i = 0; i < (a.Length - 1); i++)
for (int j = i + 1; j < a.Length; j++)
numer += Math.Sign(a[i] - a[j]) * Math.Sign(b[i] - b[j]);
double tau = numer/(a.Length * (a.Length - 1)/2);
이것은 Kendall Tau-a 인 것으로 보입니다. 데이터의 순위가 동등한 항목 (항목이 고유하지 않기 때문에)이있는 경우 Kendall tau-b를 사용해야하며, 이는 넥타이를 설명하지만 더 복잡합니다. https://en.wikipedia.org/wiki/Kendall_rank_correlation_coefficient를 참조하십시오. –
줄리안 URBANO가 제안한 것처럼, 켄달 타우 상관 관계가 좋다 :
그것은 기본적으로 쌍 총 수에 의해 두 목록의 순서에있는 요소 쌍의 수와 격차를 계산 사용할 측정. Linq를 사용하여 .Net에서 구현하기로 결정했습니다. Tau-A (넥타이가없는 데이터의 경우)와 Tau-B (넥타이가 허용되는 경우)를 구현하는 코드는 다음과 같습니다. 이 코드에서는 데이터가 아직 정렬되지 않았다고 가정하므로 Measure1에 따라 Measure1에 따라 한 번 정렬하여 순위 값의 첫 번째 집합을 가져온 다음 Measure2로 정렬하여 두 번째 순위 집합을 가져옵니다. 원래 데이터가 아닌 상관 관계가있는 순위입니다. (측정 람다 함수가 변경되지 않은 원래의 객체를 돌려주는 경우, 당신은 당신이 이미 가지고있는 계급에 적용 할 수 있습니다.) 여기
using System;
using System.Collections.Generic;
using System.Linq;
using static System.Math;
namespace Statistics
{
/// <summary>
/// Compute the Kendall Tau Correlation of two orderings of values, a non-parametric correlation that compares the ranking
/// of value, not the values themselves.
///
/// The correlation of the measures is one if all values are in the same order when sorted by two different measures.
/// The correlation is minus one if the second ordering is the reverse of the first.
/// The correlation is zero if the values are completely uncorrelated.
///
/// Two algorithms are provided: TauA and TauB. TauB accounts properly for duplicate values (ties), unlike TauA.
/// </summary>
public class KendallTauCorrelation<T, C> where C : IComparable<C>
{
private Func<T, C> Measure1 { get; }
private Func<T, C> Measure2 { get; }
public KendallTauCorrelation(Func<T, C> measure1, Func<T, C> measure2)
{
Measure1 = measure1;
Measure2 = measure2;
}
/// <summary>
/// Compute the Tau-a rank correlation, which is suitable if there are no ties in rank.
/// </summary>
/// <returns>A value between -1 and 1.
/// If the measures are ranked the same by both measures, returns 1.
/// If the measures are ranked in exactly opposite order, return -1.
/// The more items that are out of sequence, the lower the score.
/// If the measures are completely uncorrelated, returns zero.
/// </returns>
/// <param name="data">Data to be ranked according to two measures and then correlated.</param>
public double TauA(IList<T> data)
{
var ranked = data
.OrderBy(Measure1)
.Select((item, index) => new { Data = item, Rank1 = index + 1})
.OrderBy(pair => Measure2(pair.Data))
.Select((pair, index) => new { pair.Rank1, Rank2 = index + 1 })
.ToList();
var numerator = 0;
var n = ranked.Count;
var denominator = n * (n - 1)/2.0;
for (var i = 1; i < n; i++)
for (var j = 0; j < i; j++)
{
numerator += Sign(ranked[i].Rank1 - ranked[j].Rank1)
* Sign(ranked[i].Rank2 - ranked[j].Rank2);
}
return numerator/denominator;
}
/// <summary>
/// Compute the Tau-b correlation, which accounts for ties.
///
/// n - n
/// c d
/// τ = -----------------------
/// b _____________________
/// /(n - n)(n - n)
/// √ 0 1 0 2
///
/// where:
/// n0 = n(n-1)/2
///
/// n1 = Σ t (t - 1)/2
/// i i i
///
/// n2 = Σ t (t - 1)/2
/// j j j
///
/// t[i] = # of ties for the ith group according to measure 1.
/// t[j] = # of ties for the jth group according to measure 2.
/// nc = # of concordant pairs
/// nd = # of discordant pairs
/// </summary>
/// <returns>A correlation value between -1 (perfect reverse correlation)
/// and +1 (perfect correlation).
/// Zero means uncorrelated. </returns>
/// <param name="data">Data.</param>
public double TauB(IEnumerable<T> data)
{
// Compute two Ranks by sorting first by Measure1 and then by Measure2.
// Group by like values of each in order to handle ties.
var ranked = data.Select(item => new { M1 = Measure1(item), M2 = Measure2(item) })
.GroupBy(measures => new { measures.M1 })
.OrderBy(@group => @group.First().M1)
.ThenBy(@group => @group.First().M2)
.AsEnumerable()
.Select((@group, groupIndex) => new
{
Measure1Ranked = @group.Select((measure, index) => new { measure.M1, measure.M2 }),
Rank = ++groupIndex
})
.SelectMany(v => v.Measure1Ranked, (s, i) => new
{
i.M1,
i.M2,
DenseRank1 = s.Rank
})
.GroupBy(measures => new { measures.M2 })
.OrderBy(@group => @group.First().M2)
.ThenBy(@group => @group.First().M1)
.AsEnumerable()
.Select((@group, groupIndex) => new
{
Measure2Ranked = @group.Select((measure, index) => new { measure.M1, measure.M2, measure.DenseRank1 }),
Rank = ++groupIndex
})
.SelectMany(v => v.Measure2Ranked, (s, i) => new { i.M1, i.M2, i.DenseRank1, DenseRank2 = s.Rank })
.ToArray();
if (ranked.Length <= 1)
return 0; // No data or one data point. Impossible to establish correlation.
// Now that we have ranked the data, compute the correlation.
var n = ranked.Count();
var n0 = n * (n - 1)/2;
var n1 = 0;
var n2 = 0;
var numerator = 0; // Stores nc - nd as a single value, rather than computing them separately.
for (var i = 1; i < n; i++)
for (var j = 0; j < i; j++)
{
var iRanked = ranked[i];
var jRanked = ranked[j];
numerator += Sign(iRanked.DenseRank1 - jRanked.DenseRank1)
* Sign(iRanked.DenseRank2 - jRanked.DenseRank2);
// Keep track of ties. Because we are running the indices in a triangle,
// we automatically get this for n1 and n2: ties * (ties - 1)/2
if (iRanked.M1.CompareTo(jRanked.M1) == 0)
n1++;
if (iRanked.M2.CompareTo(jRanked.M2) == 0)
n2++;
}
if (n0 == n1 || n0 == n2)
return 0; // All ties, so everything as the same rank.
// Observe that if n1 = n2 = 0, that this formula is identical to Tau-a.
return numerator/Sqrt((double)(n0 - n1)*(n0 - n2));
}
}
}
이 NUnit과에 단위 테스트입니다
using System;
using NUnit.Framework;
using static System.Math; // New C# 6.0 feature that allows one to import static methods and call them without their class name.
namespace Statistics
{
[TestFixture]
public class KendallTauCorrelationTests
{
public static int[] OneToTen = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
#region Tau-a
[Test]
public void TauA_SameOrder()
{
var kendall = new KendallTauCorrelation<int, int>(
(int value) => value,
(int value) => value * 10
);
Assert.AreEqual(
1.0,
kendall.TauA(OneToTen),
"Numbers that sort in the same order should be perfectly correlated."
);
}
[Test]
public void TauA_ReverseOrder()
{
var kendall = new KendallTauCorrelation<int, int>(
(int value) => value,
(int value) => value * -10
);
Assert.AreEqual(
-1.0,
kendall.TauA(OneToTen),
"Numbers that sort in reverse order should be perfectly anti-correlated."
);
}
[Test]
public void TauA_OneSwap()
{
var reordered = new[] { 1, 2, 3, 5, 4, 6, 7, 8, 9, 10 };
var kendall = new KendallTauCorrelation<int, int>(
(int value) => value,
(int value) => reordered[value - 1]
);
Assert.AreEqual(
43.0/45.0,
kendall.TauA(OneToTen),
0.00001,
"If a single number is out of place the sequences should be almost perfectly correlated."
);
}
#endregion
#region Tau-b
[Test]
public void TauB_SameOrder()
{
var kendall = new KendallTauCorrelation<int,int>(
(int value) => value,
(int value) => value * 10
);
Assert.AreEqual(
1.0,
kendall.TauB(OneToTen),
"Numbers that sort in the same order should be perfectly correlated."
);
}
[Test]
public void TauB_ReverseOrder()
{
var kendall = new KendallTauCorrelation<int, int>(
(int value) => value,
(int value) => value * -10
);
Assert.AreEqual(
-1.0,
kendall.TauB(OneToTen),
"Numbers that sort in reverse order should be perfectly anti-correlated."
);
}
[Test]
public void TauB_OneSwap_NoTies()
{
var reordered = new[] { 1,2,3,5,4,6,7,8,9,10 };
var kendall = new KendallTauCorrelation<int, int>(
(int value) => value,
(int value) => reordered[value-1]
);
Assert.AreEqual(
43.0/45.0,
kendall.TauB(OneToTen),
0.00001,
"If a single number is out of place the sequences should be almost perfectly correlated."
);
}
[Test]
public void TauB_Ties()
{
var reordered = new[] { 1, 1, 1, 4, 5, 6, 7, 8, 9, 10 };
var kendall = new KendallTauCorrelation<int, int>(
(int value) => value,
(int value) => reordered[value - 1]
);
Assert.AreEqual(
42.0/Sqrt(42.0*45.0),
kendall.TauB(OneToTen),
0.00001,
"Adding a few ties should be almost perfectly correlated."
);
}
#endregion
}
}
참고 :이를 O (N^2) 알고리즘을 사용합니다. 이미 언급 한 N Log N이라는 수정 된 mergesort를 사용하는 것이 더 효율적인 방법이지만, 어떻게 완료되었는지는 알지 못합니다.
참고 :이 일반 클래스는 두 측정 값이 모두 동일한 데이터 형식을 반환한다고 가정합니다. 클래스에 두 가지 일반 측정 유형이있는 것은 쉬운 변경입니다. 그들은 IComparables 일 필요가 있습니다. 그들은 서로 비교할 필요가 없습니다.
[DiffLib] (http://difflib.codeplex.com/)에서 보았습니까 (면책 조항 : 라이브러리를 작성했습니다). 나는 "답변을 찾으려면이 링크를 클릭하십시오"라는 답변을 좋아하지 않으므로 답변으로 게시하지 않을 것입니다. –
[동적 프로그래밍] (http://en.wikipedia.org/wiki/Dynamic_programming)을 사용할 수 있습니다. 이는 두 시퀀스 내에서 요소의 추가, 제거 또는 수정을 확인하는 데 매우 유용합니다. – Nolonar
나는 또한이 기사를 온라인으로 제공하며, DiffLib의 기본 버전 : http://devdirective.com/post/91/creating-a-reusable-though-simple-diff-implementation-in-csharp-part-1 - 다시 스택 오버 플로우에 대한 좋은 대답이 아닙니다. . –