我有以下方法,執行分層k摺疊交叉驗證的邏輯的一部分。試圖瞭解linq /延遲執行如何工作
private static IEnumerable<IEnumerable<int>> GenerateFolds(
IClassificationProblemData problemData, int numberOfFolds)
{
IRandom random = new MersenneTwister();
IEnumerable<double> values = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices);
var valuesIndices =
problemData.TrainingIndices.Zip(values, (i, v) => new { Index = i, Value = v });
IEnumerable<IEnumerable<IEnumerable<int>>> foldsByClass =
valuesIndices.GroupBy(x => x.Value, x => x.Index)
.Select(g => GenerateFolds(g, g.Count(), numberOfFolds));
var enumerators = foldsByClass.Select(x => x.GetEnumerator()).ToList();
while (enumerators.All(e => e.MoveNext()))
{
var fold = enumerators.SelectMany(e => e.Current).OrderBy(x => random.Next());
yield return fold.ToList();
}
}
褶皺產生:
private static IEnumerable<IEnumerable<T>> GenerateFolds<T>(
IEnumerable<T> values, int valuesCount, int numberOfFolds)
{
// number of folds rounded to integer and remainder
int f = valuesCount/numberOfFolds, r = valuesCount % numberOfFolds;
int start = 0, end = f;
for (int i = 0; i < numberOfFolds; ++i)
{
if (r > 0)
{
++end;
--r;
}
yield return values.Skip(start).Take(end - start);
start = end;
end += f;
}
}
通用GenerateFolds<T
方法只是根據摺疊的指定數目的分割的IEnumerable<T>
成IEnumerable
秒的序列。例如,如果我有101個訓練樣本,它將產生11倍大小的一倍和10倍大小的9倍。
上面的方法根據類別值對樣本進行分組,將每個組分割成指定的摺疊數然後將最後的摺疊連接到類別摺疊,以確保類別標籤的分佈相同。
我的問題關於行yield return fold.ToList()
。實際上,如果我刪除了ToList()
,則該方法正常工作,但結果不再正確。在我的測試案例中,我有641個訓練樣本和10個摺疊,這意味着第一個摺疊的大小應爲65,剩餘的摺疊大小爲64.但是,當我刪除ToList()
時,所有摺疊的大小爲64,並且類標籤不正確分散式。任何想法爲什麼?謝謝。
旁註 - '的IEnumerable >>'爽:) –
2014-09-11 07:58:12
感謝編輯和製作我的問題看起來更好! :) – 2014-09-11 08:10:47
剛剛驗證你的代碼 - 工作正常,沒有保存摺疊列表。它返回'numberOfFolds'索引組數 – 2014-09-11 08:25:02