Как преобразовать ориентированный граф в неориентированный граф при записи информации об атрибутах с помощью NetworkX? - PullRequest
0 голосов
/ 10 сентября 2018

Я новичок в NetworkX, и у меня есть проблема, которая, я думаю, может быть довольно общей: как я могу взять направленную сеть, преобразовать ее в ненаправленную сеть и в этом процессе записать некоторую информацию о границах в оригинальная направленная сеть?

В частности, у меня есть DiGraph в NetworkX, который записывает ссылки с id_from на id_to. Атрибутами для каждого ребра являются месяц ссылки и вес.

Я хотел бы преобразовать этот ориентированный граф в неориентированный граф, где я записываю как атрибуты:

  • Общий вес для каждой пары (u, v), т. Е. Суммирование весов от ребер в каждом направлении,
  • Первый и последний раз я вижу связь между парой (u, v),
  • Индикатор того, является ли это обратное / двунаправленное ребро, т. Е. Логическим значением того, присутствуют ли оба ребра (u, v) и (v, u) в исходной направленной сети,
  • Количество месяцев, в течение которых ребро существует в любом направлении, т. Е. Как (u, v) и / или (v, u).

Вот пример кадра данных панд, с которого я начинаю:

In [12]: df
Out[12]: 
    id_from     id_to     total       month
0         a         b     100.0  2014-01-01
1         b         a      10.0  2014-02-01
2         a         c      15.0  2014-01-01
3         c         d       7.0  2015-06-01
4         d         c     500.0  2016-03-01

Я прочитал это как DiGraph:

In [13]: G = nx.from_pandas_dataframe(df, 'id_from', 'id_to', edge_attr = True, create_using = nx.DiGraph())
In [14]: print(G.edges(data = True))
Out[14]: [(a, b, {'id_from':  a, 'id_to': b, 'amount': 100.0, 'month': Timestamp('2014-01-01 00:00:00')}), (b, a, {'id_from':  b, 'id_to': a, 'amount': 10.0, 'month': Timestamp('2014-02-01 00:00:00')}), (a, c, {'id_from':  a, 'id_to': c, 'amount': 15.0, 'month': Timestamp('2014-01-01 00:00:00')}), (c, d, {'id_from':  c, 'id_to': d, 'amount': 7.0, 'month': Timestamp('2015-06-01 00:00:00')}), (d, c, {'id_from':  d, 'id_to': c, 'amount': 500.0, 'month': Timestamp('2016-03-01 00:00:00')})] 

И тогда я бы в конечном итоге хотел получить обратно график, который в какой-то момент я мог бы преобразовать обратно в кадр данных панд, который выглядит следующим образом:

     id_one  id_two  total  first_month  last_month  nr_months  bidirect
0         a       b  110.0   2014-01-01  2014-02-01        2.0       Yes
1         a       c   15.0   2014-02-01  2014-02-01        1.0        No
2         c       d  507.0   2015-06-01  2016-03-01        2.0       Yes

Может ли кто-нибудь помочь мне с этим?

Кажется, я не могу найти похожие вопросы, но, пожалуйста, поправьте меня, если я ошибаюсь. Любая помощь очень ценится.

1 Ответ

0 голосов
/ 11 сентября 2018

Возможный подход заключается в использовании G.to_undirected() для преобразования ориентированного графа в неориентированный граф.Затем выполняется итерация по краям для обновления требуемых свойств для каждого ребра и, наконец, преобразование графа в кадр данных:

import pandas as pd
import networkx as nx
import datetime

data = {
    'id_from': ['a', 'b', 'a', 'c', 'd'],
    'id_to': ['b', 'a', 'c', 'd', 'c'],
    'total': [100.0, 10.0, 15.0, 7.0, 500.0],
    'month': [datetime.datetime(2014, 1, 1), datetime.datetime(2014, 2, 1), datetime.datetime(2014, 1, 1), datetime.datetime(2015, 6, 1), datetime.datetime(2016, 3, 1)],
}
df = pd.DataFrame(data)
G = nx.from_pandas_edgelist(df, 'id_from', 'id_to', edge_attr=True, create_using=nx.DiGraph())

undirected = G.to_undirected()
for edge in undirected.edges(data=True):
    direction_1 = df.ix[(df['id_from'] == edge[0]) & (df['id_to'] == edge[1])]
    direction_2 = df.ix[(df['id_from'] == edge[1]) & (df['id_to'] == edge[0])]
    edges = pd.concat([direction_1, direction_2])
    edge[2]['bidirect'] = 'Yes' if (not direction_1.empty) & (not direction_2.empty) else 'No'
    edge[2]['total'] = edges['total'].sum()
    edge[2]['first_month'] = edges['month'].min()
    edge[2]['last_month'] = edges['month'].max()
    edge[2]['nr_months'] = edges['month'].nunique()
    del edge[2]['month']

print(nx.to_pandas_edgelist(undirected))

Результат:

  bidirect first_month last_month  nr_months source target  total
0       No  2014-01-01 2014-01-01          1      a      c   15.0
1      Yes  2014-01-01 2014-02-01          2      a      b  110.0
2      Yes  2015-06-01 2016-03-01          2      c      d  507.0

Каждое ребро в сетиxgraph, по сути, является кортежем, где первые 2 элемента являются узлами ребра, а последний элемент (edge ​​[2]) является словарем со свойствами ребра.Следовательно, мы можем просто обновить этот словарь в соответствии с желаемой логикой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...