#python #pandas #networkx
#python #pandas #networkx
Вопрос:
Я пытаюсь создать ориентированный граф для этого набора данных:
ID Link_to Label Date Size
0 mary NaN 0 2020-01-23 1
1 Julie Mirk 1 2020-02-27 12
1 Julie Mark 1 2020-02-27 12
1 Julie Sarah 1 2020-02-27 12
1 Chris Mirk 1 2020-01-26 12
... ... ... ... ... ... ...
50 Mirk Chris 0 2020-04-29 4
51 Mark NaN 0 2020-04-29 3
52 Greg NaN 0 2020-04-27 2
53 Luke Matt 0 2020-04-08 1
54 Sarah James 0 2020-04-01 1
Чтобы создать неориентированный граф с моими данными выше, я сделал:
G = nx.from_pandas_edgelist(df, 'ID', 'Link_to')
d = dict(df.drop_duplicates(subset=['ID'])[['ID']]
.to_numpy().tolist())
nodes = G.nodes()
plt.figure(figsize=(20,33))
pos = nx.draw(G, with_labels=True,
nodelist=nodes,
node_color=[d.get(i,'lightgreen') for i in nodes],
node_size=1000)
Я хотел бы добавить информацию о дате в график, чтобы создать ориентированный график: идентификатор, у которого самая ранняя дата, является источником.
Итак, например: Julie и Mirk связаны друг с другом: следует добавить направленную ссылку от Julie к Mirk.
Другой пример: Крис и Мирк связаны друг с другом. Однако, поскольку у Chris есть более ранняя дата по сравнению с идентификаторами, чем подключить Mirk к Chris. Если два идентификатора связаны друг с другом и имеют одинаковую дату, у них должна быть одна стрелка (двунаправленная).
Как я могу выяснить, как добавить информацию о дате в мой график?
Ответ №1:
Из предоставленных вами данных (я добавил дополнительную строку Sarah -> Julie
с тем же Date
значением):
s = """index ID Link_to Label Date Size
0 mary NaN 0 2020-01-23 1
1 Julie Mirk 1 2020-02-27 12
1 Julie Mark 1 2020-02-27 12
1 Julie Sarah 1 2020-02-27 12
1 Sarah Julie 1 2020-02-27 12
1 Chris Mirk 1 2020-01-26 12
50 Mirk Chris 0 2020-04-29 4
51 Mark NaN 0 2020-04-29 3
52 Greg NaN 0 2020-04-27 2
53 Luke Matt 0 2020-04-08 1
54 Sarah James 0 2020-04-01 1"""
df = pd.read_csv(io.StringIO(re.sub("[ ] ", ",", s)), parse_dates=['Date'])
df = df.dropna().drop(["index", "Label", "Size"], axis=1)
У нас есть следующий набор данных:
ID Link_to Date
1 Julie Mirk 2020-02-27
2 Julie Mark 2020-02-27
3 Julie Sarah 2020-02-27
4 Sarah Julie 2020-02-27
5 Chris Mirk 2020-01-26
6 Mirk Chris 2020-04-29
9 Luke Matt 2020-04-08
10 Sarah James 2020-04-01
Мы можем объединить фрейм данных с самим собой, чтобы проверить, какую комбинацию следует сохранить:
c = df.merge(df, how='left', left_on=['ID', 'Link_to'], right_on=['Link_to', 'ID'], suffixes=('', '_r'))
c['Date_r'] = c['Date_r'].fillna(c['Date'])
Предполагая, что вы хотите сохранить самое раннее отношение (например.: Chris -> Mirk
вместо Mirk -> Chris
), тогда критерий равен примерно:
c['keep'] = c['Date'] <= c['Date_r']
Если вы намереваетесь сделать обратное, просто измените отношение неравенства на >=
.
Результаты выглядят так:
ID Link_to Date ID_r Link_to_r Date_r keep
0 Julie Mirk 2020-02-27 NaN NaN 2020-02-27 True
1 Julie Mark 2020-02-27 NaN NaN 2020-02-27 True
2 Julie Sarah 2020-02-27 Sarah Julie 2020-02-27 True
3 Sarah Julie 2020-02-27 Julie Sarah 2020-02-27 True
4 Chris Mirk 2020-01-26 Mirk Chris 2020-04-29 True
5 Mirk Chris 2020-04-29 Chris Mirk 2020-01-26 False
6 Luke Matt 2020-04-08 NaN NaN 2020-04-08 True
7 Sarah James 2020-04-01 NaN NaN 2020-04-01 True
И построение ориентированного графа так же просто, как:
c = c.loc[c['keep'], :]
G = nx.from_pandas_edgelist(c, 'ID', 'Link_to', create_using=nx.DiGraph)
Окончательные результаты примерно:
nx.draw_networkx(G)
Похоже, он соответствует вашему ожидаемому результату:
- Представлены отдельные ребра;
- Двойные ребра обрабатываются следующим образом:
- Одинаковые даты, сохраняйте оба ребра;
- Разные даты, сохраняйте самую раннюю.
Ответ №2:
Итак, у меня есть теория, над которой вы можете поработать, сначала преобразуя дату в метку времени Unix, которая является целым числом. Вы можете взглянуть на следующий пример.
>>> import time
>>> import datetime
>>> s = "01/12/2011"
>>> time.mktime(datetime.datetime.strptime(s, "%d/%m/%Y").timetuple())
1322697600.0
Теперь, когда у вас есть весь столбец, преобразованный в временную метку Unix. То, что вы можете сделать сейчас, просто больше или меньше, чем (‘<‘, ‘>’,’=’) операции. Другими словами, если временная метка unix для A меньше, чем временная метка Unix для B, то это означает, что у вас есть направленное ребро от A до B.
Теперь, когда вы знаете, что существует направленное ребро от A до B, вы можете использовать
G.add_edge('A', 'B')
Вы можете узнать больше о направленном графике здесь