2009-12-01 75 views
5

我想作一个数组中一个不错的功能,以汇总数据(这是一个numpy的记录阵列,但它不会改变任何东西)以总阵列(numpy的或不)Python的方式

你有一个数组数据要一个轴之间聚集:例如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:我想保持FUNC在通话,让你也可以要求值,最小值......

+0

我不知道numpy,但是你的'dtype'好像和括号有问题.. – int3 2009-12-01 22:27:09

+0

括号不匹配。使一些额外的混乱。 – 2009-12-01 22:51:58

+0

我不明白你的意见,你“希望在一行中”。当你调用函数时,这将是一行。这个函数本身有多少行是否重要?无论如何,我认为你最好的选择是使用'defaultdict'作为答案。 – steveha 2009-12-01 23:51:50

回答

5

也许你正在寻找的功能是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返回一个recarray:

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

您可能也有兴趣检出pandas,它甚至有more versatile facilities用于处理group-by operations

+0

,这正是我所期待的:一行完成的工作!而且它直接返回一个数组!完善! – Louis 2009-12-02 20:11:50

5

您的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()] 
+3

我会改变最后一行为'return [(k,f(v))for k,v in data_per_key.items()]' – 2009-12-01 23:09:17

+0

这是一个很好的调用,但我试图突出显示'defaultdict'的东西这是唯一的改变。不过,你的回报肯定会更好。 – 2009-12-02 11:54:36

+0

感谢您使用defaultdict技巧!还有最后一次迭代 – Louis 2009-12-02 20:12:41

2

Here是一个模拟matlabs accumarray功能相当好的配方。它很好地使用pythons迭代器,但是,与matlab实现相比,它表现得更糟。由于我有同样的问题,我用scipy.weave写了一个实现。你可以在这里找到它:https://github.com/ml31415/accumarray

2

最佳的灵活性和可读性使用GET pandas

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 

大熊猫据帧是一个伟大的类的工作,但你可以根据需要取回结果:

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

等......

+1

“熊猫”比我上面给出的解决方案慢大约一个数量级。看到那里的速度比较。 – Michael 2015-06-17 12:39:12

+0

@Michael,对不起,其实我并不是说表演,我知道熊猫不是一个以顶级表现为目标的图书馆,我更喜欢使用像bincount这样的方法来表现。我编辑了原文。 – caiohamamura 2015-06-17 13:16:59

2

最佳性能是使用ndimage.meanscipy实现。这将是比这个小数据集接受的答案快两倍,并更快更大的投入约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])