Нормализация гистограммы с помощью matplotlib



Я хочу построить гистограмму с помощью Matplotlib, но я хотел бы, чтобы значения ячеек представляли процент от общего числа наблюдений. MWE будет выглядеть так:



#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import matplotlib.pyplot as plt
import matplotlib.ticker as tck
import seaborn as sns
import numpy

sns.set(style='dark')

imagen2 = plt.figure(1, figsize=(5, 2))
imagen2.suptitle('StackOverflow Matplotlib histogram demo')

luminance = numpy.random.randn(1000, 1000)
# "Luminance" should range from 0.0...1.0 so we normalize it
luminance = (luminance - luminance.min())/(luminance.max() - luminance.min())

top_left = plt.subplot(121)
top_left.imshow(luminance)
bottom_left = plt.subplot(122)
sns.distplot(luminance.flatten(), kde_kws={"cumulative": True})

# plt.savefig("stackoverflow.pdf", dpi=300)
plt.tight_layout(rect=(0, 0, 1, 0.95))
plt.show()


CDF здесь в порядке (диапазон: [0, 1]), но полученная гистограмма не соответствует моим ожиданиям:



Гистограмма со значениями вне допустимого диапазона



Почему результаты гистограммы находятся в диапазоне [0, 4]? Есть ли способ исправить это?

645   2  

2 ответов:

Что ты думаешь, что хочешь

Вот как построить гистограмму таким образом, чтобы ячейки суммировались в 1:

import matplotlib.pyplot as plt
import matplotlib.ticker as tck
import seaborn as sns
import numpy as np

sns.set(style='dark')

imagen2 = plt.figure(1, figsize=(5, 2))
imagen2.suptitle('StackOverflow Matplotlib histogram demo')

luminance = numpy.random.randn(1000, 1000)
# "Luminance" should range from 0.0...1.0 so we normalize it
luminance = (luminance - luminance.min())/(luminance.max() - luminance.min())

# get the histogram values
heights,edges = np.histogram(luminance.flat, bins=30)
binCenters = (edges[:-1] + edges[1:])/2

# norm the heights
heights = heights/heights.sum()

# get the cdf
cdf = heights.cumsum()

left = plt.subplot(121)
left.imshow(luminance)
right = plt.subplot(122)
right.plot(binCenters, cdf, binCenters, heights)

# plt.savefig("stackoverflow.pdf", dpi=300)
plt.tight_layout(rect=(0, 0, 1, 0.95))
plt.show()

# confirm that the hist vals sum to 1
print('heights sum: %.2f' % heights.sum())

Вывод:

Введите описание изображения здесь

heights sum: 1.00

Фактический ответ

На самом деле это очень просто. Просто сделай

sns.distplot(luminance.flatten(), kde_kws={"cumulative": True}, norm_hist=True)

Вот что я получаю, когда запускаю ваш скрипт с вышеуказанной модификацией:

Введите описание изображения здесь

Неожиданный поворот!

Таким образом, получается, что ваша гистограмма была нормализована все время, в соответствии с формальным идентичность:

Введите описание изображения здесь

На простом (er) английском языке общей практикой является нормирование непрерывно оцениваемых гистограмм (то есть их наблюдения могут быть выражены как число с плавающей точкой) в терминах их плотности. Таким образом, в этом случае сумма ширины ячейки, умноженная на высоту ячейки, будет равна 1,0, как вы можете видеть, запустив эту упрощенную версию вашего скрипта:
import matplotlib.pyplot as plt
import matplotlib.ticker as tck
import numpy as np

imagen2 = plt.figure(1, figsize=(4,3))
imagen2.suptitle('StackOverflow Matplotlib histogram demo')

luminance = numpy.random.randn(1000, 1000)
luminance = (luminance - luminance.min())/(luminance.max() - luminance.min())

heights,edges,patches = plt.hist(luminance.ravel(), density=True, bins=30)
widths = edges[1:] - edges[:-1]

totalWeight = (heights*widths).sum()

# plt.savefig("stackoverflow.pdf", dpi=300)
plt.tight_layout(rect=(0, 0, 1, 0.95))
plt.show()
print(totalWeight)

И totalWeight действительно будут точно равны 1.0, плюс-минус небольшая ошибка округления.

Comments

    Ничего не найдено.