Создать 2D-историю с одинаковым количеством точек в каждой ячейке - PullRequest
0 голосов
/ 17 ноября 2018

Я ищу возможность создания 2D гистограммы с нерегулярными размерами бинов с возможностью построения графика нагрева в качестве переменной z.

Данные: у меня один миллиард объектов. Каждый объект имеет особенности x, y и оценку аномалии z.

Сюжет: все объекты с у против х. Гистограмма должна иметь неправильные (адаптивные) размеры ячеек, чтобы в каждом создаваемом ящике было одинаковое количество объектов. Первоначально это должно создать гистограмму без видимых признаков, имеющую только один цвет (с цветом, представляющим количество объектов).

Чтобы создать ребра ящика, я сначала использую np.percentiles и разделяю объекты на основе функции x на процентили. Во-вторых, я использую первый x binedge, нахожу все точки в нем и складываю их в направлении y на основе процентилей. Это будет выглядеть примерно так (псевдокод):

for i, key_x in enumerate(np.percentile(x, np.arange(0,101, 10))):
    xedges[i] = key_x
    objects = find_all_objects_within_binedge(key_x)

    for j, key_y in enumerate(np.percentile(objects["y"], np.arange(0,101, 10))):
        yedges[i, j] = key_y

Таким образом, xedges - это массив с бинджами в направлении x, а yedges - это матрица, дающая мне y-байнги для каждого x-бинджа. Если это не понятно, пожалуйста, дайте мне знать.

Итак, если мы представим гистограмму, которая в результате получится, у нас будут прямые линии биннинга в x Но в направлении у эти линии будут разделены. См. здесь , чтобы получить представление о том, что я имею в виду, когда y-ые ячейки нерегулярно разделены.

И вот где я застрял. Я понятия не имею, как создать гистограмму или график из моих x-binesges и y-binesges с этими нерегулярными ячейками.

Цель (для лучшего понимания): Как только это будет выполнено, я бы хотел иметь возможность окрашивать каждый бин по среднему или стандартному значению всех точек в этой ячейке, используя значения z (подготовьте код для этого). В идеале это также будет выглядеть очень гладко, за некоторыми незначительными исключениями, которые будут аномальными и то, что я ищу. Но это должно быть осуществимо с помощью plt.pcolormesh.

Английский не мой родной язык, и я изо всех сил старался описать проблему. Если что-то неясно, пожалуйста, дайте мне знать, и я постараюсь уточнить как можно лучше. Заранее спасибо, ребята :) 1024 *

Ответы [ 2 ]

0 голосов
/ 17 ноября 2018

Кажется, вопрос требует способа построения значений на сетке, которая является регулярной в одном измерении, но нерегулярной в другом.
Насколько я понимаю, такая сетка будет определяться массивом 1D, например, x-направление и 2D-массив в y-направлении. Оба массива будут обозначать края ячеек сетки в соответствующем измерении.

Для сетки M x N x_edges, следовательно, будет иметь N+1 элементов, а y_edges будет иметь форму (M+1, N). Следующее будет сетка 4 х 3.

x_edges = np.array([0,1,2,3])
y_edges = np.array([[0.,0.,0.],
                    [.3,.2,.2],
                    [.5,.6,.4],
                    [.8,.9,.7],
                    [1.,1.,1.]])

Обычные инструменты matplotlib, такие как imshow или pcolor, делают - насколько я вижу - не позволяют строить такие сетки. Следовательно, альтернативой является использование PolyCollection и нанесение на него соответствующих прямоугольников.

Массив значений, которые должны быть сопоставлены с цветом, может быть установлен для этой коллекции. Этот массив должен иметь на одно значение меньше размера и быть плоским, т.е. иметь M * N элементов.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection

# Starting data: A grid, regular in x-direction and irregular in y direction.
x_edges = np.array([0,1,2,3])
y_edges = np.array([[0.,0.,0.],
                    [.3,.2,.2],
                    [.5,.6,.4],
                    [.8,.9,.7],
                    [1.,1.,1.]])

######## Grid creation ################
#y_edges = np.concatenate((y_edges, np.zeros(len(y_edges))))
s = np.array(y_edges.shape)
# make x_edges 2D as well.
x_edges = np.tile(x_edges, s[0]-1).reshape((s[0]-1, s[1]+1))

# you may also have an array of values. 
# This should be of shape one less than the edges and flattened.
values = np.arange(np.prod(s+np.array((-1,0))))

# Produce a vertices array of the edges of rectangles that form each pixel.
x = np.c_[x_edges[:,:-1].flatten(), x_edges[:,:-1].flatten(),
          x_edges[:,1: ].flatten(), x_edges[:,1: ].flatten()]
y = np.c_[y_edges[:-1,:].flatten(), y_edges[1: ,:].flatten(),
          y_edges[1: ,:].flatten(), y_edges[:-1,:].flatten()]
xy = np.stack((x,y), axis=2)

# Create collection of rectangles.
pc = PolyCollection(xy, closed=True, edgecolors="k", linewidth=0.72, cmap="inferno")
pc.set_array(values)

######## Plotting ################
fig, ax = plt.subplots()
ax.add_collection(pc)
fig.colorbar(pc, ax=ax)

ax.margins(0)
ax.autoscale()
plt.show()

enter image description here

Эта сетка использует небольшое количество ячеек, чтобы показать принцип. Если вы хотите иметь больше ячеек, постарайтесь не рисовать края прямоугольников, удалив аргументы edgecolors и linewidth.

0 голосов
/ 17 ноября 2018

Из того, что я понимаю, вы хотите, чтобы данные были сгруппированы на основе равных объемов данных в корзине.Действительно процентили могут быть использованы для этой цели.Если вы используете NumPy вы можете сделать это по D измерения.Вот пример для 2d binning:

import matplotlib.pyplot as plt
from numpy import array, random, percentile

data = random.randn(1000, 2)
data[:, 1] = data[:, 1] * .1 + 1 # shift the gauss


percentiles = percentile(data, range(0, 100, 10), axis = 0)

fig, ax = plt.subplots()
ax.hist2d(*data.T, bins = percentiles.T)
fig.show()

Это то, что вы искали?

Редактировать: пример неравномерной сетки

import matplotlib.pyplot as plt
from numpy import *
data = random.randn(1000, 2)
data[:, 1] = data[:, 1] * .1 + 1 # shift the gauss

xper = percentile(data[:, 0], range(0, 101, 10))
yper = zeros((xper.size, xper.size))

binnedData = ones(yper.shape)
for index, (binstart, binend) in enumerate(zip(xper[:-1], xper[1:])):
    idx = where(logical_and(data[:, 0] >= binstart, data[:, 0] <= binend))[0] # expensive
    yper[index] = percentile(data[idx, 1], range(0, 101, 10))
    for jndex, j in  enumerate(digitize(data[idx, 1], yper[index])):
        j -= 1 #digit takes right bins
        # generate dummy values
        binnedData[index, j] += data[idx[j], :].sum() /  xper.size
fig, ax = plt.subplots()
ax.pcolormesh(xper, yper, binnedData)

non uni

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...