按两列分组并根据其中一列计算累计值
Group by two columns and calculate cumulative value based on one of them
请考虑此列表:
List<Data> lst = new List<Data>
{
new Data() { Id = 1, Val1 = 100 },
new Data() { Id = 1, Val1 = 200 },
new Data() { Id = 1, Val1 = 300 },
new Data() { Id = 2, Val1 = 100 },
new Data() { Id = 2, Val1 = 200 },
new Data() { Id = 3, Val1 = 300 },
new Data() { Id = 3, Val1 = 300 },
new Data() { Id = 3, Val1 = 300 },
new Data() { Id = 1, Val1 = 200 },
new Data() { Id = 1, Val1 = 200 },
new Data() { Id = 1, Val1 = 200 },
new Data() { Id = 2, Val1 = 200 },
new Data() { Id = 3, Val1 = 100 },
new Data() { Id = 3, Val1 = 100 },
};
然后是这段代码:
decimal Cumulative_Probability = 0;
var Result1 = (lst.OrderBy(o => o.Id).GroupBy(x => new { x.Val1 })
.Select(y => new
{
y.Key.Val1,
Probability = (Convert.ToDecimal(y.Count()) / lst.Count),
Cumulative_Probability = (Cumulative_Probability =
Cumulative_Probability +
(Convert.ToDecimal(y.Count()) / lst.Count))
})).OrderBy(o => o.Val1).ToList();
此代码运行良好,Cumulative_Probability
计算正确。
现在请考虑这段代码:
decimal Cumulative_Probability2 = 0;
var Result2 = (lst.OrderBy(o => o.Id).GroupBy(x => new { x.Id, x.Val1 })
.Select(y => new
{
y.Key.Id,
y.Key.Val1,
Probability = (Convert.ToDecimal(y.Count())
/ lst.Where(o => o.Id == y.Key.Id).Count()),
Cumulative_Probability = (Cumulative_Probability2 =
Cumulative_Probability2 +
(Convert.ToDecimal(y.Count()) /
lst.Where(o => o.Id == y.Key.Id).Count()))
})).OrderBy(o => o.Id).ThenBy(o => o.Val1).ToList();
此代码生成此结果:
如您所见,Probability
在每个组中计算正确,但 Cumulative_Probability
不正确。我想在每个 Id 组中计算 Cumulative_Probability
(组记录首先根据 Id
然后 Val1
)并且 Cumulative_Probability2
不会重置在每个组中。如何计算每个组中的 Cumulative_Probability
?
谢谢
编辑 1)
我想要这个结果:
Id Val1 Probability Cumulative_Probability
-------------------------------------------------------------------------
1 100 0.16 0.16
1 200 0.66 0.82
1 300 0.16 0.98
2 100 0.33 0.33
2 200 0.66 0.66
...
我设法在扩展方法的帮助下做到了这一点,该方法累积了累积概率,以及一些嵌套的 GroupBy
。我敢肯定一定有更简单的方法,但我正在摸索着寻找它。
分机号是:
public static class EnumerableExtensions
{
public static IEnumerable<TResult> Accumulate<TSource, TAccumulate, TResult>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, (TAccumulate,TResult)> accumulator)
{
var acc = seed;
foreach(TSource value in source)
{
var (newSeed, newSource) = accumulator.Invoke(acc, value);
yield return newSource;
acc = newSeed;
}
}
}
完成的代码如下所示:
var result = lst.GroupBy( x => x.Id)
.SelectMany( (grpId,i) => grpId.GroupBy(x => x.Val1)
.Accumulate(0M, (acc,grpVal) => (acc + (decimal)grpVal.Count()/grpId.Count(), new {
Id = grpId.Key,
Val1 = grpVal.Key,
Probability = (decimal)grpVal.Count()/grpId.Count(),
Cumulative_Probability = acc + ((decimal)grpVal.Count()/grpId.Count())
}))
)
.OrderBy(x => x.Id);
此代码有效:
var Result2 = (from a in lst.OrderBy(o => o.Id)
group a by new { a.Id, a.Val1 } into grp
select new
{
grp.Key.Id,
grp.Key.Val1,
Probability = (Convert.ToDecimal(grp.Count()) / lst.Where(o => o.Id == grp.Key.Id).Count()),
Cumulative_Probability = (from b in lst.Where(o => o.Id == grp.Key.Id && o.Val1 <= grp.Key.Val1)
group b by new { b.Val1 } into grp2
select new
{
Probability2 = (Convert.ToDecimal(grp2.Count()) / lst.Where(o => o.Id == grp.Key.Id).Count())
}).Sum(o => o.Probability2)
}).OrderBy(o => o.Id).ThenBy(o => o.Val1).ToList();
请考虑此列表:
List<Data> lst = new List<Data>
{
new Data() { Id = 1, Val1 = 100 },
new Data() { Id = 1, Val1 = 200 },
new Data() { Id = 1, Val1 = 300 },
new Data() { Id = 2, Val1 = 100 },
new Data() { Id = 2, Val1 = 200 },
new Data() { Id = 3, Val1 = 300 },
new Data() { Id = 3, Val1 = 300 },
new Data() { Id = 3, Val1 = 300 },
new Data() { Id = 1, Val1 = 200 },
new Data() { Id = 1, Val1 = 200 },
new Data() { Id = 1, Val1 = 200 },
new Data() { Id = 2, Val1 = 200 },
new Data() { Id = 3, Val1 = 100 },
new Data() { Id = 3, Val1 = 100 },
};
然后是这段代码:
decimal Cumulative_Probability = 0;
var Result1 = (lst.OrderBy(o => o.Id).GroupBy(x => new { x.Val1 })
.Select(y => new
{
y.Key.Val1,
Probability = (Convert.ToDecimal(y.Count()) / lst.Count),
Cumulative_Probability = (Cumulative_Probability =
Cumulative_Probability +
(Convert.ToDecimal(y.Count()) / lst.Count))
})).OrderBy(o => o.Val1).ToList();
此代码运行良好,Cumulative_Probability
计算正确。
现在请考虑这段代码:
decimal Cumulative_Probability2 = 0;
var Result2 = (lst.OrderBy(o => o.Id).GroupBy(x => new { x.Id, x.Val1 })
.Select(y => new
{
y.Key.Id,
y.Key.Val1,
Probability = (Convert.ToDecimal(y.Count())
/ lst.Where(o => o.Id == y.Key.Id).Count()),
Cumulative_Probability = (Cumulative_Probability2 =
Cumulative_Probability2 +
(Convert.ToDecimal(y.Count()) /
lst.Where(o => o.Id == y.Key.Id).Count()))
})).OrderBy(o => o.Id).ThenBy(o => o.Val1).ToList();
此代码生成此结果:
如您所见,Probability
在每个组中计算正确,但 Cumulative_Probability
不正确。我想在每个 Id 组中计算 Cumulative_Probability
(组记录首先根据 Id
然后 Val1
)并且 Cumulative_Probability2
不会重置在每个组中。如何计算每个组中的 Cumulative_Probability
?
谢谢
编辑 1)
我想要这个结果:
Id Val1 Probability Cumulative_Probability
-------------------------------------------------------------------------
1 100 0.16 0.16
1 200 0.66 0.82
1 300 0.16 0.98
2 100 0.33 0.33
2 200 0.66 0.66
...
我设法在扩展方法的帮助下做到了这一点,该方法累积了累积概率,以及一些嵌套的 GroupBy
。我敢肯定一定有更简单的方法,但我正在摸索着寻找它。
分机号是:
public static class EnumerableExtensions
{
public static IEnumerable<TResult> Accumulate<TSource, TAccumulate, TResult>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, (TAccumulate,TResult)> accumulator)
{
var acc = seed;
foreach(TSource value in source)
{
var (newSeed, newSource) = accumulator.Invoke(acc, value);
yield return newSource;
acc = newSeed;
}
}
}
完成的代码如下所示:
var result = lst.GroupBy( x => x.Id)
.SelectMany( (grpId,i) => grpId.GroupBy(x => x.Val1)
.Accumulate(0M, (acc,grpVal) => (acc + (decimal)grpVal.Count()/grpId.Count(), new {
Id = grpId.Key,
Val1 = grpVal.Key,
Probability = (decimal)grpVal.Count()/grpId.Count(),
Cumulative_Probability = acc + ((decimal)grpVal.Count()/grpId.Count())
}))
)
.OrderBy(x => x.Id);
此代码有效:
var Result2 = (from a in lst.OrderBy(o => o.Id)
group a by new { a.Id, a.Val1 } into grp
select new
{
grp.Key.Id,
grp.Key.Val1,
Probability = (Convert.ToDecimal(grp.Count()) / lst.Where(o => o.Id == grp.Key.Id).Count()),
Cumulative_Probability = (from b in lst.Where(o => o.Id == grp.Key.Id && o.Val1 <= grp.Key.Val1)
group b by new { b.Val1 } into grp2
select new
{
Probability2 = (Convert.ToDecimal(grp2.Count()) / lst.Where(o => o.Id == grp.Key.Id).Count())
}).Sum(o => o.Probability2)
}).OrderBy(o => o.Id).ThenBy(o => o.Val1).ToList();