【问题标题】:Why is slope not a good measure of trends for data?为什么斜率不是衡量数据趋势的好方法?
【发布时间】:2020-06-23 10:48:39
【问题描述】:

按照this post 对使用 pandas 分析数据趋势的建议,我在我拥有的几个数据上使用了 numpy 的 polyfit。然而,它不允许我看到什么时候有趋势,什么时候没有。我想知道我理解错了什么。

首先代码如下

import pandas
import matplotlib.pyplot as plt
import numpy as np


file="data.csv"


df= pandas.read_csv(file,delimiter=',',header=0)

selected=df.loc[(df.index>25)&(df.index<613)]
xx=np.arange(25,612)

y= selected[selected.columns[1]].values
    
df.plot()
plt.plot(xx,y)
plt.xlabel("seconds")


coefficients, residuals, _, _, _ = np.polyfit(range(25,25+len(y)),y,1,full=True)

plt.plot(xx,[coefficients[0]*x + coefficients[1] for x in range(25,25+len(y))])


mse = residuals[0]/(len(y))
nrmse = np.sqrt(mse)/(y.max() - y.min())
print('Slope ' + str(coefficients[0]))
print('Degree '+str(np.degrees(np.arctan(coefficients[0]))))
print('NRMSE: ' + str(nrmse))
print('Max-Min '+str((y.max()-y.min())))

我修剪了第一个和最后 25 个数据点。 结果我得到了以下结果:

我可以清楚地看到数据有增加的趋势。 对于我得到的结果

Slope 397.78399534197837
Degree 89.85596288567513
NRMSE: 0.010041127178789659
Max-Min 257824

还有这些数据

我明白了

Slope 349.74410929666203
Degree 89.83617844631047
NRMSE: 0.1482879344688465
Max-Min 430752

但是有了这些数据

我明白了

Slope 29.414468649823373
Degree 88.05287249703134
NRMSE: 0.3752760050624873
Max-Min 673124

如您所见,在这种情况下,增加的趋势并不大,因此斜率较小。

但是这里

又是一个大坡

Slope 228.34551214653814
Degree 89.74908456620851
NRMSE: 0.3094116937517223
Max-Min 581600

我不明白为什么斜率没有清楚地表明趋势(更不用说度数了)

让我感到不安的第二件事是斜率取决于数据在 Y 轴上的变化程度。 例如,对于变化很少的数据,斜率在 0 范围内

Slope 0.00017744046645062043
Degree 0.010166589735754468
NRMSE: 0.07312155589459704
Max-Min 11.349999999999998

什么是检测数据趋势的好方法,无论其大小如何?

【问题讨论】:

  • 对所有图中的 y 轴进行统一缩放?
  • @amzon-ex 恐怕不会。我该怎么做?在其他问题中,有人告诉我有关 RMS 残差的一些信息……我想知道这是否有某种关系?
  • 为了让您的绘图通过斜率直观地显示趋势,并且始终如一地这样做,y 范围必须(i)在所有这些中完全相同,(ii)设置为最大值Max-Min 您已经获得(因为设置较小的 y 范围会在某些图中剪切值)。由于您的范围有很大的变化(257824 和 673124,第二个是第一个的两倍多),除非您按照我的建议进行操作,否则您将无法可视化趋势,并且也许,选择为您的地块设置纵向,以便它们有更多的垂直空间。
  • @KansaiRobot 我回答了你的问题。您介意改写您的问题标题,以便有类似数据分析问题的其他人可以找到吗?

标签: python pandas numpy data-analysis


【解决方案1】:

这个想法是你比较线性拟合与拟合周围数据的波动相比是否显示出显着增加:

在底部面板中,您会看到趋势(拟合减去常数部分)超过残差(定义为数据和拟合之间的差异)。 “显着增加”的一个好的标准是,取决于数据的类型以及沿 x 轴有多少值。我建议您采用残差的均方根 (RMS)。如果拟合中的趋势超过某个阈值(相对于残差),则称其为显着趋势。需要通过反复试验来确定合适的阈值。

这是生成上述图的代码:

import numpy as np
import matplotlib.pyplot as plt

# example data
x = np.arange(25, 600)
y = 1.76e7 + 3e5/600*x + 1e5*np.sin(x*0.2)
y += np.random.normal(scale=3e4, size=x.shape)

# process
a1, a0 = np.polyfit(x, y, 1)
resid = y - (a1*x + a0) # array
rms = np.sqrt((resid**2).mean())
plt.close('all')

fig, ax = plt.subplots(2, 1)
ax[0].plot(x, y, label='data')
ax[0].plot(x, a1*x+a0, label='fit')
ax[0].legend()
ax[1].plot(x, resid, label='residual')
ax[1].plot(x, a1*(x-x[0]), label='trend')
ax[1].legend()

dy_trend = a1*(x[-1] - x[0])
threshold = 0.3

print(f'dy_trend={dy_trend:.3g}; rms={rms:.3g  }')

if dy_trend > threshold*rms:
    print('Significant trend')

输出:

dy_trend=2.87e+05; rms=7.76e+04
Significant trend

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-09
    • 1970-01-01
    • 1970-01-01
    • 2020-01-16
    • 1970-01-01
    • 2013-07-27
    • 2011-12-05
    相关资源
    最近更新 更多