获取Triad节点列表,这些节点属于单个Triadic人口普查类别

时间:2019-03-25 13:44:34

标签: networkx clique

通过执行Networkx triadic_census算法,我可以获得有关每种三重普查类型的节点数的字典

# output from model
op_from_model = <tf.Tensor '1_conv_1x1_parts/BiasAdd:0' shape=(?, 64, 64, 16) dtype=float32>

# Numpy style - 
from scipy.ndimage import gaussian_filter, maximum_filter
import numpy as np
lst = np.zeros([16,3])
for i in range(maps.shape[-1]):
    _map = maps[:,:,i]
    _map = gaussian_filter(_map, sigma=0.3)
    _nmsPeaks = non_max_supression(_map, windowSize=3, threshold=1e-6)
    y, x = np.where(_nmsPeaks == _nmsPeaks.max())
    if len(x) > 0 and len(y) > 0:
        lst[:,i] = [int(x[0]), int(y[0]), _nmsPeaks[y[0], x[0]]]

def non_max_supression(map, windowSize, threshold):
    under_th_indices = plain < threshold
    plain[under_th_indices] = 0
    return plain * (plain == maximum_filter(plain, footprint=np.ones((windowSize, windowSize))))


#TF layer style

# adapted from here https://stackoverflow.com/questions/52012657/how-to-make-a-2d-gaussian-filter-in-tensorflow 
from keras import backend as K
import tensorflow as tf

def gaussian_kernel(size: int, mean: float, std: float):
    d = tf.distributions.Normal(mean, std)
    vals = d.prob(tf.range(start = -size, limit = size + 1, dtype = tf.float32))
    gauss_kernel = tf.einsum('i,j->ij', vals, vals)
    return gauss_kernel / tf.reduce_sum(gauss_kernel)

gauss_kernel = gaussian_kernel(5, 0.44, 0.5) # have to set correct params here 
gauss_kernel = gauss_kernel[:, :, tf.newaxis, tf.newaxis]
filt_op = tf.nn.conv2d(np.expand_dims(np.expand_dims(np.array(map[:,:,0] , dtype = np.float32), axis=0),axis=3), 
                       gauss_kernel, strides=[1, 1, 1, 1], padding="SAME")    

peaks_nhwc_tensor = tf.nn.max_pool(filt_op, windowSize, strides= [1,1,1,1], padding="SAME", data_format='NHWC')
# not sure of the equivalent op here compared to numpy above 
y, x = tf.where(peaks_nhwc_tensor == peaks_nhwc_tensor.max())

现在,我想返回黑社会列表,这些黑社会都遵循人口普查代码“ 201”,“ 120U”或16种现有类型中的任何一种。 如何获得普查计数下的那些节点列表?

2 个答案:

答案 0 :(得分:0)

networkx中没有允许您执行的功能,因此应手动实现。我为您修改了networkx.algorithms.triads代码以返回三合会,而不是它们的计数:

import networkx as nx

G = nx.DiGraph()
G.add_nodes_from([1,2,3,4,5])
G.add_edges_from([(1,2),(2,3),(2,4),(4,5)])

triad_census_social=nx.triadic_census(G)
# '003': 2,
# '012': 4,
# '021C': 3,
# '021D': 1,
# another: 0



#: The integer codes representing each type of triad.
#:
#: Triads that are the same up to symmetry have the same code.
TRICODES = (1, 2, 2, 3, 2, 4, 6, 8, 2, 6, 5, 7, 3, 8, 7, 11, 2, 6, 4, 8, 5, 9,
            9, 13, 6, 10, 9, 14, 7, 14, 12, 15, 2, 5, 6, 7, 6, 9, 10, 14, 4, 9,
            9, 12, 8, 13, 14, 15, 3, 7, 8, 11, 7, 12, 14, 15, 8, 14, 13, 15,
            11, 15, 15, 16)

#: The names of each type of triad. The order of the elements is
#: important: it corresponds to the tricodes given in :data:`TRICODES`.
TRIAD_NAMES = ('003', '012', '102', '021D', '021U', '021C', '111D', '111U',
               '030T', '030C', '201', '120D', '120U', '120C', '210', '300')


#: A dictionary mapping triad code to triad name.
TRICODE_TO_NAME = {i: TRIAD_NAMES[code - 1] for i, code in enumerate(TRICODES)}


def _tricode(G, v, u, w):
    """Returns the integer code of the given triad.

    This is some fancy magic that comes from Batagelj and Mrvar's paper. It
    treats each edge joining a pair of `v`, `u`, and `w` as a bit in
    the binary representation of an integer.

    """
    combos = ((v, u, 1), (u, v, 2), (v, w, 4), (w, v, 8), (u, w, 16),
              (w, u, 32))
    return sum(x for u, v, x in combos if v in G[u])


census = {name: set([]) for name in TRIAD_NAMES}
n = len(G)
m = {v: i for i, v in enumerate(G)}
for v in G:
    vnbrs = set(G.pred[v]) | set(G.succ[v])
    for u in vnbrs:
        if m[u] <= m[v]:
            continue
        neighbors = (vnbrs | set(G.succ[u]) | set(G.pred[u])) - {u, v}
        # Calculate dyadic triads instead of counting them.
        for w in neighbors:
            if v in G[u] and u in G[v]:
                census['102'].add(tuple(sorted([u, v, w])))
            else:
                census['012'].add(tuple(sorted([u, v, w])))
        # Count connected triads.
        for w in neighbors:
            if m[u] < m[w] or (m[v] < m[w] < m[u] and
                               v not in G.pred[w] and
                               v not in G.succ[w]):
                code = _tricode(G, v, u, w)
                census[TRICODE_TO_NAME[code]].add(tuple(sorted([u, v, w])))

# null triads, I implemented them manually because the original algorithm computes
# them as _number_of_all_possible_triads_ - _number_of_all_found_triads_
for v in G:
    vnbrs = set(G.pred[v]) | set(G.succ[v])
    not_vnbrs = set(G.nodes()) - vnbrs
    for u in not_vnbrs:
        unbrs = set(G.pred[u]) | set(G.succ[u])
        not_unbrs = set(G.nodes()) - unbrs
        for w in not_unbrs:
            wnbrs = set(G.pred[w]) | set(G.succ[w])
            if v not in wnbrs and len(set([u, v, w])) == 3:
                census['003'].add(tuple(sorted([u, v, w])))

# '003': {(1, 3, 4), (1, 3, 5)},
# '012': {(1, 2, 3), (1, 2, 4), (2, 3, 4), (2, 4, 5)},
# '021C': {(1, 2, 3), (1, 2, 4), (2, 4, 5)},
# '021D': {(2, 3, 4)},
# another: empty

答案 1 :(得分:0)

以vurmux的答案为基础(通过固定“ 102”和“ 012”三元组):

import networkx as nx
import itertools


def _tricode(G, v, u, w):
    """Returns the integer code of the given triad.

    This is some fancy magic that comes from Batagelj and Mrvar's paper. It
    treats each edge joining a pair of `v`, `u`, and `w` as a bit in
    the binary representation of an integer.

    """
    combos = ((v, u, 1), (u, v, 2), (v, w, 4), (w, v, 8), (u, w, 16),
              (w, u, 32))
    return sum(x for u, v, x in combos if v in G[u])


G = nx.DiGraph()
G.add_nodes_from([1, 2, 3, 4, 5])
G.add_edges_from([(1, 2), (2, 3), (2, 4), (4, 5)])

#: The integer codes representing each type of triad.
#: Triads that are the same up to symmetry have the same code.
TRICODES = (1, 2, 2, 3, 2, 4, 6, 8, 2, 6, 5, 7, 3, 8, 7, 11, 2, 6, 4, 8, 5, 9,
            9, 13, 6, 10, 9, 14, 7, 14, 12, 15, 2, 5, 6, 7, 6, 9, 10, 14, 4, 9,
            9, 12, 8, 13, 14, 15, 3, 7, 8, 11, 7, 12, 14, 15, 8, 14, 13, 15,
            11, 15, 15, 16)

#: The names of each type of triad. The order of the elements is
#: important: it corresponds to the tricodes given in :data:`TRICODES`.
TRIAD_NAMES = ('003', '012', '102', '021D', '021U', '021C', '111D', '111U',
               '030T', '030C', '201', '120D', '120U', '120C', '210', '300')

#: A dictionary mapping triad code to triad name.
TRICODE_TO_NAME = {i: TRIAD_NAMES[code - 1] for i, code in enumerate(TRICODES)}

triad_nodes = {name: set([]) for name in TRIAD_NAMES}
m = {v: i for i, v in enumerate(G)}
for v in G:
    vnbrs = set(G.pred[v]) | set(G.succ[v])
    for u in vnbrs:
        if m[u] > m[v]:
            unbrs = set(G.pred[u]) | set(G.succ[u])
            neighbors = (vnbrs | unbrs) - {u, v}
            not_neighbors = set(G.nodes()) - neighbors - {u, v}
            # Find dyadic triads
            for w in not_neighbors:
                if v in G[u] and u in G[v]:
                    triad_nodes['102'].add(tuple(sorted([u, v, w])))
                else:
                    triad_nodes['012'].add(tuple(sorted([u, v, w])))
            for w in neighbors:
                if m[u] < m[w] or (m[v] < m[w] < m[u] and
                                   v not in G.pred[w] and
                                   v not in G.succ[w]):
                    code = _tricode(G, v, u, w)
                    triad_nodes[TRICODE_TO_NAME[code]].add(
                        tuple(sorted([u, v, w])))
# find null triads
all_tuples = set()
for s in triad_nodes.values():
    all_tuples = all_tuples.union(s)
triad_nodes['003'] = set(itertools.combinations(G.nodes(), 3)).difference(all_tuples)

结果

# print(triad_nodes)

# {'003': {(1, 3, 4), (1, 3, 5)},
#  '012': {(1, 2, 5), (1, 4, 5), (2, 3, 5), (3, 4, 5)},
#  '102': set(),
#  '021D': {(2, 3, 4)},
#  '021U': set(),
#  '021C': {(1, 2, 3), (1, 2, 4), (2, 4, 5)},
#  '111D': set(),
#  '111U': set(),
#  '030T': set(),
#  '030C': set(),
#  '201': set(),
#  '120D': set(),
#  '120U': set(),
#  '120C': set(),
#  '210': set(),
#  '300': set()}

与nx.triadic_census达成协议

# print(nx.triadic_census(G))
# {'003': 2,
#  '012': 4,
#  '102': 0,
#  '021D': 1,
#  '021U': 0,
#  '021C': 3,
#  '111D': 0,
#  '111U': 0,
#  '030T': 0,
#  '030C': 0,
#  '201': 0,
#  '120D': 0,
#  '120U': 0,
#  '120C': 0,
#  '210': 0,
#  '300': 0}