C# 比较两组数据(x,y)

C# 比较两组数据(x,y),c#,dataset,interpolation,C#,Dataset,Interpolation,我已经将数字数据存储在带有坐标(xValues,yValues)的列表中,如果我想将这组数据与另一组数据进行比较(加、减、除…),我必须意识到如果xValues不匹配,我就无法进行比较(因为没有什么可比较的)。所以我需要在另一个集合中实际存在的“缺失”x值之间进行线性插值,并生成新的点。请检查此图片: 红线上的青色方框表示存储的点(xValues2),并且(通常)它们不会与其他设置的xValues(xValues1)匹配。绿线上的两个正方形是所需生成点的示例。有了它们,我可以毫无问题地处理这两

我已经将数字数据存储在带有坐标(xValues,yValues)的列表中,如果我想将这组数据与另一组数据进行比较(加、减、除…),我必须意识到如果xValues不匹配,我就无法进行比较(因为没有什么可比较的)。所以我需要在另一个集合中实际存在的“缺失”x值之间进行线性插值,并生成新的点。请检查此图片:

红线上的青色方框表示存储的点(xValues2),并且(通常)它们不会与其他设置的xValues(xValues1)匹配。绿线上的两个正方形是所需生成点的示例。有了它们,我可以毫无问题地处理这两张图

对于线性插值,它非常简单:如果我有两个点(x0,y0)和(x1,y1),我想在它们之间添加一个新点,给定一个“x2”:

为了实现这一点,我认为我必须实现如下内容:

  • 创建新列表(xValuesNew、yValuesNew)
  • 在xValues1和xValues2(xValuesNew)之间建立并集
  • 检查原始xValues1和xValuesNew之间的差异
  • 对于找到的每个新值,使用上述公式生成“y”
  • 将这4个步骤放在一个方法中,然后再次使用它,但现在使用set2
  • 我花了一整天的时间在这上面,试图找到一个简单的解决方案,可能使用Linq或lambda表达式,但我不习惯使用它们,而且我对这些主题缺乏知识。请注意,此操作将经常进行,因此我必须使其不太重。我认为这将是一个好主意,生成一个新的列表,而不是在原来的中间插入点。 如果有人能给我一点指导,或者告诉我是否有一个数学图书馆,这样做会很好。多谢各位


    编辑:对不起,如果我没有正确地解释我

    这里我有一个例子(用Excel完成):

    请注意,我不能直接将Series1和Series2(+)或任何其他操作相加,因为它们中的X间距不同。所以我想在需要时在序列1中生成一个新点

    为此,我想简单地使用线性插值。假设系列1中有P1(0,40)和P2(0,60),但系列2中有一个点(1,10)。我需要用(1,50)坐标在P1和P2之间生成点P3

    我试着用SkipWhile做这件事,比较两个系列的下一个X值,如果系列1的X值更低,那么在newSeries中添加该X值和相应的Y值。否则,使用XValue2生成Y并将其添加到newSeries。以下是我的一次尝试(无效):

    List series1X=新列表{0,2,4,6,8};
    列表序列1y=新列表{120、100、110、105、70};
    列表序列2x=新列表{0,1,7,8,9};
    List newSeries1X=新列表();
    List newSeries1Y=新列表();
    double lastX1=series1X[series1X.Count()-1];
    int i=0;
    
    (next1X p首先,我可能会使用一个适当的“点”类,该类包含x和y坐标,而不是每个坐标的两个单独列表。然后,您可以使用该方法快速遍历它们:

    IEnumerable<PointF> points0 = ...
    IEnumerable<PointF> points0 = ...
    float x2 = ...
    IEnumerable<PointF> newPoints = point0.Zip(points1, 
        (p0, p1) => new PointF(p0.X, p0.Y + (x2-p0.X) * (p1.Y-p0.Y) / (p1.X-p0.X)));
    
    此解决方案通过从第一对/最后一对点向外线性“投影”数据来处理第一个
    series2X[0]
    series2X[n]>series1X[m]
    的情况

    下面是另一个使用枚举数的解决方案(主要是),但它并不像我希望的那样优雅。它可能会有一些改进:

    bool hasS1 = true, hasS2 = true, preinterp = true;
    double x0 = 0, y0 = 0, x1 = 0, y1 = 0, x = 0, y = 0;
    using(var s1xEnumerator = series1X.GetEnumerator())
    using(var s1yEnumerator = series1Y.GetEnumerator())
    using(var s2xEnumerator = series2X.GetEnumerator())
    {
        hasS1 = s1xEnumerator.MoveNext();
        hasS2 = s2xEnumerator.MoveNext();
        s1yEnumerator.MoveNext();
        while(hasS1 && hasS2)
        {
            x1 = s1xEnumerator.Current;
            y1 = s1yEnumerator.Current;
            x = s2xEnumerator.Current;
    
            if (x1 <= x)
            {
                newSeries1X.Add(x1);
                newSeries1Y.Add(y1);
                hasS1 = s1xEnumerator.MoveNext();
                s1yEnumerator.MoveNext();
                preinterp = false;
                if (hasS1)
                {
                    x0 = x1;
                    y0 = y1;
                }
                if (x1 == x)
                {
                    hasS2 = s2xEnumerator.MoveNext();
                }
            }
            else
            {
                // we have to look ahead to get the next interval to interpolate before x0
                if (preinterp)
                {
                    x0 = x1;
                    y0 = y1;
                    x1 = series1X[1]; // can't peek with enumerator
                    y1 = series1Y[1]; 
                    preinterp = false;
                }
    
                y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
                newSeries1X.Add(x);
                newSeries1Y.Add(y);
                hasS2 = s2xEnumerator.MoveNext();
            }
        }
    
        while(hasS1)
        {
            newSeries1X.Add(s1xEnumerator.Current);
            newSeries1Y.Add(s1yEnumerator.Current);
            hasS1 = s1xEnumerator.MoveNext();
            s1yEnumerator.MoveNext();
        }
    
        while(hasS2)
        {
            x = s2xEnumerator.Current;
            y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
            newSeries1X.Add(x);
            newSeries1Y.Add(y);
            hasS2 = s2xEnumerator.MoveNext();
        }
    }
    
    bool hasS1=true,hasS2=true,preinterp=true;
    双x0=0,y0=0,x1=0,y1=0,x=0,y=0;
    使用(var s1xEnumerator=series1X.GetEnumerator())
    使用(var s1yEnumerator=series1Y.GetEnumerator())
    使用(var s2xEnumerator=series2X.GetEnumerator())
    {
    hasS1=s1xEnumerator.MoveNext();
    hasS2=s2xEnumerator.MoveNext();
    s1yEnumerator.MoveNext();
    而(hasS1和hasS2)
    {
    x1=S1Xe分子电流;
    y1=S1Y分子电流;
    x=S2Xe分子电流;
    
    如果(x1用于处理具有不同间距的两个系列,我首先需要在第一组中生成点,然后在第二组中生成点(使用相同的方法),最后对点进行求和

    以下是该方法的代码:

    using OxyPlot.Series;
    using OxyPlot;
    
    namespace Algorithm1
    {
    
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                List<DataPoint> S1 = new List<DataPoint> ();
                List<DataPoint> S2 = new List<DataPoint>();
                List<DataPoint> NS1 = new List<DataPoint>();
    
                S1.Add(new DataPoint(4, 10));
                S1.Add(new DataPoint(6, 20));
                S1.Add(new DataPoint(8, 15));
                S1.Add(new DataPoint(9, 70));
                S1.Add(new DataPoint(10, 5));
    
                S2.Add(new DataPoint(1, 0));
                S2.Add(new DataPoint(2, 0));
                S2.Add(new DataPoint(3, 0));
                S2.Add(new DataPoint(6, 0));
                S2.Add(new DataPoint(7, 0));
                S2.Add(new DataPoint(8.1, 0));
                S2.Add(new DataPoint(8.2, 0));
                S2.Add(new DataPoint(8.3, 0));
                S2.Add(new DataPoint(8.4, 0));
                S2.Add(new DataPoint(9, 0));
                S2.Add(new DataPoint(9.75, 0));
                S2.Add(new DataPoint(11, 0));
                S2.Add(new DataPoint(12, 0));
                S2.Add(new DataPoint(16, 0));
    
               NS1 = GetMiddlePoints(S1, S2);
               foreach (DataPoint pointin NS1)
               {
                   MessageBox.Show( point.X.ToString()+" : "+ point.Y.ToString());
               }
    
    
            }
    
            #region GetMiddlePoints
            private List<DataPoint> GetMiddlePoints(List<DataPoint> S1, List<DataPoint> S2)
            {
                List<DataPoint> NS1 = new List<DataPoint>();
    
                int i = 0;
                int j = S2.TakeWhile(p => p.X < S1[0].X).Count();
    
    
                int PointsInS1 = S1.Count;
                int PointsInS2 = S2.Count;
    
                DataPoint newPoint = new DataPoint();
    
    
                while (i < PointsInS1 )
                {
                    if (j < PointsInS2 )
                    {
                        if (S1[i].X < S2[j].X)
                        {
                            newPoint = S1[i];
                            NS1.Add(newPoint );
                            i++;
                        }
    
                        else if (S1[i].X == S2[j].X)
                        {
                            newPoint = S1[i];
                            NS1.Add(newPoint );
                            i++;
                            j++;
                        }
    
                        else if (S1[i].X > S2[j].X)
                        {
                            newPoint .X = S2[j].X;
                            newPoint .Y = S1[i-1].Y + (S2[j].X - S1[i-1].X) * (S1[i].Y - S1[i-1].Y) / (S1[i].X - S1[i-1].X);
                            NS1.Add(newPoint );
                            j++;
    
                        }
    
                    }
    
                    if (j == PointsInS2 )
                    {
                        newPoint = S1[i];
                        NS1.Add(newPoint );
                        i++;
                    }
    
    
                }
    
    
                return NS1;
    
            }
    
            #endregion
    
        }
    }
    
    使用OxyPlot.Series;
    使用氧图;
    名称空间算法1
    {
    公共部分类主窗口:窗口
    {
    公共主窗口()
    {
    初始化组件();
    列表S1=新列表();
    列表S2=新列表();
    列表NS1=新列表();
    S1.添加(新数据点(4,10));
    S1.添加(新数据点(6,20));
    S1.增加(新数据点(8,15));
    S1.增加(新数据点(9,70));
    S1.添加(新数据点(10,5));
    S2.添加(新数据点(1,0));
    S2.添加(新数据点(2,0));
    S2.添加(新数据点(3,0));
    S2.添加(新数据点(6,0));
    S2.添加(新数据点(7,0));
    S2.增加(新数据点(8.1,0));
    S2.增加(新数据点(8.2,0));
    S2.增加(新数据点(8.3,0));
    S2.增加(新数据点(8.4,0));
    S2.添加(新数据点(9,0));
    S2.增加(新数据点(9.75,0));
    S2.添加(新数据点(11,0));
    S2.添加(新数据点(12,0));
    S2.添加(新数据点(16,0));
    NS1=获取中间点(S1,S2);
    foreach(NS1中的数据点)
    {
    Show(point.X.ToString()+”:“+point.Y.ToString());
    }
    }
    #区域中间点
    私有列表GetMiddlePoints(列表S1、列表S2)
    {
    列表NS1=新列表();
    int i=0;
    intj=S2.TakeWhile(p=>p.XIEnumerable<double> y2values = 
        xValues1.Zip(yValues1, (x, y) => new { x, y }).Zip(
            xValues2.Zip(yValues2, (x, y) => new { x, y }),
            (p0, p1) => p0.y + (x2-p0.x) * (p1.y-p0.y) / (p1.x-p0.x));
    
    List<double> series1X = new List<double> {   0,   2,   4,   6,  8 };
    List<double> series1Y = new List<double> { 120, 100, 110, 105, 70 };
    List<double> series2X = new List<double> {   0,   1,   7,   8,  9 };
    
    // in the worst case there are n + m new points
    List<double> newSeries1X = new List<double>(series1X.Count + series2X.Count);
    List<double> newSeries1Y = new List<double>(series1X.Count + series2X.Count);
    
    int i = 0, j = 0;
    for ( ; i < series1X.Count && j < series2X.Count; )
    {
        if (series1X[i] <= series2X[j])
        {
            newSeries1X.Add(series1X[i]);
            newSeries1Y.Add(series1Y[i]);
            if (series1X[i] == series2X[j])
            {
                j++;
            }
            i++; 
        }
        else
        {
            int k = (i == 0) ? i : i - 1;
            // interpolate
            double y0 = series1Y[k];
            double y1 = series1Y[k + 1];
            double x0 = series1X[k];
            double x1 = series1X[k + 1];
            double y = y0 + (y1 - y0) * (series2X[j] - x0) / (x1 - x0);
            newSeries1X.Add(series2X[j]);
            newSeries1Y.Add(y);
            j++;
        }
    }
    for ( ; i < series1X.Count; i++)
    {
        newSeries1X.Add(series1X[i]);
        newSeries1Y.Add(series1Y[i]);
    }
    for ( ; j < series2X.Count; j++)
    {
        // interpolate
        double y0 = series1Y[i - 2];
        double y1 = series1Y[i - 1];
        double x0 = series1X[i - 2];
        double x1 = series1X[i - 1];
        double y = y0 + (y1 - y0) * (series2X[j] - x0) / (x1 - x0);
        newSeries1X.Add(series2X[j]);
        newSeries1Y.Add(y);
    }
    
    newSeries1X = {    0,    1,    2,    4,    6,    7,    8,    0 }
    newSeries1Y = {  120,  110,  100,  110,  105, 87.5,   70, 52.5 }
    
    bool hasS1 = true, hasS2 = true, preinterp = true;
    double x0 = 0, y0 = 0, x1 = 0, y1 = 0, x = 0, y = 0;
    using(var s1xEnumerator = series1X.GetEnumerator())
    using(var s1yEnumerator = series1Y.GetEnumerator())
    using(var s2xEnumerator = series2X.GetEnumerator())
    {
        hasS1 = s1xEnumerator.MoveNext();
        hasS2 = s2xEnumerator.MoveNext();
        s1yEnumerator.MoveNext();
        while(hasS1 && hasS2)
        {
            x1 = s1xEnumerator.Current;
            y1 = s1yEnumerator.Current;
            x = s2xEnumerator.Current;
    
            if (x1 <= x)
            {
                newSeries1X.Add(x1);
                newSeries1Y.Add(y1);
                hasS1 = s1xEnumerator.MoveNext();
                s1yEnumerator.MoveNext();
                preinterp = false;
                if (hasS1)
                {
                    x0 = x1;
                    y0 = y1;
                }
                if (x1 == x)
                {
                    hasS2 = s2xEnumerator.MoveNext();
                }
            }
            else
            {
                // we have to look ahead to get the next interval to interpolate before x0
                if (preinterp)
                {
                    x0 = x1;
                    y0 = y1;
                    x1 = series1X[1]; // can't peek with enumerator
                    y1 = series1Y[1]; 
                    preinterp = false;
                }
    
                y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
                newSeries1X.Add(x);
                newSeries1Y.Add(y);
                hasS2 = s2xEnumerator.MoveNext();
            }
        }
    
        while(hasS1)
        {
            newSeries1X.Add(s1xEnumerator.Current);
            newSeries1Y.Add(s1yEnumerator.Current);
            hasS1 = s1xEnumerator.MoveNext();
            s1yEnumerator.MoveNext();
        }
    
        while(hasS2)
        {
            x = s2xEnumerator.Current;
            y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
            newSeries1X.Add(x);
            newSeries1Y.Add(y);
            hasS2 = s2xEnumerator.MoveNext();
        }
    }
    
    using OxyPlot.Series;
    using OxyPlot;
    
    namespace Algorithm1
    {
    
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                List<DataPoint> S1 = new List<DataPoint> ();
                List<DataPoint> S2 = new List<DataPoint>();
                List<DataPoint> NS1 = new List<DataPoint>();
    
                S1.Add(new DataPoint(4, 10));
                S1.Add(new DataPoint(6, 20));
                S1.Add(new DataPoint(8, 15));
                S1.Add(new DataPoint(9, 70));
                S1.Add(new DataPoint(10, 5));
    
                S2.Add(new DataPoint(1, 0));
                S2.Add(new DataPoint(2, 0));
                S2.Add(new DataPoint(3, 0));
                S2.Add(new DataPoint(6, 0));
                S2.Add(new DataPoint(7, 0));
                S2.Add(new DataPoint(8.1, 0));
                S2.Add(new DataPoint(8.2, 0));
                S2.Add(new DataPoint(8.3, 0));
                S2.Add(new DataPoint(8.4, 0));
                S2.Add(new DataPoint(9, 0));
                S2.Add(new DataPoint(9.75, 0));
                S2.Add(new DataPoint(11, 0));
                S2.Add(new DataPoint(12, 0));
                S2.Add(new DataPoint(16, 0));
    
               NS1 = GetMiddlePoints(S1, S2);
               foreach (DataPoint pointin NS1)
               {
                   MessageBox.Show( point.X.ToString()+" : "+ point.Y.ToString());
               }
    
    
            }
    
            #region GetMiddlePoints
            private List<DataPoint> GetMiddlePoints(List<DataPoint> S1, List<DataPoint> S2)
            {
                List<DataPoint> NS1 = new List<DataPoint>();
    
                int i = 0;
                int j = S2.TakeWhile(p => p.X < S1[0].X).Count();
    
    
                int PointsInS1 = S1.Count;
                int PointsInS2 = S2.Count;
    
                DataPoint newPoint = new DataPoint();
    
    
                while (i < PointsInS1 )
                {
                    if (j < PointsInS2 )
                    {
                        if (S1[i].X < S2[j].X)
                        {
                            newPoint = S1[i];
                            NS1.Add(newPoint );
                            i++;
                        }
    
                        else if (S1[i].X == S2[j].X)
                        {
                            newPoint = S1[i];
                            NS1.Add(newPoint );
                            i++;
                            j++;
                        }
    
                        else if (S1[i].X > S2[j].X)
                        {
                            newPoint .X = S2[j].X;
                            newPoint .Y = S1[i-1].Y + (S2[j].X - S1[i-1].X) * (S1[i].Y - S1[i-1].Y) / (S1[i].X - S1[i-1].X);
                            NS1.Add(newPoint );
                            j++;
    
                        }
    
                    }
    
                    if (j == PointsInS2 )
                    {
                        newPoint = S1[i];
                        NS1.Add(newPoint );
                        i++;
                    }
    
    
                }
    
    
                return NS1;
    
            }
    
            #endregion
    
        }
    }