J'essaie de tracer une simple fonction de moyennes mobiles, mais le tableau résultant contient quelques nombres inférieurs à la taille totale de l'échantillon. Comment tracer une telle ligne à côté d'une ligne plus standard qui s'étend sur toute la taille de l'échantillon? Le code ci-dessous entraîne ce message d'erreur:
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()
Ceci utilise la norme matplotlib.pyplot . J'ai simplement essayé de supprimer les valeurs X en utilisant remove et del ainsi que de changer tous les tableaux en tableaux numpy (puisque c'est le format de sortie de ma fonction de moyennes mobiles), puis j'ai essayé d'ajouter une condition if à l'ajout dans la boucle while mais aucune n'a fonctionné.
ValueError: x and y must have same first dimension, but have shapes (96,) and (100,)
Les résultats attendus seraient deux lignes sur le même graphique - l'une une simple moyenne mobile de l'autre.
3 Réponses :
Voici comment remplir un tableau numpy à la longueur souhaitée avec 'nan's (remplacer' nan 'par d'autres valeurs, ou remplacer' constant 'par un autre mode en fonction des résultats souhaités) https://docs.scipy.org/doc/numpy/ reference / generated / numpy.pad.html
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()
Donc, dans votre code, cela ressemblerait à ceci:
import numpy as np
bob = np.asarray([1,2,3])
alice = np.pad(bob,(0,100-len(bob)),'constant',constant_values=('nan','nan'))
p >
Je ne pense pas que le rembourrage soit nécessairement la bonne réponse ici.
Je l'ai mis à jour pour que le rembourrage soit uniforme à l'avant et à l'arrière, et il est rembourré avec «nan». Désormais, le pavé ne représente pas le graphique et les données restent correctement alignées.
Le rembourrage semble en fait idéal pour un autre problème que je regarde. La couverture détaillée est appréciée!
Le rembourrage avec Nan est bien meilleur. +1
Modifiez simplement cette ligne comme suit:
smas = np.convolve(values, weights,'same')
L'option 'valide' ne se converse que si la fenêtre couvre complètement le tableau des valeurs. Ce que vous voulez, c'est «pareil», qui fait ce que vous recherchez.
Ceci, cependant, vient aussi avec ses propres problèmes car il agit comme s'il y avait des bits supplémentaires de données avec la valeur 0 quand votre fenêtre ne repose pas entièrement sur les données. Cela peut être ignoré s'il est choisi, comme cela est fait dans cette solution, mais une autre approche consiste à remplir le tableau avec des valeurs spécifiques de votre choix à la place (voir la réponse de Mike Sperry).
Cela se déroule avec des données "zéro" hors de portée, et entraînera des queues invalides sur le graphique.
@MikeSperry Si c'est ce que veut l'utilisateur, alors ce n'est pas un problème.
Bien sûr, mais c'est sous-facultatif.
Différentes réponses ont des cas d'utilisation différents, comme l'indique clairement l'affiche. Si le message était le moyen idéal pour y parvenir, ce serait une chose. Ce n'est cependant pas le cas.
D'accord. Je n'ai pas voté contre votre réponse et j'ai préparé ma propre réponse à cause d'un problème similaire. Le simple fait d'inclure des informations sur le surplomb de données améliorerait votre réponse.
Pour répondre à votre question de base, la clé est de prendre une tranche de l'axe des x appropriée aux données de la moyenne mobile. Puisque vous avez une convolution de 100 éléments de données avec une fenêtre de taille 5, le résultat est valide pour les 96 derniers éléments. Vous le traceriez comme ceci:
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()
Cela étant dit, votre code pourrait supporter une optimisation. Par exemple, les tableaux numpy sont stockés dans des tampons statiques de taille fixe. Chaque fois que vous ajoutez ou supprimez dessus, le tout est réalloué, contrairement aux listes Python, qui ont un amortissement intégré. Il est toujours préférable de préallouer si vous connaissez la taille du tableau à l'avance (ce que vous faites). P >
Deuxièmement, exécuter une boucle explicite est rarement nécessaire. Vous êtes généralement mieux d'utiliser les boucles sous le capot implémentées au niveau le plus bas dans les fonctions numpy à la place. C'est ce qu'on appelle la vectorisation. La génération de nombres aléatoires, les sommes cumulées et les tableaux incrémentiels sont tous entièrement vectorisés dans numpy. Dans un sens plus général, il n'est généralement pas très efficace de mélanger des fonctions de calcul Python et numpy, y compris random.
Enfin, vous voudrez peut-être envisager une méthode de convolution différente. Je suggérerais quelque chose basé sur numpy .lib.stride_tricks.as_strided . C'est un moyen quelque peu mystérieux, mais très efficace, d'implémenter une fenêtre glissante avec des tableaux numpy. Je vais le montrer ici comme une alternative à la méthode de convolution que vous avez utilisée, mais n'hésitez pas à ignorer cette partie.
Dans l'ensemble:
plt.plot(vX[window - 1:], movingaverage(vY, window))
A remarque sur les noms: en Python, les noms de variables et de fonctions sont classiquement name_with_underscore. CamelCase est réservé aux noms de classes. np.random .random_integers utilise des limites inclusives tout comme random.randint , mais vous permet de spécifier le nombre d'échantillons à générer. Confusément, np .random.randint a une limite supérieure exclusive, plus comme random.randrange .
Comment décideriez-vous si vous réduisez le début ou la fin de vX?
Intéressant, je prendrai note de ces suggestions. Je n'ai commencé sur python que cette semaine, donc obtenir des commentaires sur l'optimisation de ma génération sera précieux.
@MikeSperry. La configuration présentée ici est interprétée comme "la moyenne des derniers éléments de window ". Vous pouvez le réinitialiser par n'importe quel nombre 0 x [window - k: -k] . Pour inclure la possibilité de k == 0 , utilisez x [window - k: -k if k else None]
Êtes-vous sûr que l'erreur indique 97? Ça devrait être 96, non?
@MadPhysicist C'est définitivement 96.
Pourriez-vous corriger le message d'erreur que vous affichez alors?