Python: создание гистограммы из словаря - PullRequest
4 голосов
/ 07 февраля 2012

Я новичок в Python и учусь правильно делать все.

У меня есть список словарей d.Каждый словарь представляет пользователей и содержит такую ​​информацию, как user_id, age и т. Д. Этот список d может содержать несколько словарей, которые представляют одного и того же пользователя (но с немного другой информацией, которая не имеет значения для моих целей).Я хочу создать гистограмму, которая показывает, сколько пользователей в d с данным возрастом.Как это сделать эффективно?

Редактировать: Хочу подчеркнуть, что мне нужно исключить дубликаты в списке.

Ответы [ 3 ]

3 голосов
/ 07 февраля 2012

Ну, классический подход к этой проблеме - создать defaultdict:

import collections
histogram = collections.defaultdict(int)

Затем переберите словари в списке и (используя d_list вместо d в качестве названия списка словарей),

for d in d_list:
    histogram[d['age']] += 1

Но вы включили дополнительную информацию, которая смущает меня. Вы сказали, что несколько слов могут представлять одного и того же пользователя. Вы хотите удалить эти дубликаты из гистограммы? Если это ваш вопрос, один из подходов - хранить пользователей в формате user_records, используя (firstname, lastname) кортежи в качестве ключей. Тогда последовательные словари, представляющие одного и того же пользователя, будут разбивать друг друга, и будет сохраняться только одна запись на пользователя. Затем переберите значения в этом словаре (возможно, используя user_records.itervalues()).

Этот общий подход можно изменить, чтобы использовать любые значения в каждой записи, которые лучше всего идентифицируют уникальных пользователей. Если значение user_id является уникальным для пользователя, используйте его в качестве ключа вместо (firstname, lastname). Но ваш вопрос подсказал (мне), что user_id не обязательно будет одинаковым для двух одинаковых пользователей.

Однако, если у вас есть удаленные дубликаты, есть и ярлык, если вы используете Python> = 2.7:

histogram = collections.Counter(d['age'] for d in user_records.itervalues())

Пример кода ... скажем, у нас есть record_list:

>>> record_list
[{'lastname': 'Mann', 'age': 23, 'firstname': 'Joe'}, 
 {'lastname': 'Moore', 'age': 23, 'firstname': 'Alex'}, 
 {'lastname': 'Sault', 'age': 33, 'firstname': 'Marie'}, 
 {'lastname': 'Mann', 'age': 23, 'firstname': 'Joe'}]
>>> user_ages = dict(((d['firstname'], d['lastname']), d['age']) for d in record_list)
>>> user_ages
{('Joe', 'Mann'): 23, ('Alex', 'Moore'): 23, ('Marie', 'Sault'): 33}

Как видите, у record_list есть дубликат, а у user_ages нет. Теперь получить количество возрастов так же просто, как пропустить значения через Counter.

>>> collections.Counter(user_ages.itervalues())
Counter({23: 2, 33: 1})

То же самое можно сделать с любой строкой или неизменным объектом, который может служить уникальным идентификатором конкретного пользователя.

2 голосов
/ 07 февраля 2012

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

Например:

import itertools

l = [{'user_id': 1, 'age': 20},
     {'user_id': 2, 'age': 21},
     {'user_id': 3, 'age': 21},
     {'user_id': 4, 'age': 20},
     {'user_id': 5, 'age': 21},
     {'user_id': 6, 'age': 21},
     ]

def get_age(d):
    return d.get('age')

print [(age, len(list(group)))
       for age, group in itertools.groupby(sorted(l, key=get_age),
                                           key=get_age)]

Пример вывода:

[(20, 2), (21, 5)]

Примечание. Как указано @Dougal, список должен быть sorted.В противном случае itertools.groupby не будет работать должным образом.

0 голосов
/ 07 февраля 2012

Пытаясь улучшить ответ @ senderle, надеюсь, я лучше понял проблему.

Я предполагаю, что список содержит словари, где ключи - это идентификаторы пользователей, а данные - это объекты, которые имеют свойство age:

import collections
# Merge all dictionaries to one uid->age mapping (I'm sure there's a shorter way)
all_ages={}
for d1 in d:
   for uid,data in d1.iteritems():
       all_ages[uid]=data.age
# Count distinct users per age
histogram = collections.defaultdict(int)
for uid,age in all_ages.iteritems():
    histogram[age]+=1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...