Как вы можете создать KDE только из значений гистограммы? - PullRequest
0 голосов
/ 18 декабря 2018

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

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

Вот график, который я сгенерировал до сих пор: HISTOGRAM Порядок yось действительно важна, так как она представляет филогению каждого вида бактерий.

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

Вот код для вышеупомянутой сгруппированной гистограммы, использующей 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)

Спасибо!

Ответы [ 3 ]

0 голосов
/ 19 декабря 2018

Я изложил свои оговорки в отношении применения 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)
0 голосов
/ 29 июля 2019

ЛЕГКИЙ ПУТЬ

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

Простой способ сделать это - использовать 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])

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

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

enter image description here

является допустимым ядром.Для упорядоченного X,

enter image description here

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


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

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

0 голосов
/ 19 декабря 2018

Как построить «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()

Вывод:

enter image description here

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

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

enter image description here

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

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

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

...