我试图绘制一个简单的移动平均线函数,但结果数组比完整样本大小少了几个数字。如何在延伸整个样本大小的标准线旁边绘制这样的线?下面的代码导致此错误消息:
ValueError: x and y must have same first dimension, but have shapes (96,) and (100,)
这使用的是标准matplotlib.pyplot
。我试过只使用remove
和del
删除X值,以及将所有数组切换为numpy数组(因为这是我的移动平均值函数的输出格式),然后尝试将if条件添加到追加在while循环中,但都没有起作用。
import random
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
def movingaverage(values, window):
weights = np.repeat(1.0, window) / window
smas = np.convolve(values, weights, 'valid')
return smas
sampleSize = 100
min = -10
max = 10
window = 5
vX = np.array([])
vY = np.array([])
x = 0
val = 0
while x < sampleSize:
val += (random.randint(min, max))
vY = np.append(vY, val)
vX = np.append(vX, x)
x += 1
plt.plot(vX, vY)
plt.plot(vX, movingaverage(vY, window))
plt.show()
预期结果将是同一张图上的两条线-一个是另一条的简单移动平均值。
答案 0 :(得分:1)
这里是如何用'nan's将numpy数组填充到所需的长度(根据需要的结果,将'nan'替换为其他值,或将'constant'替换为其他模式) https://docs.scipy.org/doc/numpy/reference/generated/numpy.pad.html
import numpy as np
bob = np.asarray([1,2,3])
alice = np.pad(bob,(0,100-len(bob)),'constant',constant_values=('nan','nan'))
所以在您的代码中,它看起来像这样:
import random
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
def movingaverage(values,window):
weights = np.repeat(1.0,window)/window
smas = np.convolve(values,weights,'valid')
shorted = int((100-len(smas))/2)
print(shorted)
smas = np.pad(smas,(shorted,shorted),'constant',constant_values=('nan','nan'))
return smas
sampleSize = 100
min = -10
max = 10
window = 5
vX = np.array([])
vY = np.array([])
x = 0
val = 0
while x < sampleSize:
val += (random.randint(min,max))
vY = np.append(vY,val)
vX = np.append(vX,x)
x += 1
plt.plot(vX,vY)
plt.plot(vX,(movingaverage(vY,window)))
plt.show()
答案 1 :(得分:1)
只需将此行更改为以下内容:
smas = np.convolve(values, weights,'same')
“有效”选项仅在窗口完全覆盖values数组时才卷积。您想要的是“相同”,它可以满足您的需求。
答案 2 :(得分:1)
要回答您的基本问题,关键是截取与移动平均值数据相对应的x轴切片。由于您将100个数据元素与一个大小为5的窗口进行卷积,因此结果对最后96个元素有效。您将这样绘制它:
plt.plot(vX[window - 1:], movingaverage(vY, window))
话虽如此,您的代码可以对它进行一些优化。例如,numpy数组存储在固定大小的静态缓冲区中。每次对它们进行追加或删除操作时,都将重新分配整个内容,这与内置了摊销功能的Python列表不同。如果事先知道数组大小(这样做),总是最好进行预分配。
第二,很少需要运行显式循环。通常,最好使用numpy函数中最低级别实现的后台循环。这称为向量化。随机数生成,累加和和增量数组都在numpy中完全矢量化。从更一般的意义上讲,混合使用Python和numpy计算函数(包括random
)通常不是很有效。
最后,您可能需要考虑其他卷积方法。我建议基于numpy.lib.stride_tricks.as_strided
的内容。这是一种有点不可思议但非常有效的方法,可以实现带有numpy数组的滑动窗口。我将在这里展示它作为您使用的卷积方法的替代方法,但是请随时忽略此部分。
总共:
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
def movingaverage(values, window):
# this step creates a view into the same buffer
values = np.lib.stride_tricks.as_strided(values, shape=(window, values.size - window + 1), strides=values.strides * 2)
smas = values.sum(axis=0)
smas /= window # in-place to avoid temp array
return smas
sampleSize = 100
min = -10
max = 10
window = 5
v_x = np.arange(sampleSize)
v_y = np.cumsum(np.random.random_integers(min, max, sampleSize))
plt.plot(v_x, v_y)
plt.plot(v_x[window - 1:], movingaverage(v_y, window))
plt.show()
关于名称的说明:在Python中,变量和函数的名称通常为name_with_underscore。 CamelCase保留用于类名。 np.random.random_integers
像random.randint
一样使用包含边界,但是允许您指定要生成的样本数。令人困惑的是,np.random.randint
有一个专有的上限,更像random.randrange
。