Питонический способ для объединения массивов (NumPy или нет) - PullRequest
5 голосов
/ 02 декабря 2009

Я хотел бы сделать хорошую функцию для агрегирования данных в массиве (это массивный массив записей, но он ничего не меняет)

у вас есть массив данных, которые вы хотите агрегировать по одной оси: например, массив dtype=[(name, (np.str_,8), (job, (np.str_,8), (income, np.uint32)], и вы хотите иметь средний доход на задание

Я сделал эту функцию, и в примере она должна называться aggregate(data,'job','income',mean)


def aggregate(data, key, value, func):

    data_per_key = {}

    for k,v in zip(data[key], data[value]):

        if k not in data_per_key.keys():

            data_per_key[k]=[]

        data_per_key[k].append(v)

    return [(k,func(data_per_key[k])) for k in data_per_key.keys()]

проблема в том, что я нахожу это не очень хорошим, я хотел бы, чтобы это было в одной строке: у вас есть какие-нибудь идеи?

Спасибо за ваш ответ Луи

PS: Я бы хотел оставить функцию в вызове, чтобы вы также могли запросить медиану, минимум ...

Ответы [ 6 ]

5 голосов
/ 02 декабря 2009

Возможно, вы ищете функцию matplotlib.mlab.rec_groupby :

import matplotlib.mlab

data=np.array(
    [('Aaron','Digger',1),
     ('Bill','Planter',2),
     ('Carl','Waterer',3),
     ('Darlene','Planter',3),
     ('Earl','Digger',7)],
    dtype=[('name', np.str_,8), ('job', np.str_,8), ('income', np.uint32)])

result=matplotlib.mlab.rec_groupby(data, ('job',), (('income',np.mean,'avg_income'),))

выходы

('Digger', 4.0)
('Planter', 2.5)
('Waterer', 3.0)

matplotlib.mlab.rec_groupby возвращает повторный массив:

print(result.dtype)
# [('job', '|S7'), ('avg_income', '<f8')]

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

5 голосов
/ 02 декабря 2009

Ваш if k not in data_per_key.keys() может быть переписан как if k not in data_per_key, но вы можете сделать еще лучше с defaultdict. Вот версия, которая использует defaultdict, чтобы избавиться от проверки существования:

import collections

def aggregate(data, key, value, func):
    data_per_key = collections.defaultdict(list)
    for k,v in zip(data[key], data[value]):
        data_per_key[k].append(v)

    return [(k,func(data_per_key[k])) for k in data_per_key.keys()]
2 голосов
/ 29 октября 2016

Наилучшая производительность достигается при использовании ndimage.mean из scipy . Это будет в два раза быстрее, чем принятый ответ для этого небольшого набора данных, и примерно в 3,5 раза быстрее для больших входных данных:

from scipy import ndimage

data=np.array(
    [('Aaron','Digger',1),
     ('Bill','Planter',2),
     ('Carl','Waterer',3),
     ('Darlene','Planter',3),
     ('Earl','Digger',7)],
    dtype=[('name', np.str_,8), ('job', np.str_,8), ('income', np.uint32)])

unique = np.unique(data['job'])
result=np.dstack([unique, ndimage.mean(data['income'], data['job'], unique)])

Сдастся:

array([[['Digger', '4.0'],
        ['Planter', '2.5'],
        ['Waterer', '3.0']]],
      dtype='|S32')

РЕДАКТИРОВАТЬ: с bincount (быстрее!)

Это примерно в 5 раз быстрее, чем принятый ответ для небольшого примера ввода, если вы повторите данные 100000 раз, это будет примерно в 8,5 раза быстрее:

unique, uniqueInd, uniqueCount = np.unique(data['job'], return_inverse=True, return_counts=True)
means = np.bincount(uniqueInd, data['income'])/uniqueCount
return np.dstack([unique, means])
2 голосов
/ 24 июля 2014

Лучшая гибкость и удобочитаемость - это использование панд :

import pandas

data=np.array(
    [('Aaron','Digger',1),
     ('Bill','Planter',2),
     ('Carl','Waterer',3),
     ('Darlene','Planter',3),
     ('Earl','Digger',7)],
    dtype=[('name', np.str_,8), ('job', np.str_,8), ('income', np.uint32)])

df = pandas.DataFrame(data)
result = df.groupby('job').mean()

Доходность до:

         income
job
Digger      4.0
Planter     2.5
Waterer     3.0

Pandas DataFrame - отличный класс для работы, но вы можете получать свои результаты по мере необходимости:

result.to_records()
result.to_dict()
result.to_csv()

И так далее ...

2 голосов
/ 12 января 2013

Здесь - это рецепт, который достаточно хорошо имитирует функциональность matlabs accmarray. Он довольно хорошо использует итераторы питонов, тем не менее, с точки зрения производительности это отстой по сравнению с реализацией matlab. Поскольку у меня была та же проблема, я написал реализацию, используя scipy.weave. Вы можете найти его здесь: https://github.com/ml31415/accumarray

0 голосов
/ 02 декабря 2009

http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#dictionary-get-method

должно помочь сделать его немного красивее, питоннее, возможно, более эффективным. Я вернусь позже, чтобы проверить ваши успехи. Может быть, вы можете редактировать функцию с учетом этого? Также см. Следующую пару разделов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...