2

假设我有一个表示节点网络的数组,其中连接的节点被描述为“从节点”和“到节点”:

a = array([(1, 2), (2, 3), (3, 4), (4, 5), (2, 6), (6, 7), (7, 8), (2, 9),
       (9, 10), (10, 11), (2, 12), (12, 13), (13, 14), (13, 15), (14, 16)], 
      dtype=[('fnode', '<i4'), ('tnode', '<i4')])

a['fnode']
array([ 1,  2,  3,  4,  2,  6,  7,  2,  9, 10,  2, 12, 13, 13, 14])
a['tnode']
array([ 2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16])

我如何最好地将“到节点”组合到它们共享相同“从节点”的列表中?

我追求这种格式:

#from-node  to-nodes
1             [2]
2             [3,6,9,12]
3             [4]
4             [5]
5             []
6             [7]
7             [8]
8             []
9             [10]
10            [11]
11            []
12            [13]
13            [14,15]
14            [16]
15            []
16            []

编辑

需要明确的是,我希望没有“到节点”(例如节点 8)的“从节点”与一个空列表相关联。

4

4 回答 4

5

使用collections.defaultdict

d = defaultdict(list)
map( lambda (k,v) : d[k].append(v), a)
print d
>> Out[40]: defaultdict(<type 'list'>, {1: [2], 2: [3, 6, 9, 12], 3: [4]
: [7], 7: [8], 9: [10], 10: [11], 12: [13], 13: [14, 15], 14: [16]})
于 2013-09-17T11:19:49.830 回答
3

如果您已经使用 NumPy 而不是列表,我想您的目标是加快速度。在这种情况下,我建议使用 Pandas 库。

>>> pd.DataFrame(a).groupby('fnode').apply(lambda x: x['tnode'].values)
fnode
1                  [2]
2        [3, 6, 9, 12]
3                  [4]
4                  [5]
6                  [7]
7                  [8]
9                 [10]
10                [11]
12                [13]
13            [14, 15]
14                [16]
dtype: object

大数组的时序信息:

In [32]: a = array([(1, 2), (2, 3), (3, 4), (4, 5), (2, 6), (6, 7), (7, 8),
                    (2, 9), (9, 10), (10, 11), (2, 12), (12, 13), (13, 14),
                    (13, 15), (14, 16)] * 100000, 
                    dtype=[('fnode', '<i4'), ('tnode', '<i4')])
In [33]: %%timeit
         pd.DataFrame(a).groupby('fnode').apply(lambda x: x['tnode'].values)
10 loops, best of 3: 102 ms per loop

In [34]: %%timeit
         d = defaultdict(list)
         map( lambda (k,v) : d[k].append(v), a)
1 loops, best of 3: 5.76 s per loop
In [35]: %%timeit
         [(k, list(v)) for k,v in groupby(a, lambda (x, y): x)]
1 loops, best of 3: 9.02 s per loop
于 2013-09-17T11:27:37.043 回答
1

您可以使用itertools.groupby.

定义数组:

A = np.array([(1, 2), (2, 3), (3, 4), (4, 5), (2, 6), (6, 7), (7, 8), (2, 9),
   (9, 10), (10, 11), (2, 12), (12, 13), (13, 14), (13, 15), (14, 16)], 
  dtype=[('fnode', '<i4'), ('tnode', '<i4')])

解决:

A = sorted(A, key=lambda (a,b): a)

然后对它进行分组(我在这里将生成器变成了一个列表,这样你就可以看到它的结果):

In [18]: [(k, list(v)) for k,v in groupby(A, lambda (a,b): a)]
Out[18]: 
[(1, [(1, 2)]),
 (2, [(2, 3), (2, 6), (2, 9), (2, 12)]),
 (3, [(3, 4)]),
 (4, [(4, 5)]),
 (6, [(6, 7)]),
 (7, [(7, 8)]),
 (9, [(9, 10)]),
 (10, [(10, 11)]),
 (12, [(12, 13)]),
 (13, [(13, 14), (13, 15)]),
 (14, [(14, 16)])]

然后,您可以进行所需的任何后处理。

例如,您正在寻找更像[(k, map(lambda (a,b): b, v)) for k,v ...本示例中的内容。

(请注意,对数组进行排序重要。 groupby其操作方式与 POSIX 相同uniq,因为它只会组合相邻的元素。要组合所有元素,请按分组所依据的相同键进行排序。)

于 2013-09-17T11:08:54.387 回答
0

这有点冗长,但它有效(也可以获取空列表):

np.array((np.unique(np.hstack((a['tnode'],a['fnode']))),np.array([a['tnode'][x].tolist() for x in [np.where(a['fnode']==y) for y in np.unique(np.hstack((a['tnode'],a['fnode'])))]]))).T

array([[1, [2]],
       [2, [3, 6, 9, 12]],
       [3, [4]],
       [4, [5]],
       [5, []],
       [6, [7]],
       [7, [8]],
       [8, []],
       [9, [10]],
       [10, [11]],
       [11, []],
       [12, [13]],
       [13, [14, 15]],
       [14, [16]],
       [15, []],
       [16, []]], dtype=object)

以(可能)更易读的形式:

uniq_nodes = np.unique(np.hstack((a['tnode'],a['fnode'])))   # list nodes in network
to_nodes_loc = [np.where(a['fnode']==y) for y in uniq_nodes] # find where nodes are in tonodes array
to_nodes = [a['tnode'][x].tolist() for x in to_nodes_loc]     # get to_nodes
np.array((uniq_nodes,np.array(to_nodes))).T                  # combine into array
于 2013-09-17T13:17:19.943 回答