2016-11-28 2 views
1

Я пытаюсь подсчитать количество целых точек данных в пределах 1000 групп.Подсчет/группировка точек данных: для определения цикла или списка?

Давайте предположим, что мы имеем 10000 точек данных в диапазоне 0..999999:

import random 
random.seed(123456) # generate a reproducable sequence 

# make 10000 numbers in range 0..99999 
maxn = 99999 
numbers = [random.randint(0,maxn) for i in range(10000)] 

Теперь, какой вариант был бы в «лучше» способ создания списка, содержащего подсчитанное количество точек данных в пределах каждого 1000-х группа?

"Лучше" может означать одно из следующих действий (просьба уточнить):

  • лучшую производительность
  • более вещий
  • лучше читаемым после 6 месяцев ...

Вариант 1:

# generate a zero-initialized "array" to hold the counts per 1000's block 
blocks1 = [0 for i in range(maxn/1000 +1)] # init 1D "array" 

for num in numbers: 
    blocks1[num/1000] += 1 # int divide by 1000 gives index 

print blocks1[1] # show how many in range 1000..1999 

Вариант 2:

# Use a really wild list comprehension: 
blocks2 = [len(filter(lambda num: num/1000 == i, numbers)) 
    for i in range(maxn/1000+1)] 

print blocks2[1] # show how many in range 1000..1999 

Спасибо за помощь мне делать вещи лучше в Python! :-)

ответ

2

Если вы пытаетесь подсчитать, самый ответ на вопрос Pythonic - это Counter, тип dict, предназначенный для подсчета.

from collections import Counter 

Counter(n // 1000 for n in numbers) 

Результаты в чем-то вроде:

Counter({0: 87, 
     1: 113, 
     2: 117, 
     3: 99, 
     4: 114, 
     ... 

где ключи число тысяч в каждой "группы" или группы. Таким образом, ключ 0 записывает значения 0-999, 1 из 1000-1999 и т. Д.

Но вы можете сделать это более аккуратно. Сначала определите функцию (в данном случае однострочную лямбда-функцию), которая отображает значения в имена групп. Затем построить Counter по обобщенному выражению генератора:

bandof = lambda x, b=1000: '{}-{}'.format(x//b*b, (x//b+1)*b-1) 
Counter(bandof(n) for n in numbers) 

Это дает что-то вроде:

Counter({'0-999': 87, 
     '1000-1999': 113, 
     '10000-10999': 102, 
     '11000-11999': 114, 
     '12000-12999': 113, 
     ... 

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

Приятная вещь в обобщении, так это то, что в любое время, когда вы хотите изменить размер группы, это тривиально. Например. для размера полосы 2000:

Counter(bandof(n, 2000) for n in numbers) 

Урожайность:

Counter({'0-1999': 200, 
     '10000-11999': 216, 
     '12000-13999': 235, 
     '14000-15999': 186, 
     '16000-17999': 188, 
     ... 

размер Пика полосы 100, 250, 500, 1000, 5000, или все, что вы хотите. Это не ограничивается хорошими круглыми номерами. Если вы хотите размер группы 391, это тоже работает.

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

bandtuple = lambda x, b=1000: (x//b*b, (x//b+1)*b-1) 

Вы вызываете эту функцию классификатором, как и раньше. Давайте дикие и сумасшедшие, и сделать это с необычным размером группы:

Counter(bandtuple(n, 3924) for n in numbers) 

Это дает что-то вроде:

Counter({(0, 3923): 411, 
     (3924, 7847): 386, 
     (7848, 11771): 403, 
     (11772, 15695): 417, 
     (15696, 19619): 396, 
     ... 

Теперь начните группа и остановки значения по-прежнему ясно, но они также немедленно также можно использовать как данные.

ПРИМЕЧАНИЕ: Значения начала и останова полосы, приведенные здесь, являются инклюзивными/закрытыми интервалами. Это отлично работает для многих применений, но всегда настолько незначительно, но критически отличается от полуоткрытых диапазонов, обычно возвращаемых функцией/генератором range() Python.

+0

Большое спасибо за подсказку в 'collections' и' Counter'. Я думаю, это модуль, который стоит проверить. Я думаю, что я буду следовать предложенному вами маршруту с помощью 'Counter' и вернуть пары tuple/value. Спасибо за ваше время и отличное объяснение! Ответ принят :-) – Moonbase

Смежные вопросы