Как я могу собрать серию Pandas, установив размер корзины на заданное значение макс / мин для каждой корзины - PullRequest
3 голосов
/ 07 октября 2019

У меня есть pd.Series of float, и я хотел бы поместить его в n бинов , где размер бина для каждого бина установлен так, чтобы max / min было предустановленным значением (например, 1,20)?

Требование означает, что размер бункеров не является постоянным. Например:

data = pd.Series(np.arange(1, 11.0))
print(data)

0     1.0
1     2.0
2     3.0
3     4.0
4     5.0
5     6.0
6     7.0
7     8.0
8     9.0
9    10.0
dtype: float64

Я бы хотел, чтобы размеры бина были:

1.00 <= bin 1 < 1.20
1.20 <= bin 2 < 1.20 x 1.20 = 1.44
1.44 <= bin 3 < 1.44 x 1.20 = 1.73
...

и т. Д.

Спасибо

Ответы [ 3 ]

0 голосов
/ 07 октября 2019

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

data = pd.Series(np.arange(1, 11.0))
bins = []
i = min(data)
while i < max(data):
    bins.append(i)
    i = i*1.2
    bins.append(i)
bins = list(set(bins))
bins.sort()
df = pd.cut(data,bins,include_lowest=True)
print(df)

Вывод:

0       (0.999, 1.2]
1     (1.728, 2.074]
2     (2.986, 3.583]
3       (3.583, 4.3]
4        (4.3, 5.16]
5      (5.16, 6.192]
6      (6.192, 7.43]
7      (7.43, 8.916]
8    (8.916, 10.699]
9    (8.916, 10.699]

Вывод бинов:

Categories (13, interval[float64]): [(0.999, 1.2] < (1.2, 1.44] < (1.44, 1.728] < (1.728, 2.074] < ... <
                                     (5.16, 6.192] < (6.192, 7.43] < (7.43, 8.916] <
                                     (8.916, 10.699]]
0 голосов
/ 08 октября 2019

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

Мне больше всего понравилось векторизованное предложение @ yatu, потому что оно будет лучше масштабироваться с большими наборами данных, но я стремлюсь не только автоматически вычислять биныно также определите минимальное количество бинов, необходимое для покрытия набора данных.

Это мой предложенный алгоритм:

  1. Размер бина определяется так, чтобы bin_max_i / bin_min_i была постоянной:
bin_max_i / bin_min_i = bin_ratio
Определите количество лотков для требуемого размера лотка (bin_ratio):
data_ratio = data_max / data_min
n_bins = math.ceil( math.log(data_ratio) / math.log(bin_ratio) )
Установите нижнюю границу для наименьшего бина, чтобы в него помещалась наименьшая точка данных:
bin_min_0 = data_min
Создание n неперекрывающихся ячеек, соответствующих условиям:
bin_min_i+1 = bin_max_i
bin_max_i+1 = bin_min_i+1 * bin_ratio
Прекратите создавать дополнительные ячейки после того, как все наборы данных можно будет разделить между уже созданными ячейками. Другими словами, остановитесь один раз:
bin_max_last > data_max

Вот фрагмент кода:

import math
import pandas as pd

bin_ratio = 1.20

data = pd.Series(np.arange(2,12))
data_ratio = max(data) / min(data)

n_bins = math.ceil( math.log(data_ratio) / math.log(bin_ratio) )
n_bins = n_bins + 1               # bin ranges are defined as [min, max)

bins = np.full(n_bins, bin_ratio) # initialise the ratios for the bins limits
bins[0] = bin_min_0               # initialise the lower limit for the 1st bin
bins = np.cumprod(bins)           # generate bins

print(bins)
[ 2.          2.4         2.88        3.456       4.1472      4.97664
  5.971968    7.1663616   8.59963392 10.3195607  12.38347284]

Теперь я настроен на построение гистограммы данных:

data.hist(bins=bins)
0 голосов
/ 07 октября 2019

Вот один с pd.cut, где bins может быть вычислено с использованием np.cumprod массива, заполненного 1.2:

data = pd.Series(list(range(11)))
import numpy as np

n = 20 # set accordingly
bins= np.r_[0,np.cumprod(np.full(n, 1.2))]
# array([ 0.        ,  1.2       ,  1.44      ,  1.728 ...
pd.cut(data, bins)

0                 NaN
1          (0.0, 1.2]
2      (1.728, 2.074]
3      (2.986, 3.583]
4        (3.583, 4.3]
5         (4.3, 5.16]
6       (5.16, 6.192]
7       (6.192, 7.43]
8       (7.43, 8.916]
9     (8.916, 10.699]
10    (8.916, 10.699]
dtype: category

Где в этом случае бункеры доходят до:

np.r_[0,np.cumprod(np.full(20, 1.2))]

array([ 0.        ,  1.2       ,  1.44      ,  1.728     ,  2.0736    ,
        2.48832   ,  2.985984  ,  3.5831808 ,  4.29981696,  5.15978035,
        6.19173642,  7.43008371,  8.91610045, 10.69932054, 12.83918465,
       15.40702157, 18.48842589, 22.18611107, 26.62333328, 31.94799994,
       38.33759992])

Так что вам придется установить это в соответствии с диапазоном значений фактических данных

...