Eu gostaria de traçar um histograma normalizado de um vetor usando matplotlib. Tentei o seguinte:
plt.hist(myarray, normed=True)
assim como:
plt.hist(myarray, normed=1)
mas nenhuma das opções produz um eixo y de [0, 1] de forma que as alturas das barras do histograma somam 1. Eu gostaria de produzir esse histograma - como posso fazer isso?
Respostas:
Seria mais útil se você apresentasse um exemplo funcional (ou, neste caso, não funcional) mais completo.
Tentei o seguinte:
import numpy as np import matplotlib.pyplot as plt x = np.random.randn(1000) fig = plt.figure() ax = fig.add_subplot(111) n, bins, rectangles = ax.hist(x, 50, density=True) fig.canvas.draw() plt.show()
Isso realmente produzirá um histograma de gráfico de barras com um eixo y que vai de
[0,1]
.Além disso, de acordo com a
hist
documentação (ou seja,ax.hist?
deipython
), acho que a soma também é adequada:*normed*: If *True*, the first element of the return tuple will be the counts normalized to form a probability density, i.e., ``n/(len(x)*dbin)``. In a probability density, the integral of the histogram should be 1; you can verify that with a trapezoidal integration of the probability density function:: pdf, bins, patches = ax.hist(...) print np.sum(pdf * np.diff(bins))
Experimente depois dos comandos acima:
np.sum(n * np.diff(bins))
Recebo um valor de retorno
1.0
conforme o esperado. Lembre-se de quenormed=True
isso não significa que a soma do valor em cada barra será a unidade, mas, em vez da integral sobre as barras, a unidade. No meu casonp.sum(n)
retornou aprox7.2767
.fonte
Se você quiser que a soma de todas as barras seja igual à unidade, pondere cada caixa pelo número total de valores:
weights = np.ones_like(myarray) / len(myarray) plt.hist(myarray, weights=weights)
Espero que ajude, embora o tópico seja bastante antigo ...
Nota para Python 2.x: adicione fundição a
float()
para um dos operadores da divisão, caso contrário, você terminaria com zeros devido à divisão inteirafonte
array_like
em vez de uma matriz numpy você precisará elencolen(myarray)
parafloat
.Sei que esta resposta é tarde demais, considerando que a pergunta é datada de 2010, mas me deparei com essa pergunta porque eu mesmo estava enfrentando um problema semelhante. Como já foi afirmado na resposta, normed = True significa que a área total sob o histograma é igual a 1, mas a soma das alturas não é igual a 1. No entanto, eu queria, para conveniência da interpretação física de um histograma, fazer um com soma de alturas igual a 1.
Encontrei uma dica na seguinte pergunta - Python: Histograma com área normalizada para algo diferente de 1
Mas não consegui encontrar uma maneira de fazer as barras imitarem o recurso histtype = "step" hist (). Isso me desviou para: Matplotlib - histograma em etapas com dados já armazenados
Se a comunidade considerar aceitável, gostaria de apresentar uma solução que sintetize as ideias de ambas as postagens acima.
import matplotlib.pyplot as plt # Let X be the array whose histogram needs to be plotted. nx, xbins, ptchs = plt.hist(X, bins=20) plt.clf() # Get rid of this histogram since not the one we want. nx_frac = nx/float(len(nx)) # Each bin divided by total number of objects. width = xbins[1] - xbins[0] # Width of each bin. x = np.ravel(zip(xbins[:-1], xbins[:-1]+width)) y = np.ravel(zip(nx_frac,nx_frac)) plt.plot(x,y,linestyle="dashed",label="MyLabel") #... Further formatting.
Isso funcionou maravilhosamente para mim, embora em alguns casos eu tenha notado que a "barra" mais à esquerda ou a "barra" mais à direita do histograma não fecha ao tocar o ponto mais baixo do eixo Y. Nesse caso, adicionar um elemento 0 no início ou no final de y alcançou o resultado necessário.
Só pensei em compartilhar minha experiência. Obrigado.
fonte
Aqui está outra solução simples usando o
np.histogram()
método.myarray = np.random.random(100) results, edges = np.histogram(myarray, normed=True) binWidth = edges[1] - edges[0] plt.bar(edges[:-1], results*binWidth, binWidth)
Você pode, de fato, verificar se o total é de até 1 com:
> print sum(results*binWidth) 1.0
fonte