Как можно создать KDE только из значений гистограммы?

У меня есть набор значений, для которых я хотел бы построить оценку плотности ядра по Гауссу, однако у меня есть две проблемы:

  1. У меня есть только значения столбцов, а не сами значения
  2. Я рисую на категориальной оси

Вот сюжет, который я создал на данный момент: Как можно создать KDE только из значений гистограммы? Порядок оси Y на самом деле важен, поскольку он представляет филогению каждого вида бактерий.

Я хотел бы добавить гауссовское наложение kde для каждого цвета, но до сих пор мне не удалось использовать seaborn или scipy для этого.

Вот код для вышеупомянутой сгруппированной гистограммы с использованием python и matplotlib:

enterN = len(color1_plotting_values)
fig, ax = plt.subplots(figsize=(20,30))
ind = np.arange(N)    # the x locations for the groups
width = .5         # the width of the bars
p1 = ax.barh(Species_Ordering.Species.values, color1_plotting_values, width, label='Color1', log=True)
p2 = ax.barh(Species_Ordering.Species.values, color2_plotting_values, width, label='Color2', log=True)
for b in p2:
    b.xy = (b.xy[0], b.xy[1]+width)

Спасибо!

Похоже, вы берете данные из фрейма данных, вы пробовали встроенный функция построения графиков kde?

G. Anderson 18.12.2018 00:14

Да, пробовал, но не знаю, как заставить правильно интерпретировать категориальную ось. результирующий kde - это kde гистограммы данных. Однако данные уже представляют высоту столбцов гистограммы. Думайте о каждом виде бактерий как о корзине, а каждое число - как о количестве значений в этой корзине. Надеюсь, это поможет показать, как форматируются данные!

Joe B 18.12.2018 01:05

KDE обычно включает интеграцию по соседним точкам данных. Для категориальных данных, таких как ваш другой вид, нет критерия объективного расстояния (тем более того, который соблюдает неравенство треугольника). Следовательно, использование KDE здесь нежелательно и невозможно.

Paul Brodersen 18.12.2018 11:19

@PaulBrodersen, извините за вторжение, допустим, мы забываем, что данные являются категориальными, и смотрим на них как на гистограмму с равными ячейками, или, может быть, просто как на функцию в однородно выбранном домене. Можно ли запустить KDE в таких условиях? Я имею в виду без доступа к самим образцам, только к бинированной гистограмме

filippo 18.12.2018 16:47

@PaulBrodersen Вы правы, конечно, в том, что KDE не идеален, но здесь он весьма полезен, поскольку мы ищем общие тенденции в столбцах «гистограммы». ось Y здесь построена из филогенетического дерева. Филогенетические деревья действительно имеют объективный критерий расстояния, который я не включил выше. Мы только сохранили порядок видов здесь, потому что расстояние может добавить информацию, которую нам не нужно представлять.

Joe B 18.12.2018 19:21

@filippo Да! это в основном то, что я хочу знать. Можем ли мы оценить гауссовский KDE (или другой KDE) без примеров?

Joe B 18.12.2018 19:22

Филогенетическое «расстояние» не является истинное расстояние в математическом смысле, поскольку оно не удовлетворяет неравенству треугольника (пример здесь). Поэтому здесь вы не может применяете KDE (конечно, не на рисунке, который, как я полагаю, предназначен для академической публикации).

Paul Brodersen 19.12.2018 10:56

@filippo Вроде. В некотором смысле определение KDE по гистограмме аналогично KDE с использованием взвешенных выборок (что для большинства методов KDE является простым расширением). Проблема в том, что вы не знаете истинного положения точки внутри краев бункера. Поэтому, если ширина ядра равна или меньше ширины бункера, вы столкнетесь с проблемами (легко увидеть, если вы имитируете кучу точек на однородном интервале, примените алгоритм KDE по вашему выбору, а затем сравните результат с тем, когда вы округлите координаты точки до 1 значащей цифры). Тем не менее, широкие ядра подойдут.

Paul Brodersen 19.12.2018 11:05

@JoeB Существуют методы сглаживания, которые не зависят от ядра и, следовательно, не обязательно нуждаются в критерии расстояния, удовлетворяющем неравенству треугольника. На ум приходит оценка плотности k-ближайших соседей, взвешенная по обратному расстоянию. У меня есть реализация для общего случая здесь. Если сегодня у меня будет время, я могу придумать что-нибудь, что решит вашу проблему. Между тем, было бы полезно, если бы вы могли опубликовать данные, то есть значения бинов и матрицу филогенетических расстояний.

Paul Brodersen 19.12.2018 11:18

@PaulBrodersen Расслабьтесь. Взгляните на мой ответ. Не всегда есть интеграция.

user3103059 01.08.2019 11:34
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
8
10
4 980
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Как построить KDE, начиная с гистограммы

Протокол оценки плотности ядра требует лежащих в основе данных. Вы могли бы придумать новый метод, который вместо этого использует эмпирический pdf (то есть гистограмму), но тогда это не будет дистрибутив KDE.

Однако не вся надежда потеряна. Вы можете получить хорошее приближение распределения KDE, сначала взяв образцы из гистограммы, а затем используя KDE для этих образцов. Вот полный рабочий пример:

import matplotlib.pyplot as plt
import numpy as np
import scipy.stats as sts

n = 100000

# generate some random multimodal histogram data
samples = np.concatenate([np.random.normal(np.random.randint(-8, 8), size=n)*np.random.uniform(.4, 2) for i in range(4)])
h,e = np.histogram(samples, bins=100, density=True)
x = np.linspace(e.min(), e.max())

# plot the histogram
plt.figure(figsize=(8,6))
plt.bar(e[:-1], h, width=np.diff(e), ec='k', align='edge', label='histogram')

# plot the real KDE
kde = sts.gaussian_kde(samples)
plt.plot(x, kde.pdf(x), c='C1', lw=8, label='KDE')

# resample the histogram and find the KDE.
resamples = np.random.choice((e[:-1] + e[1:])/2, size=n*5, p=h/h.sum())
rkde = sts.gaussian_kde(resamples)

# plot the KDE
plt.plot(x, rkde.pdf(x), '--', c='C3', lw=4, label='resampled KDE')
plt.title('n = %d' % n)
plt.legend()
plt.show()

Вывод:

Красная пунктирная линия и оранжевая линия почти полностью перекрываются на графике, показывая, что реальные KDE и KDE, рассчитанные путем повторной выборки гистограммы, отлично согласуются.

Если ваши гистограммы действительно зашумлены (например, то, что вы получаете, если вы устанавливаете n = 10 в приведенном выше коде), вы должны быть немного осторожны при использовании передискретизированного KDE для чего-либо, кроме целей построения графика:

В целом соответствие между реальным и передискретизированным KDE по-прежнему хорошее, но отклонения заметны.

Внесите свои категориальные данные в соответствующую форму

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

Какова цель определения «x»? Не могли бы вы вместо этого использовать «е»?

KaPy3141 22.12.2021 12:08

Я высказал свои оговорки относительно применения KDE к категориальным данным OP в моих комментариях выше. По сути, поскольку филогенетическое расстояние между видами не подчиняется неравенству треугольника, не может быть действительного ядра, которое можно было бы использовать для оценки плотности ядра. Однако есть другие методы оценки плотности, которые не требуют построения ядра. Одним из таких методов является метод k-ближайшего соседа взвешивание с обратным расстоянием, который требует только неотрицательных расстояний, которые не должны удовлетворять неравенству треугольника (и даже не должны быть симметричными, я думаю). Ниже описывается этот подход:

import numpy as np

#--------------------------------------------------------------------------------
# simulate data

total_classes = 10
sample_values = np.random.rand(total_classes)
distance_matrix = 100 * np.random.rand(total_classes, total_classes)

# Distances to the values itself are zero; hence remove diagonal.
distance_matrix -= np.diag(np.diag(distance_matrix))

# --------------------------------------------------------------------------------
# For each sample, compute an average based on the values of the k-nearest neighbors.
# Weigh each sample value by the inverse of the corresponding distance.

# Apply a regularizer to the distance matrix.
# This limits the influence of values with very small distances.
# In particular, this affects how the value of the sample itself (which has distance 0)
# is weighted w.r.t. other values.
regularizer = 1.
distance_matrix += regularizer

# Set number of neighbours to "interpolate" over.
k = 3

# Compute average based on sample value itself and k neighbouring values weighted by the inverse distance.
# The following assumes that the value of distance_matrix[ii, jj] corresponds to the distance from ii to jj.
for ii in range(total_classes):

    # determine neighbours
    indices = np.argsort(distance_matrix[ii, :])[:k+1] # +1 to include the value of the sample itself

    # compute weights
    distances = distance_matrix[ii, indices]
    weights = 1. / distances
    weights /= np.sum(weights) # weights need to sum to 1

    # compute weighted average
    values = sample_values[indices]
    new_sample_values[ii] = np.sum(values * weights)

print(new_sample_values)

ЛЕГКИЙ СПОСОБ

На данный момент я пропускаю какие-либо философские аргументы о правомерности использования плотности ядра в таких настройках. Об этом позже.

Простой способ для этого использует scikit-learn KernelDensity:

import numpy as np
import pandas as pd
from sklearn.neighbors import KernelDensity
from sklearn import preprocessing

ds=pd.read_csv('data-by-State.csv')

Y=ds.loc[:,'State'].values # State is AL, AK, AZ, etc...

# With categorical data we need some label encoding here...
le = preprocessing.LabelEncoder()
le.fit(Y)                            # le.classes_ would be ['AL', 'AK', 'AZ',...
y=le.transform(Y)                    # y would be [0, 2, 3, ..., 6, 7, 9]
y=y[:, np.newaxis]                   # preparing for kde

kde = KernelDensity(kernel='gaussian', bandwidth=0.75).fit(y)

# You can control the bandwidth so the KDE function performs better
# To find the optimum bandwidth for your data you can try Crossvalidation

x=np.linspace(0,5,100)[:, np.newaxis] # let's get some x values to plot on
log_dens=kde.score_samples(x)
dens=np.exp(log_dens)            # these are the density function values

array([0.06625658, 0.06661817, 0.06676005, 0.06669403, 0.06643584,
       0.06600488, 0.0654239 , 0.06471854, 0.06391682, 0.06304861,
       0.06214499, 0.06123764, 0.06035818, 0.05953754, 0.05880534,
       0.05818931, 0.05771472, 0.05740393, 0.057276  , 0.05734634,
       0.05762648, 0.05812393, 0.05884214, 0.05978051, 0.06093455,
       ..............
       0.11885574, 0.11883695, 0.11881434, 0.11878766, 0.11875657,
       0.11872066, 0.11867943, 0.11863229, 0.11857859, 0.1185176 ,
       0.11844852, 0.11837051, 0.11828267, 0.11818407, 0.11807377])

И эти значения - все, что вам нужно для построения графика плотности ядра на гистограмме. Капитон?

Теперь, с теоретической точки зрения, если X - категориальная (*) неупорядоченная переменная с c возможными значениями, то для 0 ≤ час <1

- действующее ядро. Для упорядоченного X,

где |x1-x2| следует понимать как расстояние между x1 и x2 уровнями. Поскольку час стремится к нулю, оба они становятся индикаторами и возвращают подсчет относительной частоты. час часто упоминается как пропускная способность.


(*) Расстояние в пространстве переменных не требуется. Не обязательно должно быть метрическим пространством.

Devroye, Luc and Gábor Lugosi (2001). Combinatorial Methods in Density Estimation. Berlin: Springer-Verlag.

Другие вопросы по теме