繁体   English   中英

从 pandas dataframe 有效地创建边缘列表

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM