确定数值列表(样本)是递增还是递减(找到斜率)

时间:2017-01-09 11:51:56

标签: c# graph statistics

我正在寻找一种方法来确定样本列表中的数据是明显上升还是下降。数据的x值递增,y值介于0和100%之间。

Y值可以具有不同的行为,并且数据的计数可以在10到200个样本之间。我需要能够确定Y值是否明显上升或下降,并检测它们是否波动太大或是否变化不足。

您可以在下面的图片中看到不同的示例。

1.数据从95%左右变为50%,斜率明显为负值

2.数据波动在80%左右,斜率无法确定,所以应该忽略它

在3.数据从大约50%变为100%所以斜率明显为正,有1个样本由于读数不准确而下降到0%

在4.数据从100%到50%多次变化,两个闪烁读数下降到0%,斜率无法确定,所以应该忽略它

在5.数据从大约85%变化到大约80%,斜率是负的,但变化很小所以它应该忽略它

在6.数据保持稳定在100%,然后切换到50%并保持在它,斜率是负的

通过查看图表来进行这些观察非常容易,我想知道是否有一种简单的方法可以轻松地以编程方式得出这个结论。 对于情况2和5,我可以检查最小值和最大值之间的幅度以及是否低于某个阈值忽略数据,但是如果存在不准确的样本(降至0),幅度看起来会很好。我想我可以尝试过滤突然的尖峰,但是如何在6例情况下区分尖峰和从100%到50%的突然下降?

enter image description here

经过一番搜索,我得到了https://en.wikipedia.org/wiki/Simple_linear_regression,在那里我可以检查回归线的斜率,但我对统计数据一无所知,对于处理像4这样的情况也不是很好。

这是我的C#代码,它会返回正或负的双数或0,以防出现问题。然后我可以检查并忽略斜率在-0.3和0.3(或其他一些阈值)之间的数据

private double getSlope(List<DataPoint>points)
    {
        if (points.Count == 0) return 0; 

        double slope = 0;
        double avgX = 0;
        double avgY = 0;
        double avgXY = 0;
        double avgX2 = 0;
        double avgY2 = 0;

        foreach (var p in points)
        {
            //calculate the sums
            avgX += p.X;
            avgY += p.Y;
            avgXY += p.X * p.Y;
            avgX2 += p.X * p.X;
            avgY2 += p.Y * p.Y;
        }
        //calculate the average 
        avgX /= points.Count;
        avgY /= points.Count;
        avgXY /= points.Count;
        avgX2 /= points.Count;
        avgY2 /= points.Count;

        try { slope = (avgXY - avgX * avgY) / Math.Sqrt((avgX2 - avgX * avgX) * (avgY2 - avgY * avgY)); } catch {} 

        return slope;
    }

那么你能否建议另一种方法对我的情况更好,我想要一个伪代码算法,一个有用资源的链接或只是建议。

2 个答案:

答案 0 :(得分:0)

using System;

namespace ConsoleApp
{
    class Program
    {
        static void Main()
        {
            int[,] array = new int[,]
            {
                {  95,  50 },
                {  77,  78 },
                {  52, 100 },
                { 100,  73 },
                {  86,  77 },
                {  99,  50 }
            };

            for (int i = 0; i <= array.GetUpperBound(0); i++)
            {
                float i1 = array[i, 0];
                float i2 = array[i, 1];

                var calc = i2 / i1;

                if ( calc < 0.70 )
                {
                    Console.WriteLine("{0} negative", calc);
                }
                else if ( calc > 1.3 )
                {
                    Console.WriteLine("{0} positive", calc);
                }
                else
                {
                    Console.WriteLine("{0} ignore", calc);
                }
            }

            Console.ReadKey();
        }
    }
}

你只需要比较开头和&amp;最后的价值观我的输出完全符合您的要求 - 即

0.5263158 negative
1.012987 ignore
1.923077 positive
0.73 ignore
0.8953488 ignore
0.5050505 negative

答案 1 :(得分:0)

using System;

namespace ConsoleApp
{
    class Program
    {
        static void Main()
        {
            int[,] array = new int[,]
            {
                {  95,  50 },
                {  77,  78 },
                {  52, 100 },
                { 100,  73 },
                {  86,  77 },
                {  99,  50 },
                {  50,   0 }
            };

            for (int i = 0; i <= array.GetUpperBound(0); i++)
            {
                float i1 = array[i, 0];
                float i2 = array[i, 1];

                var calc = i2 / i1;

                if (calc > 0.10 && calc < 0.70)
                {
                    Console.WriteLine("{0} negative", calc);
                }
                else if (calc > 1.3 && calc < 2.00)
                {
                    Console.WriteLine("{0} positive", calc);
                }
                else
                {
                    Console.WriteLine("{0} ignore", calc);
                }
            }

            Console.ReadKey();
        }
    }
}

我添加了'边界' - 如果移动太远(正面或负面),它将被忽略。您可以调整公差。我添加了一个从50到0和0的运动示例。你可以看到它被忽略了。你可以忽略这些大的波动&amp;坚持现有价值。