如何在Python中确定数字列表的趋势

3
有没有简单的方法可以找出列表的趋势呢?
例如:
[5.0, 6.0, 9.0, 4.0, 10.0]。整体上,它的元素随着时间增加。
[6.0, 4.0, 5.0, 4.0, 3.0]。它的元素随着时间减少。
理想情况下,我希望能从这些类型的列表中得到一个布尔结果。
实际上,我想知道一组数据的趋势。不是线性递增或精确递增,现实世界中,有些数据并不总是很好,也许有一两个季度的数据不如以前那么好(但也不太糟糕),但只要它的趋势是好的,就是好的。

布尔类型表示什么?'True' 表示增加,'False' 表示减少? - Kanmani
你的意思是要检查数值是增加还是减少吗? - Alireza
在尝试解决问题的编码部分之前,您应该决定要确定趋势的什么类型回归分析。在现实世界中,许多数据集会一直变得更好或更糟。或者你想要一个三态输出始终改善始终恶化没有明显的趋势 - phihag
3个回答

11

总体而言,它的元素是增加的。

我理解您想要考虑移动平均的变化。这项工作的一半是明确您真正想要的内容,所以我建议在开始编写逻辑之前,仔细考虑一下。

我结合了@Jaime提供的移动平均解决方案和np.diff,提出了一种可能的推断方式来满足您的需求。

import numpy as np

def moving_average(a, n=3) :
    ret = np.cumsum(a, dtype=float)
    ret[n:] = ret[n:] - ret[:-n]
    return ret[n - 1:] / n

lst1 = [5.0, 6.0, 9.0, 4.0, 10.0]
lst2 = [6.0, 4.0, 5.0, 4.0, 3.0]

res1 = np.all(np.diff(moving_average(np.array(lst1), n=4))>0)
# True; i.e. "generally increasing"

res2 = np.all(np.diff(moving_average(np.array(lst2), n=4))>0)
# False, i.e. "generally not increasing"

解释

  • moving_average 会在4个连续的数值中计算移动平均。
  • 对于长度为5的列表,每次都会得到2个数字的数组。
  • np.diff 接着会计算这些数字之间的成对差异。
  • np.all 使用测试条件>0 来确定这些差异是否全部是正数或全部不是正数。这是一种过度简化的方法,没有明确的要求驱动。

只是为了我理解,这个程序的作用是获取相邻数字之间的每个差值,将负数求和,将正数求和,如果两个总和之间的差值是正数,那么趋势就是上升的。是这样吗? - ChatterOne
@ChatterOne,我已经添加了一个解释。 - jpp
@FrankWang,你真正需要的是一个精确的数学公式来说明你想要实现什么。描述固然很好,但本身并不利于代码转换。 - jpp
2
考虑到请求的模糊性和答案的优雅,这是一个扎实的回答。 - deepelement

0

我刚遇到了同样的问题,为此使用了仅依赖pandas的版本解决了该问题,使得不必要实现moving_average函数。

def get_trend(array=[], reverse=False):
    array  = pd.Series(array).iloc[::-1].reset_index(drop=True) if reverse else pd.Series(array) #reverse Array if needed and convertes it to a pandas Series object
    trend  = pd.Series(array).rolling(len(array)-1).mean().dropna().reset_index(drop=True)             #calculate MA from array
    return -1 if trend[0] > trend[1] else 1 if trend[0] < trend[1] else 0

该函数返回1表示上涨趋势,返回-1表示下跌趋势,如果两者都不是则返回0。
根据我的测量,使用您上面的数组,每次调用此函数大约需要0.002秒。

0

你可以简单地检查一下,这个会起作用吗?

def checker(list_):
    check={}
    temp = []
    for m, n in enumerate(list_):
        try:
            if list_[m] < list_[m + 1]:
                temp.append('Increasing')
            else:
                temp.append('Decreasing')
        except IndexError:
            pass
    check[temp.count('Increasing')] = 1
    check[temp.count('Decreasing')] = 0


    return check[max(check)]

测试用例1:

print(checker([5.0, 6.0, 9.0, 4.0, 10.0]))

输出:

1

测试用例 2

print(checker([6.0, 4.0, 5.0, 4.0, 3.0]))

输出:

0

1
这只会检查有多少个上升和下降。如果你有很多微小的下降,比如说10个-1的下降,还有一个大的增长,比如说+1000的增长,我认为应该标记为增长,或者我漏掉了什么? - ChatterOne
@ChatterOne 是的,你漏掉了一些东西,所以如果我输入 print(checker([-1,-1,-1,-1,-1,-1,-1,10000])),它将返回0,这是递减的。 - Aaditya Ura
是的,这就是我的观点。我认为这是不正确的,应该标记为“增加”,因为整个系列都在上升。但我认为“增加”的定义可能会有所不同。 - ChatterOne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接