如何强制两个数组在pyplot中相等?

时间:2019-07-04 02:42:34

标签: python numpy matplotlib

我试图绘制一个简单的移动平均线函数,但结果数组比完整样本大小少了几个数字。如何在延伸整个样本大小的标准线旁边绘制这样的线?下面的代码导致此错误消息:

ValueError: x and y must have same first dimension, but have shapes (96,) and (100,)

这使用的是标准matplotlib.pyplot。我试过只使用removedel删除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()

预期结果将是同一张图上的两条线-一个是另一条的简单移动平均值。

3 个答案:

答案 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数组时才卷积。您想要的是“相同”,它可以满足您的需求。


编辑:但是,这也有其自身的问题,因为当您的窗口未完全位于数据之上时,它的作用就好像有额外的值为0的数据位。如果选择该选项,可以忽略不计,就像在此解决方案中一样,但是另一种方法是使用您选择的特定值填充数组(请参见Mike Sperry的答案)。

答案 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_integersrandom.randint一样使用包含边界,但是允许您指定要生成的样本数。令人困惑的是,np.random.randint有一个专有的上限,更像random.randrange