【问题标题】:Create new columns based on a tree like pattern基于树状模式创建新列
【发布时间】:2020-04-04 15:45:00
【问题描述】:

我有以下数据框:

col1      col2               
basic      c                   
c          c++                 
c++        java                
ruby                                     
php                                      
java       python              
python                                   
r                                        
c#                                      

我想根据数据框中遵循的模式创建新列。
例如,在上面的dataframe中basic->c->c++->java->python的顺序可以从col1和col2观察到。

逻辑:

col1 值basiccol2 中具有c 值,类似地,col1 中的c 值对应于col2 中的c++c++ 导致col2 中的java,最后是@ 987654332@ 到 pythoncol2.
“col1”中的剩余值在col2 中具有相应的空白,在新创建的列中也将留空。 (也就是说,我们只考虑“col1”中在col2 中没有空格的值)。

所以我的输出数据框是:

     col1     col2   new_col1  new_col2   new_col3   new_col4   
0   basic       c          c        c++       java     python
1       c     c++        c++       java     python         
2     c++    java       java     python                  
3    ruby                                              
4     php                                              
5    java  python     python                           
6  python                                             
7       r                                               
8       c               

谢谢!

【问题讨论】:

    标签: python pandas graph networkx graph-theory


    【解决方案1】:

    这可以通过graph theory分析解决。看起来您想从col2 中的每个节点开始获取所有successors。为此,我们需要首先使用col1col2 列构建directed graph。我们可以为此使用networkX,并使用nx.from_pandas_edgelist从数据帧中构建一个nx.DiGraph

    import networkx as nx
    
    m = df.ne('').all(1)
    G = nx.from_pandas_edgelist(df[m], 
                                source='col1', 
                                target='col2', 
                                create_using=nx.DiGraph())
    

    然后我们可以遍历col2中的nodes,并从该节点开始搜索所有后继节点。为此,我们可以使用dfs_tree,它将遍历图以从源中进行深度优先搜索来搜索后继者:

    all_successors = [list(nx.dfs_tree(G, node)) for node in df.loc[m,'col2']]
    

    现在我们可以分配回最长路径列表:

    out = (df.assign(
             **pd.DataFrame(all_successors, index=df[m].index)
             .reindex(df.index)
             .fillna('')
             .add_prefix('new_col')))
    

    print(out)
    
         col1    col2   new_col0   new_col1   new_col2   new_col3
    0   basic       c          c        c++       java     python
    1       c     c++        c++       java     python         
    2     c++    java       java     python                  
    3    ruby                                              
    4     php                                              
    5    java  python     python                           
    6  python                                             
    7       r                                               
    8       c                  
    

    为了更好地解释这种方法,请考虑这个稍微不同的网络,它带有一个额外的组件:

    如前所述,我们想要的是Col2 中每个节点的后继列表。对于这些问题,有几种图搜索算法,可用于从给定节点开始探索图的分支。为此,我们可以使用nx.algorithms.traversal 中提供的基于depth first search 的函数。在这种情况下,我们需要nx.dfs_tree,它返回一个通过从指定节点开始的深度优先搜索构造的面向树

    这里有一些例子:

    list(nx.dfs_tree(G, 'c++'))
    # ['c++', 'java', 'python', 'julia']
    
    list(nx.dfs_tree(G, 'python'))
    # ['python', 'julia']
    
    list(nx.dfs_tree(G, 'basic'))
    # ['basic', 'php', 'sql']
    

    请注意,如果图中有循环,这可能会变得非常棘手。假设在c++scala 之间有一条边。在这种情况下,不清楚应该选择哪条路径。一种方法是使用nx.dfs_tree 遍历所有相应的路径,并保持感兴趣的路径预先定义一些逻辑,例如保持最长。虽然在这个问题中似乎不是这样。

    【讨论】:

    • 所以检查一下这个数据框,看看你是否发现与你有任何不同? @pc_pyr
    • 感谢@yatu,运行完美!另外我想了解DAG部分中编辑的逻辑(更新部分),再次感谢!!!
    • 我将添加更多细节来解释@pc_pyr 也感谢你,这是一个非常有趣的工作:)
    • 很好的解释!!谢谢@yatu,这也能处理列中的整数/字母数字值吗?
    • 是的,这应该不是问题@pc_pyr
    猜你喜欢
    • 2020-12-10
    • 2022-01-05
    • 2019-01-25
    • 2014-04-24
    • 1970-01-01
    • 1970-01-01
    • 2018-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多