выделите один столбец и суммируйте другой из (2,N) массива

#python #numpy

#python #numpy

Вопрос:

Вопрос:

У меня есть набор данных, подобный следующему:

 import numpy as np 
x = np.arange(0,10000,0.5)
y = np.arange(x.size)/x.size
  

При построении графика в пространстве log-log это выглядит следующим образом:

 import matplotlib.pyplot as plt
plt.loglog(x, y)
plt.show()
  

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

Очевидно, что на этом графике журнала много избыточной информации.
Мне не нужно 10000 точек, чтобы представить эту тенденцию.

Мой вопрос заключается в следующем: как я могу объединить эти данные, чтобы они отображали одинаковое количество точек в каждом порядке величины логарифмической шкалы? При каждом порядке величины я хотел бы получить около десяти баллов. Следовательно, мне нужно выделить ‘x’ с экспоненциально растущим размером ячейки, а затем взять среднее значение всех элементов y , соответствующих каждой ячейке.

Попытка:

Сначала я генерирую ячейки, для которых хочу использовать x .

 # need a nicer way to do this.
# what if I want more than 10 bins per order of magnitude? 
bins = 10**np.arange(1,int(round(np.log10(x.max()))))
bins = np.unique((bins.reshape(-1,1)*np.arange(0,11)).flatten())

#array([    0,     10,    20,    30,    40,    50,    60,    70,    80,
#          90,   100,   200,   300,   400,   500,   600,   700,   800,
#         900,  1000,  2000,  3000,  4000,  5000,  6000,  7000,  8000,
#        9000, 10000])
  

Во-вторых, я нахожу индекс ячейки, которому соответствует каждый элемент x:

 digits = np.digitize(x, bins) 
  

Теперь часть, с которой мне действительно нужна помощь. Я хочу взять среднее значение каждого элемента в y , соответствующего каждой ячейке, а затем построить график этих средних значений в зависимости от средних точек ячейки:

 # need a nicer way to do this.. is there an np.searchsorted() solution?
# this way is quick and dirty, but it does not scale with acceptable speed
averages = []
for d in np.unique(digits):
    mask = digits==d
    y_mean = np.mean(y[mask])
    averages.append(y_mean)
del mask, y_mean, d    

# now plot the averages within each bin against the center of each bin 
plt.loglog((bins[1:] bins[:-1])/2.0, averages)
plt.show()
  

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

Краткие сведения:
Есть ли более плавный способ сделать это? Как я могу сгенерировать произвольные n точки на порядок величины вместо 10?

Комментарии:

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

2. Привет @Anoop — это потому, что в этом примере len(averages) равно 28, а len(y) равно 10000, поэтому на первом графике 10000 точек, в то время как на втором меньше 30. В моем приложении наборы данных на самом деле содержат около 10 миллионов точек.

Ответ №1:

Я отвечу на два из ваших нескольких вопросов: Как альтернативно создать ячейки и сгенерировать произвольные n точки на порядок величины вместо 10?

Вы можете использовать np.logspace и np.outer для создания своих ячеек для любого произвольного n значения следующим образом. База по умолчанию в logspace равна 10. Он генерирует логарифмически разнесенные точки, аналогичные linspace который генерирует линейно разнесенную сетку.

Для n=10

 n = 10
bins = np.unique(np.outer(np.logspace(0, 3, 4), np.arange(0, n 1)))
# array([0.e 00, 1.e 00, 2.e 00, 3.e 00, 4.e 00, 5.e 00, 6.e 00, 7.e 00,
#        8.e 00, 9.e 00, 1.e 01, 2.e 01, 3.e 01, 4.e 01, 5.e 01, 6.e 01,
#        7.e 01, 8.e 01, 9.e 01, 1.e 02, 2.e 02, 3.e 02, 4.e 02, 5.e 02,
#        6.e 02, 7.e 02, 8.e 02, 9.e 02, 1.e 03, 2.e 03, 3.e 03, 4.e 03,
#        5.e 03, 6.e 03, 7.e 03, 8.e 03, 9.e 03, 1.e 04])
  

Для n=20

 n = 20
bins = np.unique(np.outer(np.logspace(0, 3, 4), np.arange(0, n 1)))
# array([0.0e 00, 1.0e 00, 2.0e 00, 3.0e 00, 4.0e 00, 5.0e 00, 6.0e 00, 7.0e 00, 8.0e 00, 9.0e 00, 1.0e 01, 1.1e 01, 1.2e 01, 1.3e 01, 1.4e 01, 1.5e 01, 1.6e 01, 1.7e 01, 1.8e 01, 1.9e 01, 2.0e 01, 3.0e 01, 4.0e 01, 5.0e 01, 6.0e 01, 7.0e 01, 8.0e 01, 9.0e 01, 1.0e 02, 1.1e 02, 1.2e 02, 1.3e 02, 1.4e 02, 1.5e 02, 1.6e 02, 1.7e 02, 1.8e 02, 1.9e 02, 2.0e 02, 3.0e 02, 4.0e 02, 5.0e 02, 6.0e 02, 7.0e 02, 8.0e 02, 9.0e 02, 1.0e 03, 1.1e 03, 1.2e 03, 1.3e 03, 1.4e 03, 1.5e 03, 1.6e 03, 1.7e 03, 1.8e 03, 1.9e 03, 2.0e 03, 3.0e 03, 4.0e 03, 5.0e 03, 6.0e 03, 7.0e 03, 8.0e 03, 9.0e 03, 1.0e 04, 1.1e 04, 1.2e 04, 1.3e 04, 1.4e 04, 1.5e 04, 1.6e 04, 1.7e 04, 1.8e 04, 1.9e 04, 2.0e 04])
  

Редактировать

Если вы хотите 0, 10, 20, 30...90, 100, 200, 300... , вы можете сделать следующее

 n = 10
bins = np.unique(np.outer(np.logspace(1, 3, 3), np.arange(0, n 1)))
# array([    0.,    10.,    20.,    30.,    40.,    50.,    60.,    70.,
#           80.,    90.,   100.,   200.,   300.,   400.,   500.,   600.,
#          700.,   800.,   900.,  1000.,  2000.,  3000.,  4000.,  5000.,
#         6000.,  7000.,  8000.,  9000., 10000.])
  

Комментарии:

1. что, если я хочу, чтобы самая маленькая ячейка находилась между 0 и 10 ? Я понимаю, что не могу объединить свои данные в пределах этого диапазона, не уничтожив их. Таким образом, n=10 последовательность должна быть 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, ...

2. bins = np.unique(np.outer(np.logspace(1, 3, 3), np.arange(0, n 2))) ?

3. @kevinkayaks: Вы были близки к этому. Но вам просто нужно использовать n 1 . Вы использовали (1,3,3) правильно. Проверьте мою правку

4. Спасибо! это очень помогает. Теперь я буду работать над усреднением всех y , соответствующих каждому компоненту bin

5. @kevinkayaks: В вашем подходе вам не нужно, flatten потому что np.unique уже есть плоский одномерный массив.