2015-11-13 2 views
3

Я профилирую некоторые числовые измерения времени, которые группируются очень близко. Я хотел бы получить среднее, стандартное отклонение и т. Д. Некоторые входы большие, поэтому я думал, что могу избежать создания списков миллионов чисел, а вместо использовать коллекции Python.Counter-объекты как компактное представление.Вычислить среднее значение для значений в коллекциях python.Counter

Пример: один из моих маленьких входов дает collection.Counter как [(48, 4082), (49, 1146)], что означает 4,082 вхождения значения 48 и 1146 вхождений значения 49. Для этого набора данных я вручную рассчитать среднее значение, чтобы быть что-то вроде 48.2192042846.

Конечно, если бы у меня был простой список из 4,082 + 1,146 = 5,228 целых чисел, я бы просто передал его numpy.mean().

Мой вопрос: как я могу рассчитать описательную статистику из значений в объекте collections.Counter так же, как если бы у меня был список чисел? Мне нужно создать полный список или есть ярлык?

+0

(не успел написать ответ сам, но 'np.average' имеет параметр весов, и вы можете сделать stddev вручную, см. [Здесь] (http://stackoverflow.com/questions/2413522/weighted -стандартное отклонение-в-numpy) - если кто-то хочет написать ответ, используя этот подход, я удалю это) – DSM

ответ

3

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

Среднее значение только сумма всех чисел, разделенных по их подсчетам, так что это очень просто:

sum_of_numbers = sum(number*count for number, count in counter) 
count = sum(count for n, count in counter) 
mean = sum_of_numbers/count 

Стандартное отклонение является немного более сложным. Это квадратный корень дисперсии, а дисперсия в свою очередь определяется как «среднее значение квадратов минус квадрат среднего» для вашей коллекции. Тааак ...

total_squares = sum(number*number * count for number, count in counter) 
mean_of_squares = total_squares/count 
variance = mean_of_squares - mean * mean 
std_dev = math.sqrt(variance) 

Немного больше ручной работы, но также должны быть гораздо быстрее, если множества чисел есть много повторений.

+0

Как этот для краткости. Спасибо @Martijn Pieters за то, что я разъяснил функции Python integer & float math, пожалуйста, не сердитесь, что я принимаю этот ответ :) – chrisinmtown

5

collections.Counter() является подклассом dict. Просто используйте Counter().values(), чтобы получить список подсчетов:

counts = Counter(some_iterable_to_be_counted) 
mean = numpy.mean(counts.values()) 

Обратите внимание, что я сделал не вызов Counter.most_common() здесь, который будет производить список (key, count) кортежей вы вывешенные в вашем вопросе.

Если вы должны использовать выход Counter.most_common() вы можете отфильтровать только отсчеты со списком понимания:

mean = numpy.mean([count for key, count in most_common_list]) 

Если вы используете Python 3 (где dict.values() возвращает представление словаря), вы можете либо удар в list(counts.values()) или использовать стандартную библиотеку staticstics.mean() function, которая принимает итерируемый (включая словарь словаря dict.values()).

Если вы хотите рассчитать среднее значение ключевое значение с учетом их количества, вы сами сделаете собственные вычисления непосредственно из значений счетчика. В Python 2, что бы:

from __future__ import division 

mean = sum(key * count for key, count in counter.iteritems())/sum(counter.itervalues()) 

from __future__ импорт должен быть в верхней части модуля и гарантирует, что вы не столкнетесь с проблемами переполнения с большими числами с плавающей точкой. В Python 3, который был бы упрощен до:

mean = sum(key * count for key, count in counter.items())/sum(counter.values()) 

Медиан может быть рассчитан с использованием пополам; сортируйте пары (key, count) по ключу, суммируйте подсчеты и разделите половину точки на накопленную сумму подсчетов. Индекс для точки вставки указывает на медианный ключ в списке отсортированных ключей.

+0

Спасибо, что исправил мою разметку. Я не хочу, чтобы среднее из графов, я хочу, чтобы среднее значение было соответствующим образом взвешено по счетам. Я отредактировал сообщение, чтобы добавить вычисляемое вручную значение, значение около 48,2. – chrisinmtown

+0

@chrislott: тогда вы можете рассчитать среднее значение: 'sum (key * count for key, count in counter.iteritems())/sum (counter.itervalues ​​(), 0.0)' для Python 2. –

+0

Да еще используя Python 2. Я не знаю о числовых возможностях Python, вы говорите, что мне не нужно беспокоиться о бесшумном переполнении, учитывая большие значения ключа, count? – chrisinmtown

0

Если вы не хотите писать свои собственные статистические функции, нет решения prêt-à-porter (насколько я знаю).

Итак, в конце вам нужно создать списки, а самый быстрый способ - использовать numpy. Один из способов сделать это:

import numpy as np 

# One memory allocation will be considerably faster 
# if you have multiple discrete values. 
elements = np.ones(48+49) 
elements[0:48] *= 4082 
elements[48:] *= 1146 

# Then you can use numpy statistical functions to calculate 
np.mean(elements) 
np.std(elements) 
# ... 

UPDATE: Создание элементов из существующих коллекций.Счетчик() объекта

c = collections.Counter({48: 4082, 49: 1146}) 
elements = np.ones(sum(c.values())) 
idx = 0 
for value, occurrences in c.iteritems(): 
    elements[idx:idx + occurrences] *= value 
    idx += occurrences 
Смежные вопросы