Python – Как создать индекс биннинга для списка?

У меня есть 10 бункеров:

    bins = [0,1,2,3,4,5,6,7,8,9]

У меня есть список из 25 значений:

    values = [10,0,0,14,14,123,235,0,0,0,0,0,12,12,1235,23,234,15,15,23,136,34,34,37,45]

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

binnedValues = [[10,0],[0,14,14],[123,235],[0,0,0],[0,0],[12,12,1235],[23,234],[15,15,23],[136,34,34],[37,45]]

Как видите, количество значений в корзине не всегда одинаково (как len(values) != len(bins))

Кроме того, у меня есть много разных списков значений, которые имеют разные размеры. Поэтому мне нужно сделать это несколько раз для одного и того же количества ячеек, но с разной длиной списков значений. Вышеприведенный пример - реальный размер ячейки составляет 10 КБ, а реальный len (значения) составляет от ~ 10 КБ до ~ 750 КБ.

Есть ли способ сделать это последовательно? Мне нужно сохранить порядок значений, но равномерно разделить список значений, чтобы было «справедливое» и «четное» количество значений диапазона, распределенных по каждому из бункеров.

Я думаю, что могу использовать numpy.digitize, но, посмотрев, я не вижу, как сгенерировать «бинированный» список


person Jay Gattuso    schedule 05.12.2012    source источник
comment
Что вы имеете в виду под последовательной группировкой значений? Вы можете уточнить? Размещение binnedValues выглядит несколько произвольно, за исключением того, что оно находится в том же порядке, что и исходный список.   -  person Ehtesh Choudhury    schedule 05.12.2012
comment
Размещение произвольное, так как я пытался продемонстрировать, чего я пытаюсь достичь. Если len(values)= 20, то каждый бин будет иметь 2 значения. Если len(values) = 30, то каждый бин будет иметь 3 значения. Я пытаюсь выяснить, как «равномерно» распределять значения по ячейкам, когда, скажем, len(values) = 27 (таким образом, у 7 ячеек будет 3 значения, а у 3 будет 2) - как я могу равномерно распределить ячейки разного размера по диапазон мусорного ведра ... лучше?   -  person Jay Gattuso    schedule 05.12.2012
comment
Каков ваш ожидаемый результат, если у вас есть 26 элементов?   -  person sberry    schedule 05.12.2012
comment
6 ячеек будут иметь 3 значения, а 4 — 2. Ячейки с 2 связанными значениями будут равномерно распределены по диапазонам ячеек.   -  person Jay Gattuso    schedule 05.12.2012


Ответы (1)


Вы пытаетесь разбить список на списки переменного размера от 2 до 3 элементов? Тогда это выполнимо.

from itertools import cycle

values = [10,0,0,14,14,123,235,0,0,0,0,0,12,12,1235,23,234,15,15,23,136,34,34,37,45]
splits = cycle([2,3])
bins = []
count = 0

while count < len(values):
    splitby = splits.next()
    bins.append(values[count:count+splitby])
    count += splitby

print bins

Изменить:

А, я вижу, что вы просите... вроде того. Что-то вроде:

из цикла импорта itertools из math import floor, ceil

values = [10,0,0,14,14,123,235,0,0,0,0,0,12,12,1235,23,234,15,15,23,136,34,34,37,45]
number_bins = 10
bins_lower = int(floor(len(values) / float(number_bins)))
bins_upper = int(ceil(len(values) / float(number_bins)))

splits = cycle([bins_lower, bins_upper])
bins = []
count = 0

while count < len(values):
    splitby = splits.next()
    bins.append(values[count:count+splitby])
    count += splitby

print bins

Если вы хотите большего разнообразия по размеру корзины, вы можете добавить больше чисел в splits

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

Способ Эшвина, более лаконичный, но не сложный для понимания.

from itertools import cycle, islice
from math import floor, ceil

values = [10,0,0,14,14,123,235,0,0,0,0,0,12,12,1235,23,234,15,15,23,136,34,34,37,45]
number_bins = 10
bins_lower = int(floor(len(values) / float(number_bins)))
bins_upper = int(ceil(len(values) / float(number_bins)))

splits = cycle([bins_lower, bins_upper])

it = iter(values)
bins = [list(islice(it,next(splits))) for _ in range(10)] 
print bins
person Ehtesh Choudhury    schedule 05.12.2012
comment
Это просто пример - реальный размер корзины составляет 10 КБ, а реальный len (значения) составляет от ~ 10 КБ до ~ 750 КБ ... Однако я ценю ваш пример, извините, если я потратил ваше время из-за неясности! Я отредактирую основной пост. - person Jay Gattuso; 05.12.2012
comment
Ух ты! это потрясающе. Как ты это сделал! (и так быстро!) - person Jay Gattuso; 05.12.2012
comment
как насчет [list(islice(it,next(splits))) for _ in range(10)], где it это iter(values). - person Ashwini Chaudhary; 05.12.2012
comment
Симпатичный парень, @AshwiniChaudhary. Я не очень хорошо знаком с itertools, но это приятно. - person Ehtesh Choudhury; 05.12.2012
comment
Дает ли это ожидаемый результат, когда splits = cycle([3, 4])? - person sberry; 05.12.2012
comment
@sberry: если под ожидаемым результатом вы подразумеваете выплевывание чередующихся списков длины 3 и 4, то да. - person Ehtesh Choudhury; 05.12.2012
comment
@AshwiniChaudhary есть ли причина делать it=iter(values), когда вы можете просто передать values напрямую islice? Не будет ли islice работать постепенно, так как он находится в itertools? - person Ehtesh Choudhury; 05.12.2012
comment
Ах, я совершенно пропустил, что они так катались на велосипеде. - person sberry; 05.12.2012