Как сгенерировать две отдельные оси Y для гистограммы на одном и том же рисунке в Seaborn

#python #statistics #seaborn #histogram #kernel-density

#python #Статистика #seaborn #гистограмма #Плотность ядра

Вопрос:

Я хотел бы сгенерировать одну фигуру, которая имеет две оси y: Count (из гистограммы) и Density (из KDE).

Я хочу использовать sns.displot в Seaborn >= v 0.11 .

 import seaborn as sns

df = sns.load_dataset('tips')

# graph 1: This should be the Y-Axis on the left side of the figure
sns.displot(df['total_bill'], kind='hist', bins=10)

# graph 2: This should be the Y-axis on the right side of the figure
sns.displot(df['total_bill'], kind='kde')
 

Написанный мной код генерирует два отдельных графика; я мог бы просто использовать сетку фасетов для двух отдельных графиков, но я хочу быть более кратким и поместить две оси y на двух отдельных сетках в одну фигуру, разделяющую одну и ту же ось x.

seaborn_tips_dataset_dist

Ответ №1:

displot() это функция уровня рисунка, которая может создавать несколько подзаголовков внутри рисунка. Таким образом, у вас нет контроля над отдельными осями.

Для создания комбинированных графиков вы можете использовать функции уровня базовых осей: histplot() и kdeplot() для Seaborn v.0.11. Эти функции принимают ax= параметр. twinx() создает вторую ось y.

 import matplotlib.pyplot as plt
import seaborn as sns

df = sns.load_dataset('tips')

fig, ax = plt.subplots()

sns.histplot(df['total_bill'], bins=10, ax=ax)

ax2 = ax.twinx()
sns.kdeplot(df['total_bill'], ax=ax2)

plt.tight_layout()
plt.show()
 

результирующий график

Редактировать:

Как упоминалось в комментариях, оси y не выровнены. Левая ось только что-то говорит о гистограмме. Например. самая высокая ячейка, имеющая высоту 68, означает, что между и находится ровно 68 счетов 12.618 17.392 . Правая ось только что-то говорит о kde. Например. значение y 0.043 для x=20 будет означать, что вероятность того, что общий счет будет находиться между и, составляет около 4,3% 19.5 20.5 .

Чтобы выровнять обе похожие sns.histplot(..., kde=True) , можно вычислить площадь гистограммы (ширина ячейки, умноженная на количество значений данных) и использовать в качестве коэффициента масштабирования. Такое масштабирование сделало бы площадь гистограммы и область под кривой kde равными при измерении в пикселях:

 num_bins = 10
bin_width = (df['total_bill'].max() - df['total_bill'].min()) / num_bins
hist_area = len(df) * bin_width
ax2.set_ylim(ymax=ax.get_ylim()[1] / hist_area)
 

масштабированный график kde

Обратите внимание, что правая ось была бы более похожа на процент, если бы гистограмма использовала ширину ячейки со степенью десять (например sns.histplot(..., bins=np.arange(0, df['total_bill'].max() 10, 10) ). Какие ячейки будут наиболее подходящими, сильно зависит от того, как вы хотите интерпретировать свои данные.

Комментарии:

1. Хорошее объяснение различия между уровнем рисунка и уровнем осей, но если вы буквально хотите, чтобы кривая KDE находилась поверх гистограммы, вы должны добавить kde=True к histplot вызову (или displot ). Правда, это не даст вам обе оси y, но на самом деле они не эквивалентны здесь так, как подразумевает график (ограничения устанавливаются автоматическим масштабированием matplotlib для художников, а не математической зависимостью между количеством / плотностью), и ось плотности в любом случае не поддается интерпретации.

2. Хорошая проработка; вы точно правильно указываете интерпретацию значения плотности в своем редактировании. Просто отмечу для других, что «плотность» в качестве значения оси y имеет очень высокую вероятность неправильного толкования, поэтому будьте осторожны при отображении такого графика.