Гистограммы с большим количеством измерений в Python - PullRequest
0 голосов
/ 14 июля 2020

Я выполняю моделирование сточасти c системы многих тел, и в настоящее время мне нужно получить многомерное распределение вероятностей из сгенерированных данных. Для этой цели я пытался использовать np.histogramdd как в:

bins = np.linspace(start = -x_max, stop = x_max, num = n_bins)
hists = np.histogramdd(Data, bins = [bins] * dimensions, density = True)

Однако этот код выдает ошибку MemoryError (или генерирует исключение о том, что какой-то массив слишком велик) уже для n_bins = 20, dimensions = 5 и np.shape(Data) = (1000, 5), что намного ниже целевых значений. Количество корзин растет экспоненциально с увеличением числа измерений, поэтому легко понять, почему возникают такие проблемы. Итак, возникает вопрос: как можно сгенерировать, сохранить и обработать гистограмму большой размерной величины в Python? Существуют ли для этого какие-либо рамки? Лучше переключиться на что-то другое?

Edit: MCEV и примеры кодов ошибок.

x_max = 10 
n_bins = 20 
Data = np.random.uniform(-x_max, x_max, size=(1000, dimensions))

bins = np.linspace(start = -x_max, stop = x_max, num = n_bins)
hists = np.histogramdd(Data, bins = [bins] * dimensions, density = True)

Ставя dimensions = 7, получаю:

lib\site-packages\numpy\lib\histograms.py in histogramdd(sample, bins, range, normed, weights, density)
1066 # Compute the number of repetitions in xy and assign it to the
1067 # flattened histmat.
-> 1068  hist = np.bincount(xy, weights, minlength=nbin.prod())
MemoryError:

dimensions = 15:

   1062     # Compute the sample indices in the flattened histogram matrix.
   1063     # This raises an error if the array is too large.
-> 1064     xy = np.ravel_multi_index(Ncount, nbin)
   1065 
   1066     # Compute the number of repetitions in xy and assign it to the

ValueError: invalid dims: array size defined by dims is larger than the maximum possible size. 

dimensions = 10

   1066     # Compute the number of repetitions in xy and assign it to the
   1067     # flattened histmat.
-> 1068     hist = np.bincount(xy, weights, minlength=nbin.prod())
   1069 
   1070     # Shape into a proper matrix

ValueError: 'minlength' must not be negative

1 Ответ

0 голосов
/ 14 июля 2020

Если гистограмма имеет фиксированную ширину ячейки на каждой оси, вы можете вести учет и использовать тип данных с низким объемом памяти для подсчетов (например, 1 байт на ячейку). В следующем примере интервалы одинаковы для каждой оси, но вы можете адаптировать его для диапазонов интервалов, которые различаются по осям, если края интервалов равноудалены.

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

import numpy as np

x_max = 10 
n_dim = 7
n_data = 100000
data = np.random.uniform(-x_max, x_max-0.01, size=(n_data, n_dim))

# assume bins are the same for all dimensions. Bin edges at x0+i*xstep.
n_bins = 5
x0 = -x_max
xstep = 2*x_max/n_bins

# high-dimensional histogram
hist = np.zeros((n_bins,)*n_dim, dtype=np.int8)

# build the histogram indices corresponding to the data samples.
ii = ((data - x0)*(1/xstep)).astype(np.int16) # shape (n_data, n_dim)

# increment the histogram bins. The np.add.at will correctly handle 
# bins that occur multiple times in the input.
np.add.at(hist, tuple(ii.T), 1)

Но с n_dim=8 или 9 у вас закончится память в большинстве случаев. системы в любом случае.

Вопрос в том, что вы собираетесь делать с гистограммой, имеющей 10**10 интервалов; у вас есть 10 ** 11 или более образцов?

Более практично хранить массив ii и генерировать гистограммы меньшей размерности, когда они вам нужны. Например, если вы хотите уменьшить гистограмму 7D до гистограммы 4D по осям 0, 1, 5, 6:

hist_4d = np.zeros((n_bins,)*4, dtype=np.int16)
np.add.at(hist_4d, tuple(ii[:, [0, 1, 5, 6]].T), 1)

Примечание: я рекомендую вам использовать целые числа со знаком для подсчета интервалов. Целочисленные переполнения будут тихими, но, по крайней мере, отрицательные числа в ячейках будут указывать на то, что у вас произошло переполнение.

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