[英]Efficiently create edgelist from pandas dataframe
我有一些我想对其进行合着分析的出版数据。 dataframe 看起来像这样:
Author Title Pub_date City
John A. Paper 1 2020-01-01 Boston
Joan B. Paper 1 2020-01-01 Boston
Jeff C. Paper 2 2020-02-01 Chicago
Joan B. Paper 2 2020-02-01 Chicago
Jose D. Paper 2 2020-02-01 Chicago
我想创建一个未加权、无向的边缘列表,将发布数据保留为边缘属性,如下所示:
Node1 Node2 Title Pub_date City
John A. Joan B. Paper 1 2020-01-01 Boston
Joan B. John A. Paper 1 2020-01-01 Boston
Jeff C. Joan B. Paper 2 2020-02-01 Chicago
Jeff C. Jose D. Paper 2 2020-02-01 Chicago
Joan B. Jeff C. Paper 2 2020-02-01 Chicago
Joan B. Jose D. Paper 2 2020-02-01 Chicago
Jose D. Jeff C. Paper 2 2020-02-01 Chicago
Jose D. Joan B. Paper 2 2020-02-01 Chicago
我可以通过以下方式了解基本思想:
edgelist = pd.merge(left=df, right=df, how='outer', on='Title')
但是我必须做很多修复来删除重复的列、重命名并删除没有共同作者的行。 对我来说似乎效率低下。 当数据集非常大或有很多列时,我不知道这种方法的可扩展性如何。
非常感谢一些改进建议。
这是您提供的数据:
import pandas as pd
data = pd.DataFrame([["John A.", "Paper 1", "2020-01-01", "Boston"],
["Joan B." , "Paper 1", "2020-01-01", "Boston"],
["Jeff C." , "Paper 2" , "2020-02-01" , "Chicago"],
["Joan B." , "Paper 2" , "2020-02-01" , "Chicago"]],
columns=["Author", "Title", "Pub_date", "City"])
这是解决方案:
first = data.groupby(by=["Title", "Pub_date", "City"]).first().reset_index().rename(columns={"Author": "Node1"})
last = data.groupby(by=["Title", "Pub_date", "City"]).last().reset_index().rename(columns={"Author": "Node2"})
edgelist = pd.merge(first, last, how='left', on=["Title", "Pub_date", "City"])
这将允许您为每个出版物创建一个作者列表。 您可以使用pd.Series
将这些列表扩展为新列,然后重命名它们并连接回来。 对于共享同一出版物的任意数量的作者来说,这应该可以正常工作。
import pandas as pd
df = pd.DataFrame({'Author': {0: 'John A.', 1: 'Joan B.', 2: 'Jeff C.', 3: 'Joan B.'},
'Title': {0: 'Paper 1', 1: 'Paper 1', 2: 'Paper 2', 3: 'Paper 2'},
'Pub_date': {0: '2020-01-01',
1: '2020-01-01',
2: '2020-02-01',
3: '2020-02-01'},
'City': {0: 'Boston', 1: 'Boston', 2: 'Chicago', 3: 'Chicago'}})
df = df.groupby(['Title','Pub_date','City'])['Author'].apply(list).reset_index()
a = df.Author.apply(pd.Series)
a.columns = [f'Node{x+1}' for x in a.columns]
df = pd.concat([df,a],axis=1)
df.drop(columns='Author', inplace=True)
我想我明白了。 感谢所有的想法!
样品 dataframe:
df = pd.DataFrame([["John A.", "Paper 1", "2020-01-01", "Boston"],
["Joan B." , "Paper 1", "2020-01-01", "Boston"],
["Jeff C." , "Paper 2" , "2020-02-01" , "Chicago"],
["Joan B." , "Paper 2" , "2020-02-01" , "Chicago"],
["Jose D." , "Paper 2" , "2020-02-01" , "Chicago"]],
columns=["Author", "Title", "Pub_date", "City"])
我的解决方案是制作一个 function ,我可以在其中指定具有节点 ID 的列和具有共享属性的列来折叠网络,这样我就不必为不同的数据更改一堆列名。
def df_to_folded_edgelist(df, node_id_col='node_id', fold_id_cols=['fold_attribute']):
df_list = []
df_orig = df.copy()
#group the node ids by the fold attribute column(s)
for i, g in df.groupby(fold_id_cols)[node_id_col]:
# get the pairwise combinations for each group
for u, v in itertools.combinations(g, 2):
# add the pair and the first index from that group to a list
df_list.append([u, v, g.first_valid_index()])
#convert to dataframe
df = pd.DataFrame(df_list, columns=['node_1', 'node_2', 'orig_index'])
#merge the original data so each edge now has all the other columns
edgelist = df.merge(df_orig, how='left', left_on='orig_index', right_index=True)
#drop the unnecessary columns
edgelist.drop(columns=['orig_index', node_id_col], inplace=True)
return edgelist
我不确定这在更大的数据集上会有多快,但我认为它对于我获得的任何新数据都是可重用的,我只需要知道哪些列包含我的节点 ID 和哪些折叠属性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.