Как вычислить среднее значение в пределах заданных процентилей в Python? - PullRequest
2 голосов
/ 10 июля 2020

Я занимаюсь научными c вычислениями и не могу найти элегантного способа выполнить следующую операцию. Предположим, у меня есть двумерный numpy массив D, который хранит измерения заданного количества несколько раз в течение дня. Каждая строка соответствует разному измерительному прибору, а каждый столбец соответствует разному моменту дня, в который проводилось измерение.

Рассмотрим список желаемых процентилей. Например:

quantiles = [0.25, 0.5, 0.75]

Моя цель - вычислить среднее значение по группе процентилей в каждый момент дня. Другими словами, учитывая столбец измерений, я хотел бы отсортировать все измерения из этого столбца по группам в соответствии с приведенными выше квантилями, а затем взять средние значения по группам. Используя этот пример, у меня было бы 4 группы в каждый момент дня: измерения в нижнем квартиле, затем измерения между 25-м и 50-м квартилем, измерения между 50-м и 75-м и, наконец, измерения в последнем квартиле. Следовательно, если m - это количество моментов в день, когда проводились измерения, а q - это количество элементов в переменной quantiles, мой желаемый результат будет q x m numpy массив .

В настоящее время я делаю это самым неэффективным и жестко запрограммированным способом. Здесь мы go:

quantiles = [0.25, 0.5, 0.75]
window = "30min"
moments = pd.date_range(start = "9:30", end = "16:00", freq = window).time
quantile_curves = np.zeros((len(quantiles)+1, len(moments)-1))
EmpQuantiles = np.quantile(D, quantiles, axis = 0)
for moment in range(len(moments)-1):
    quantile_curves[0, moment] = np.mean(D[:, moment][D[:,moment] < EmpQuantiles[0, moment]])
    quantile_curves[1, moment] = np.mean(D[:, moment][np.logical_and(D[:,moment] > EmpQuantiles[0, moment], D[:,moment] <EmpQuantiles[1, moment])])
    quantile_curves[2, moment] = np.mean(D[:, moment][np.logical_and(D[:,moment] > EmpQuantiles[1, moment], D[:,moment] <EmpQuantiles[2, moment])])
    quantile_curves[3, moment] = np.mean(D[:, moment][D[:,moment] > EmpQuantiles[2, moment]])

Какой изящный и простой способ сделать это? Я не смог найти здесь ответ, однако в R есть связанный (но не тот же) вопрос: ddply множественные квантили по группам

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

введите описание изображения здесь

Заранее большое спасибо!

1 Ответ

1 голос
/ 10 июля 2020

Вы можете сделать это эффективно, используя masked_arrays :

import numpy as np

quantiles = [0.25, 0.5, 0.75]
print('quantiles:\n', quantiles)

moments = [f'moment {i}' for i in range(5)]
print('nb of moments:\n', len(moments))
nb_measurements = 10000
D = np.random.rand(nb_measurements,len(moments))
quantile_values = np.quantile(D,quantiles,axis=0)
print('quantile_values (for each moment):\n', quantile_values)

quantile_curves = np.zeros((len(quantiles)+1,len(moments)))
quantile_curves[0, :] = np.mean(np.ma.masked_array(D, mask=D>quantile_values[[0],:]), axis=0)
for q in range(len(quantiles)-1):
  quantile_curves[q+1, :] = np.mean(np.ma.masked_array(D, mask=np.logical_or(D<quantile_values[[q],:], D>quantile_values[[q+1],:])), axis=0)
quantile_curves[len(quantiles), :] = np.mean(np.ma.masked_array(D, mask=D<quantile_values[[len(quantiles)-1],:]), axis=0)

print('mean for each group and at each moment:')
print(quantile_curves)

Вывод:

% python3 script.py
quantiles:
 [0.25, 0.5, 0.75]
nb of moments:
 5
quantile_values (for each moment):
 [[0.25271343 0.25434056 0.24658732 0.24612319 0.25221014]
 [0.51114344 0.50103699 0.49671249 0.49113293 0.49819521]
 [0.75629377 0.75427293 0.74676209 0.74211813 0.7490436 ]]
mean for each group and at each moment
[[0.12650993 0.12823392 0.12492136 0.12200609 0.12655318]
 [0.3826476  0.373516   0.37050513 0.36974876 0.37722219]
 [0.63454102 0.63023986 0.62280545 0.61696283 0.6238492 ]
 [0.87866019 0.87614489 0.87492553 0.87253142 0.87403426]]

Обратите внимание, что я использую случайные значения от 0 до 1, которые почему значения квантилей (границы интервалов групп) почти равны квантилям. Также нельзя сказать, что этот код работает для произвольного количества квантилей или моментов.

...