Python/NetworkX:按边出现频率添加权重

11

我有一个使用networkx创建的多重有向图,现在我想给边添加权重,然后根据边出现的频率/计数来分配新的权重值。我使用下面的代码创建了这个图并添加了权重,但我不知道如何处理基于计数重新分配权重的问题:

g = nx.MultiDiGraph()

df = pd.read_csv('G:\cluster_centroids.csv', delimiter=',')
df['pos'] = list(zip(df.longitude,df.latitude))
dict_pos = dict(zip(df.cluster_label,df.pos))
#print dict_pos


for row in csv.reader(open('G:\edges.csv', 'r')):
    if '[' in row[1]:       #
        g.add_edges_from(eval(row[1]))

for u, v, d in g.edges(data=True):
    d['weight'] = 1
for u,v,d in g.edges(data=True):
    print u,v,d

编辑

我成功地为每个边分配了权重,这是我原来问题的第一部分,以下是方法:

for u, v, d in g.edges(data=True):
    d['weight'] = 1
for u,v,d in g.edges(data=True):
    print u,v,d

然而,我仍然无法根据边出现的次数重新分配权重(我的图中的单个边可能会多次出现)。为了以不同于较低计数的边缘颜色或宽度可视化具有较高计数的边缘,我需要完成此操作。我不确定如何根据计数重新分配权重,请给予建议。以下是示例数据和我的完整数据集的链接。

数据

样本重心(节点):

cluster_label,latitude,longitude
0,39.18193382,-77.51885109
1,39.18,-77.27
2,39.17917928,-76.6688633
3,39.1782,-77.2617
4,39.1765,-77.1927
5,39.1762375,-76.8675441
6,39.17468,-76.8204499
7,39.17457332,-77.2807235
8,39.17406072,-77.274685
9,39.1731621,-77.2716502
10,39.17,-77.27

样例边:

user_id,edges
11011,"[[340, 269], [269, 340]]"
80973,"[[398, 279]]"
608473,"[[69, 28]]"
2139671,"[[382, 27], [27, 285]]"
3945641,"[[120, 422], [422, 217], [217, 340], [340, 340]]"
5820642,"[[458, 442]]"
6060732,"[[291, 431]]"
6912362,"[[68, 27]]"
7362602,"[[112, 269]]"

全部数据:

质心(节点):https://drive.google.com/open?id=0B1lvsCnLWydEdldYc3FQTmdQMmc

边缘:https://drive.google.com/open?id=0B1lvsCnLWydEdEtfM2E3eXViYkk

更新

我设置了minLineWidth并将其与权重相乘,以解决由于高边权导致过度不成比例的边缘宽度问题,至少是暂时解决了。

minLineWidth = 0.25

for u, v, d in g.edges(data=True):
    d['weight'] = c[u, v]*minLineWidth
edges,weights = zip(*nx.get_edge_attributes(g,'weight').items())

在下面提供的解决方案中,使用nx.draw_networkx_edges()中的width=[d['weight'] for u,v, d in g.edges(data=True)]

此外,我还能够使用以下方式进行颜色缩放:

# Set Edge Color based on weight
values = range(7958) #this is based on the number of edges in the graph, use print len(g.edges()) to determine this
jet = cm = plt.get_cmap('YlOrRd')
cNorm  = colors.Normalize(vmin=0, vmax=values[-1])
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
colorList = []

for i in range(7958):
    colorVal = scalarMap.to_rgba(values[i])
    colorList.append(colorVal)

然后在nx.draw_networkx_edges()中使用参数edge_color=colorList

enter image description here


请提供一个最小可复现示例(MCVE)。由于我们没有您的输入文件,所以很难处理您的代码。请提取出足够少的代码来隔离问题。 - Arya McCarthy
抱歉,我本意是要提供样本的。我已经提供了两个文件的样本以及 Google Drive 上完整数据的链接。 - andrewr
假设在您的数据中,节点A和节点B之间的边出现了3次。您想要在节点之间有多个加权边(即A和B之间有3条边,每条边的权重为3),还是想要一个单一的加权边(即A和B之间只有一条边,权重为3)? - edo
能同时看到两者吗?由于图是有向的,我更喜欢有多个加权边,但我不确定这是否会使边的可视化变得复杂,因为边的宽度或颜色将取决于权重,此时两个节点之间的边会重叠。 - andrewr
1个回答

8

试试这个。

注意: 我添加了一个现有边的副本,只是为了展示当您的多重图中有重复时的行为。

from collections import Counter
c = Counter(g.edges())  # Contains frequencies of each directed edge.

for u, v, d in g.edges(data=True):
    d['weight'] = c[u, v]

print(list(g.edges(data=True)))
#[(340, 269, {'weight': 1}),
# (340, 340, {'weight': 1}),
# (269, 340, {'weight': 1}),
# (398, 279, {'weight': 1}),
# (69, 28, {'weight': 1}),
# (382, 27, {'weight': 1}),
# (27, 285, {'weight': 2}),
# (27, 285, {'weight': 2}),
# (120, 422, {'weight': 1}),
# (422, 217, {'weight': 1}),
# (217, 340, {'weight': 1}),
# (458, 442, {'weight': 1}),
# (291, 431, {'weight': 1}),
# (68, 27, {'weight': 1}),
# (112, 269, {'weight': 1})]

编辑:要将边权重作为线条粗细可视化,请使用以下代码:

nx.draw_networkx(g, width=[d['weight'] for _, _, d in g.edges(data=True)])

可以了,谢谢。顺便提一下,我想用权重来确定边缘的宽度或颜色,我该如何使用你的解决方案呢?我尝试使用这里提供的解决方案https://dev59.com/uHTYa4cB1Zd3GeqPuWzv?rq=1和https://dev59.com/9mAg5IYBdhLWcg3w9e_m,但是我没有成功地将你的解决方案应用到它们上面。再次感谢! - andrewr
更新了我的答案,应该解决了你的问题。 - Arya McCarthy
我收到了一个值错误:需要多于2个值来解包 - andrewr
2
原则上,这是相同的想法。它将使用您提供的任何颜色映射或默认值,并将您传递的值分配给颜色映射中的值。请参见文档 - Arya McCarthy
2
你可以随时进行缩放,例如使用 np.log(d['width']) 进行缩放,或者使用 scipy 的 stats.rankdata 按排名排序。 - Arya McCarthy
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接