【问题标题】:Find the 'shape' of a list of numbers (straight-line/concave/convex, how many humps)查找数字列表的“形状”(直线/凹/凸,多少个驼峰)
【发布时间】:2014-10-31 11:09:07
【问题描述】:

这有点难以解释。我有一个整数列表。因此,例如,[1, 2, 4, 5, 8, 7, 6, 4, 1] - 当根据元素编号绘制时,它类似于凸图。我如何以某种方式从列表中提取这个“形状”特征?它不必特别准确 - 只是一般的形状,凸有一个驼峰,凹有两个,直线等 - 就可以了。

我可以对每个可能的形状使用条件:例如,如果斜率在某个索引之前为正,然后为负,则它是一个斜率,其偏度取决于index/list_size

有没有更聪明、更通用的方法?我想这可能是一个分类问题 - 但是没有 ML 是否可能?

干杯。

【问题讨论】:

  • 这似乎更像是一个数学问题而不是编程问题......但我认为你想要做的是将它们拟合到 n 次多项式并使用导数来确定形状(二阶导数给出凹度,临界点的数量给出了“驼峰”等)
  • 也许您可以遍历数组并验证(准确或不准确)一些数学原理。例如:对于每个 i,凸 => v[i+1] + v[i-1] >= v[i]
  • 你可以通过计算每个连续项之间的差异,然后它们之间的差异来找到大致的形状——这将是近似的(这里的关键是近似于二阶导数。即使是第一组差异您可以看到符号的变化,这将显示您的峰/谷。

标签: python statistics classification computer-science differentiation


【解决方案1】:
numpy.diff 

一阶差分由 out[n] = a[n+1] - a[n] 给出

https://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.diff.html

import numpy as np

data = [1, 2, 4, 5, 8, 7, 6, 4, 1]
data = np.array(data, dtype=float)
velocity = np.diff(data)
acceleration = np.diff(velocity)
jerk = np.diff(acceleration)
jounce = np.diff(jerk)

print data
print velocity
print acceleration
print jerk
print jounce

>>>
[ 1.  2.  4.  5.  8.  7.  6.  4.  1.]

# positive numbers = rising
[ 1.  2.  1.  3. -1. -1. -2. -3.]

# positive numbers = concave up
[ 1. -1.  2. -4.  0. -1. -1.]

# positive numbers = curling up
[-2.  3. -6.  4. -1.  0.]

# positive numbers = snapping up
[  5.  -9.  10.  -5.   1.]

https://en.wikipedia.org/wiki/Velocity

https://en.wikipedia.org/wiki/Acceleration

https://en.wikipedia.org/wiki/Jerk_(physics)

https://en.wikipedia.org/wiki/Jounce

我的倾向是然后除一阶导数;移动平均速度乘以 100 以转换为 %ROC;有时加速也很重要;凹度......你得到的混蛋/跳跃越多,数据变得越随机/嘈杂

您还可以计算每个的平均值:

print np.mean(data)
print np.mean(velocity)
print np.mean(acceleration)

对这个样本集的形状进行概括:

>>>
4.22222222222     # average value
0.0               # generally sideways; no trend
-0.571428571429   # concave mostly down

然后是平均相对标准差

import numpy as np
data = [1, 2, 4, 5, 8, 7, 6, 4, 1]
coef_variance = np.std(data) / np.mean(data)
print coef_variance

>>>0.566859453383

我称之为“相当不稳定”;但不是极端的数量级;通常 >1 被认为是“高度变异”

https://en.wikipedia.org/wiki/Coefficient_of_variation

如果我们绘制:

import matplotlib.pyplot as plt
import numpy as np

data = [1, 2, 4, 5, 8, 7, 6, 4, 1]
x = range(9)

plt.plot(x,data,c='red',ms=2)

plt.show()

我们可以看到,这是对我们发现的一般情况的良好描述:

没有整体上升/下降趋势,相当波动,下凹;意味着刚刚超过 4

你也可以使用 polyfit:

import matplotlib.pyplot as plt
import numpy as np

data = [1, 2, 4, 5, 8, 7, 6, 4, 1]
x = range(9)
plt.plot(x,data,c='red',ms=2)
poly = np.polyfit(x,data,2)
z = []
for x in range(9):
    z.append(poly[0]*x*x + poly[1]*x + poly[2])
x = range(9)
plt.plot(x,z,c='blue',ms=2)
print poly
plt.show()

返回:

[-0.37445887  3.195671   -0.07272727]

换句话说:

-0.374x^2 +  3.195x - 0.072

哪些情节:

你可以从那里计算平方和,看看你的模型有多准确

Sum of Square Differences (SSD) in numpy/scipy

您可以迭代 polyfit 过程,每次都增加度数

np.polyfit(x,data,degree)

直到您获得足够低的 SSD 以满足您的需求;这会告诉您您的数据是否更多 x^2ish、x^3ish、x^4ish 等。

while ssd > your_desire:               
   poly_array = polyfit()
   ssd = sum_squares(poly_array, data)
   degree +=1

【讨论】:

    【解决方案2】:

    如果您重复地对数据(即x[i+1] - x[i])进行差分,直到所有结果的符号相同,情况如何?例如,如果你将它差分两次并且所有结果都是非负的,你就知道它是凸的。否则再次区别并检查标志。您可以设置一个限制,例如 10 左右,超过该限制您认为序列太复杂而无法表征。否则,您的形状会以您差异的次数和最终符号为特征。

    【讨论】:

      猜你喜欢
      • 2016-11-21
      • 2012-04-30
      • 2016-10-21
      • 2012-11-05
      • 2013-07-11
      • 2011-01-28
      • 1970-01-01
      • 2020-11-02
      • 2012-09-30
      相关资源
      最近更新 更多