Python: создать дистрибутив из списка на основе количества элементов, попадающих в определенные диапазоны - PullRequest
1 голос
/ 23 августа 2010

Я пометил этот вопрос как poisson, так как я не уверен, будет ли он полезен в этом случае.

Мне нужно создать дистрибутив (вероятно, отформатированный как изображение в конце) из спискаданных.

Например:

data = [1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 10, 10, 10, 22, 30, 30, 35, 46, 58, 59, 59]

, чтобы данные могли использоваться для создания визуального распределения.Я мог бы, например, в этом случае сказать, что диапазоны находятся в 10, и в каждом диапазоне должно быть как минимум 3 элемента, чтобы быть действительной точкой.

С данными этого примера я бы ожидал результатабыть аналогом

ditribution = [1, 2, 4, 6]

, поскольку у меня> 3 пункта в диапазонах 0-9, 10-19, 30-39 и 50-59.Используя этот результат, я мог бы создать изображение с сегментированными участками (более темный цвет), которые существуют в моем окончательном выпуске.Пример типа изображения, которое я пытаюсь создать, можно увидеть ниже, и он был бы создан с гораздо большим количеством данных.Пока игнорируйте синюю линию.

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

distribution image

Спасибо за любую помощь.

Ответы [ 3 ]

4 голосов
/ 23 августа 2010

Если data всегда сортируется, компактный подход может быть:

import itertools as it

d = [k+1 for k, L in
         ((k, len(list(g))) for k, g in it.groupby(data,key=lambda x:x//10))
     if L>=3]

Если data не отсортировано или если вы не знаете, используйте sorted(data) в качестве первого аргумента для itertools.groupby вместо просто data.

Если вы предпочитаете менее плотный / компактный подход, вы, конечно, можете расширить его, например, чтобы:

def divby10(x): return x//10

distribution = []
for k, g in it.groupby(data, key=divby10):
    L = len(list(g))
    if L < 3: continue
    distribution.append(k+1)

В любом случае механизм состоит в том, что groupby сначала применяет вызываемый элемент, передаваемый как key=, к каждому элементу в повторяемом элементе, передаваемом в качестве первого аргумента, для получения «ключа» каждого элемента; для каждой последовательной группы элементов, имеющих один и тот же «ключ», groupby дает кортеж с двумя элементами: значением ключа и итерацией для всех элементов в указанной группе.

Здесь ключ получается путем деления элемента на 10 (с усечением); len(list(g)) - количество последовательных элементов с этим «ключом». Поскольку элементы должны быть последовательными, вам необходимо отсортировать данные (и проще просто отсортировать их, чем отсортировать их «по значению, деленному на 10 с усечением»; -).

2 голосов
/ 24 августа 2010

Поскольку data может быть очень длинным, вы можете использовать numpy .Он предоставляет много полезных функций для численной работы, требует меньше памяти для хранения data в массиве numpy, чем список Python [*], и, поскольку многие из функций numpy вызывают функции C внутри, вы можетеполучить некоторое увеличение скорости:

import numpy as np

data = np.array([1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 10, 10, 10, 22, 30, 30, 35, 46, 58, 59, 59])

hist,bins=np.histogram(data,bins=np.linspace(0,60,7))
print(hist)
# [11  3  1  3  1  3]

distribution=np.where(hist>=3)[0]+1
print(distribution)
# [1 2 4 6]

[*] - Примечание: в приведенном выше коде список Python был сформирован в процессе определения data.Таким образом, максимальное требование к памяти здесь на самом деле больше, чем если бы вы только что использовали список Python.Однако память должна быть освобождена, если нет других ссылок на список Python.В качестве альтернативы, если данные хранятся на диске, numpy.loadtxt может использоваться для считывания их непосредственно в массив данных.

0 голосов
/ 23 августа 2010

Это звучит как работа для некоторой формы гистограммы.Предварительная сортировка не должна быть необходимой для достижения этой цели.Я расскажу об использовании варианта сортировки сегментов для группировки соседних элементов здесь , хотя вам нужно будет настроить этот алгоритм в соответствии с вашими целями.Обратите внимание, что вам не нужно хранить сами числа в корзинах для формирования гистограммы

...