使用itertools.groupby而不更改密钥的类型?

时间:2013-11-05 01:51:20

标签: python numpy itertools

我试图通过数组的两个维度将一个大的numpy ndarray(最多16个维度的约1mil条目)组织成两个子组。

目前,我使用的是itertool的groupby函数,但它在我的字典中创建的值是itertools._grouper个对象,我的ndarray似乎是无论我做什么,都转换为grouper对象。

虽然我可以创建一个自定义groupby函数来解决这个问题,但我的Python编码能力似乎是一个根本问题,这是一种我非常新的语言,不确定如何阻止此操作或将grouper对象转换回具有正确字段的ndarray。我需要ndarray因为需要保留其字段以供以后操作。

如何修复以下代码,将返回的groupby结果完全转换回ndarray或阻止转换?

array = np.sort(array, order=['Front','Back','SecStruc'])
front_dict = dict((k,v) for k,v in groupby(array, lambda array : array['Front']))
for key in front_dict:
    front_dict[key] = dict((k,list(v)) for k,v in groupby(front_dict[key], 
    lambda array : front_dict[key]['Back']))

谢谢!

2 个答案:

答案 0 :(得分:2)

我认为您可以使用numpy.split。您可以通过执行以下操作将数组拆分为子数组:

import numpy as np

def findsplit(a):
    diff = a[1:] != a[:-1]
    edges = np.where(diff)[0]
    return edges + 1

array = np.array([0,0,0,1,1,1,1,2,2,3,4,4,4])
s = np.split(array, findsplit(array))
for a in s:
    print a
# [0 0 0]
# [1 1 1 1]
# [2 2]
# [3]
# [4 4 4]

要获得您在问题中描述的嵌套词典,您可以执行以下操作:

byFront = np.split(array, findsplit(array['Front']))
front_dict = {}
for sameFront in byFront:
    back_dict = {}
    byBack = np.split(sameFront, findsplit(sameFront['Back']))
    for sameBack in byBack:
        back_dict[sameBack['Back'][0]] = sameBack
    front_dict[sameFront['Front'][0]] = back_dict

答案 1 :(得分:0)

看起来你几乎就在那里。 list(v)是一个可以轻松转换为数组的列表。

x=np.array([0,0,0,1,1,1,1,2,2,3,4,4,4])
{k:np.array(list(v)) for k,v in groupby(x)}

{0: array([0, 0, 0]),
 1: array([1, 1, 1, 1]),
 2: array([2, 2]),
 3: array([3]),
 4: array([4, 4, 4])}

或者使用2d数组(在第1列上分组,然后在最后一列上分组)。

x=np.array([[0,1,2],[1,2,3],[1,2,4],[1,0,4],[2,3,1]])
d={k:list(v) for k,v in groupby(x,lambda s:s[0])}
print d
# {0: [array([0, 1, 2])],
#  1: [array([1, 2, 3]), array([1, 2, 4]), array([1, 0, 4])],
#  2: [array([2, 3, 1])]}
for i in d.keys():
    d[i]={k:np.array(list(v)) for k,v in groupby(list(d[i]),lambda s:s[2])}
print d
# {0: {2: array([[0, 1, 2]])},
#  1: {3: array([[1, 2, 3]]), 4: array([[1, 2, 4], [1, 0, 4])},
#  2: {1: array([[2, 3, 1]])}}
print d[1][4]
#  [[1 2 4]
#   [1 0 4]]

无论我在任何阶段使用list(v)还是np.array(list(v)) - 都没关系(假设您有兴趣迭代第一维)。


使用改编自numpy文档的结构化数组

x = np.array([(1.5,2.5,(1.0,2.0)),(1.5,2.5,(2.0,4.0)),(3.,4.,(4.,5.)),(1.,3.,(2.,6.))],
        dtype=[('x','f4'),('y',np.float32),('value','f4',(2,2))])
d={k:list(v) for k,v in groupby(x,lambda s:s['x'])}
for i in d.keys():
    d[i]={k:list(v) for k,v in groupby(list(d[i]),lambda s:s['y'])}
pprint(d)
for dd in d[1.5][2.5]:
    print dd
print d[1.5][2.5][0].dtype
# [('x', '<f4'), ('y', '<f4'), ('value', '<f4', (2, 2))]
dd = np.array(d[1.5][2.5],dtype=x.dtype)
print dd
print dd.dtype
print dd[0]
# (1.5, 2.5, [[1.0, 2.0], [1.0, 2.0]])
print dd['value']
# [[[ 1.  2.] [ 1.  2.]]
#  [[ 2.  4.] [ 2.  4.]]]

保留“最里面”元素的结构化数组字符。如果我想将这些数组的列表转换为一个数组(例如np.array(...,dtype=x.dtype)),我只需要使用dd

d[1.5][2.5][0]['value']中,1.52.5是字典键,0是列表索引,value是结构数组字段名称。


但真的需要使用groupby吗?我可以通过正常的numpy索引获得最后的'价值'。并且x的“行”不必排序。对于非常大的阵列,速度和内存使用可能是重要的考虑因素。

I=(x['x']==1.5)&(x['y']==2.5)
print x[I]['value']