Изначально это выглядело как bincount
или histogram
, но выводом являются ячейки, в которые помещается каждое значение, а не количество элементов в ячейке:
In [3]: eq_width_bin(data,3)
Out[3]: [1, 2, 1, 0, 0, 0, 1, 1, 2, 2, 2, 1]
Ваши ящики:
In [10]: np.linspace(np.min(data),np.max(data),4)
Out[10]: array([ 10., 50., 90., 130.])
мы можем определить ячейку для каждого значения с помощью простого целочисленного деления:
In [12]: (data-10)//40
Out[12]: array([1, 2, 1, 0, 0, 0, 1, 1, 2, 2, 3, 1])
и исправить это 3 с помощью:
In [16]: np.minimum((data-10)//40,2)
Out[16]: array([1, 2, 1, 0, 0, 0, 1, 1, 2, 2, 2, 1])
Но это не отвечает на ваш вопрос о .select .collect .inject .sort_by
. Я не знаком с ними (хотя я был фанатом Squeak
лет назад и немного баловался с Ruby
). Они больше похожи на итераторы, такие как собранные в itertools
.
С numpy
мы обычно не используем итеративный подход. Скорее мы пытаемся посмотреть на массивы в целом, делая такие вещи, как деление и мин / макс для всего этого.
===
searchsorted
также работает для этой проблемы:
In [19]: np.searchsorted(Out[10],data)
Out[19]: array([2, 3, 2, 1, 1, 0, 2, 2, 3, 3, 3, 2])
In [21]: np.maximum(0,np.searchsorted(Out[10],data)-1)
Out[21]: array([1, 2, 1, 0, 0, 0, 1, 1, 2, 2, 2, 1])
(возможно) более чистое выражение вашего цикла Python:
def foo(i, edges):
for j,n in enumerate(edges):
if i<n:
return j-1
return j-1
In [34]: edges = np.linspace(np.min(data),np.max(data),4).tolist()
In [35]: [foo(i,edges) for i in data]
Out[35]: [1, 2, 1, 0, 0, 0, 1, 1, 2, 2, 2, 1]
Я конвертировал edges
в список, потому что его итерация быстрее.
С itertools
:
In [55]: [len(list(itertools.takewhile(lambda x: x<i,edges)))-1 for i in data]
Out[55]: [1, 2, 1, 0, 0, -1, 1, 1, 2, 2, 2, 1]
===
Другой подход
In [45]: edges = np.linspace(np.min(data),np.max(data),4)
In [46]: data[:,None]<-edges
Out[46]:
array([[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False],
[False, False, False, False]])
In [47]: np.argmax(data[:,None]<edges, axis=1)-1
Out[47]: array([ 1, 2, 1, 0, 0, 0, 1, 1, 2, 2, -1, 1])
То, что -1
нуждается в очистке (строка, где нет Истины).
редактировать
Списки имеют метод index
; с этим мы можем получить выражение, очень похожее на вашу последнюю строку Ruby
. Похоже, что понимание списка очень похоже на Ruby collect
:
In [88]: [[i<j for i in edges].index(False)-1 for j in data]
Out[88]: [1, 2, 1, 0, 0, -1, 1, 1, 2, 2, 2, 1]