斜率法
''' 1.做最小二乘拟合,把序列拟合成一条直线; 2.根据直线的斜率k可以得知序列的主要走势: 例如:(1)k > 0.1763 上升 (2) k < -0.1763 下降 (3)其他 3.然后计算序列各点到直线的距离(和方差一样) 设定一个阈值L,统计超过L的点数目,点数目越多说明序列震荡越厉害 '''
import numpy as np
import math
def trendline(data): # 拟合曲线
order=1
index=[i for i in range(1,len(data)+1)] # x轴坐标
coeffs = np.polyfit(index, list(data), order) # 曲线拟合
# k = coeffs[0] # 斜率
return coeffs
def judge_slope(coeffs, data, degree, shake=1):
tan_k = math.tan(degree*math.pi/180) # 注意弧度转化
# print(coeffs[0])
# print(tan_k)
if coeffs[0] >= tan_k:
return "上升"
elif coeffs[0] <= -tan_k:
return "下降"
else:
return get_shake(coeffs, data, shake)
def get_shake(coeffs, data, shake):
count = 0
for i, d in enumerate(data): # i+1相当于横坐标,从1开始
y = np.polyval(coeffs, i+1)
count += (y-d)**2
# print("count: ",count)
if count > shake:
return "波动"
else:
return "平稳"
if __name__ == '__main__':
data = [10,15,29,30,56,45,41,19,37,48,46]
coeffs = trendline(data)
res = judge_slope(coeffs, data, degree=1, shake=1)
print(res)
cox_stuart趋势检验
''' 判断一组数据的趋势是上升还是下降 '''
import scipy.stats as stats
def cox_stuart(list_c,debug=False):
lst=list_c.copy()
raw_len=len(lst)
if raw_len%2==1:
del lst[int((raw_len-1)/2)] # 删除中位数
c=int(len(lst)/2)
n_pos=n_neg=0
for i in range(c):
diff=lst[i+c]-lst[i]
if diff>0:
n_pos+=1
elif diff<0:
n_neg+=1
else:
continue
num=n_pos+n_neg
k=min(n_pos,n_neg) # 双边检验
print("k: ",k)
print("num:",num)
p_value=2*stats.binom.cdf(k,num,0.5) # 二项分布
if debug:
print('fall:%i, rise:%i, p-value:%f'%(n_neg, n_pos, p_value))
if n_pos>n_neg and p_value<0.05: # 双边检验
return 'increasing'
elif n_neg>n_pos and p_value<0.05: # 双边检验
return 'decreasing'
else:
return 'no trend'
list_c = [10,15,29,30,56,45,41,19,37,48,46] # 数据量太小,得不到有效结果
res = cos_staut(list_c, True)
print(res)
参考链接
https://wenku.baidu.com/view/cec731b981c758f5f61f6760.html
https://zhuanlan.zhihu.com/p/112703276
https://bbs.csdn.net/topics/350253275
https://blog.csdn.net/speargod/article/details/79939798