微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 计算几个函数的平均函数

我有几个有序的X / Y对列表,我想计算一个有序的X / Y对列表,代表这些列表的平均值.

所有这些列表(包括“平均列表”)将被绘制到图表上(参见下面的示例图片).

我有几个问题:

>不同的列表没有相同数量的值
> X和Y值可以增加,减少和增加(等等)(参见下面的示例图片)

我需要在C#中实现这一点,我想这对算法本身并不重要.

对不起,我无法以更正式或数学的方式解释我的问题.

编辑:我用“X / Y对列表”替换术语“功能”,这不那么令人困惑.

解决方法

我会使用贾斯汀提出的方法,进行一次调整.他建议使用带有小数指数的映射表,但我建议使用整数指数.这可能听起来有点数学,但是必须阅读以下两次并不是一件好事(我也必须这样做).假设对A列表中的索引i处的点已搜索另一列表B中的最近点,并且该最近点位于索引j处.要找到B中最接近A [i 1]的点,您应该只考虑B中具有等于或大于j的索引的点.它可能是j 1,但可能是j或j 2,j 3等,但从不低于j.即使最接近A [i 1]的点的索引小于j,您仍然不应该使用该点进行插值,因为这会导致意外的平均值和图形.我现在花点时间为您创建一些示例代码.我希望你看到这种优化是有道理的.

编辑:在实现这一点时,我意识到j不仅从下面(通过上述方法)限制,而且还从上面限定.当你尝试从A [i 1]到B [j],B [j 1],B [j 2]等的距离时,你可以停止比较距离A [i 1]到B [j …]的距离停止下降.在B中进一步搜索是没有意义的.同样的推理适用于j从下面开始的界限:即使B中其他地方的某个点更接近,这可能不是你想要插入的点.这样做会导致意外的图形,可能不如您预期的那么平滑.第二个限制的额外奖励是提高了性能.我创建了以下代码

IEnumerable<Tuple<double,double>> Average(List<Tuple<double,double>> A,List<Tuple<double,double>> B)
{
    if (A == null || B == null || A.Any(p => p == null) || B.Any(p => p == null)) throw new ArgumentException();
    Func<double,double> square = d => d * d;//squares its argument
    Func<int,int,double> euclidiandistance = (a,b) => Math.Sqrt(square(A[a].Item1 - B[b].Item1) + square(A[a].Item2 - B[b].Item2));//computes the distance from A[first argument] to B[second argument]

    int prevIoUsIndexInB = 0;
    for (int i = 0; i < A.Count; i++)
    {
        double distance = euclidiandistance(i,prevIoUsIndexInB);//distance between A[i] and B[j - 1],initially 
        for (int j = prevIoUsIndexInB + 1; j < B.Count; j++)
        {
            var distance2 = euclidiandistance(i,j);//distance between A[i] and B[j]
            if (distance2 < distance)//if it's closer than the prevIoUsly checked point,keep searching. Otherwise stop the search and return an interpolated point.
            {
                distance = distance2;
                prevIoUsIndexInB = j;
            }
            else
            {
                break;//don't place the yield return statement here,because that Could go wrong at the end of B.
            }
        }
        yield return LinearInterpolation(A[i],B[prevIoUsIndexInB]);
    }
}
Tuple<double,double> LinearInterpolation(Tuple<double,double> a,Tuple<double,double> b)
{
    return new Tuple<double,double>((a.Item1 + b.Item1) / 2,(a.Item2 + b.Item2) / 2);
}

对于您的信息,函数Average返回列表A包含的相同数量的插值点,这可能很好,但您应该考虑针对您的特定应用程序.我在其中添加了一些注释以澄清一些细节,我在上面的文本中描述了此代码的所有方面.我希望它很清楚,否则可以随意提问.

第二次编辑:我误读并认为你只有两个积分列表.我创建了一个上面接受多个列表的通用函数.它仍然只使用上面解释的那些原则.

IEnumerable<Tuple<double,double>> Average(List<List<Tuple<double,double>>> data)
{
    if (data == null || data.Count < 2 || data.Any(list => list == null || list.Any(p => p == null))) throw new ArgumentException();
    Func<double,double> square = d => d * d;
    Func<Tuple<double,double>,b) => Math.Sqrt(square(a.Item1 - b.Item1) + square(a.Item2 - b.Item2));

    var firstList = data[0];
    for (int i = 0; i < firstList.Count; i++)
    {
        int[] prevIoUsIndices = new int[data.Count];//the indices of points which are closest to the prevIoUs point firstList[i - 1]. 
        //(or zero if i == 0). This is kept track of per list,except the first list.
        var closests = new Tuple<double,double>[data.Count];//an array of points used for caching,of which the average will be yielded.
        closests[0] = firstList[i];
        for (int listIndex = 1; listIndex < data.Count; listIndex++)
        {
            var list = data[listIndex];
            double distance = euclidiandistance(firstList[i],list[prevIoUsIndices[listIndex]]);
            for (int j = prevIoUsIndices[listIndex] + 1; j < list.Count; j++)
            {
                var distance2 = euclidiandistance(firstList[i],list[j]);
                if (distance2 < distance)//if it's closer than the prevIoUsly checked point,keep searching. Otherwise stop the search and return an interpolated point.
                {
                    distance = distance2;
                    prevIoUsIndices[listIndex] = j;
                }
                else
                {
                    break;
                }
            }
            closests[listIndex] = list[prevIoUsIndices[listIndex]];
        }
        yield return new Tuple<double,double>(closests.Select(p => p.Item1).Average(),closests.Select(p => p.Item2).Average());
    }
}

实际上,我分别为2个列表做了具体案例可能是一件好事:它很容易解释并在理解通用版本之前提供了一个步骤.此外,可以取出平方根,因为它不会改变排序时的距离顺序,只改变长度.

第三次编辑:在评论中,很明显可能存在错误.我认为除了上面提到的小虫子之外没有其他的东西,除了图表的末尾之外不应该有任何区别.作为它实际工作的证明,这是它的结果(虚线是平均值):

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐