【问题标题】:Unfurling two columns in a Pandas dataframe into a list of lists将 Pandas 数据框中的两列展开为列表列表
【发布时间】:2020-02-19 13:55:57
【问题描述】:

我在 Pandas 数据框中有两列,它们的值在逻辑上彼此跟随。请参阅以下内容:

Name                Includes

Account             Product Account
Product Account     Card Account
Card Account        Plastic
Card Account        Token
Token               Token Vault
Account             Savings Account

所以帐户>产品帐户>卡帐户等。最终我想创建一个列表列表,其中根(“帐户”)是每个列表的第一个元素。输出应如下所示:

[['Account', 'Product Account', 'Card Account', 'Plastic'],
 ['Account', 'Product Account', 'Card Account', 'Token', 'Token Vault'],
 ['Account', 'Savings Account']]

我基本上想找到可能存在的数据框元素之间的任何和所有可能的路径。我目前有一个将两个数据框列转换为字典结构的代码:

def link_hops(dictionary):

    dictionary = dict(df.groupby('Name')['Includes'].apply(set))
    dictionary = {k: list(v) for k, v in dictionary.items()}

    all_values = set(x for xs in dictionary.values() for x in xs)
    refs = all_values & set(dictionary.keys())

    for k, v in dictionary.items():
        for i in range(len(v)):
            if v[i] in refs:
                v[i] = {v[i]: v1 for k1, v1 in dictionary.items() if v[i] == k1}

    dictionary = {k: v for k, v in dictionary.items() if k not in refs}

    return dictionary

我得到以下信息:

{'Account': ['Savings Account',
            {'Product Account': [{'Card Account': ['Plastic',
            {'Token': ['Token Vault']}]}]}]}

此代码完成了定义从根('Account')到每个路径('Savings Account'、'Plastic'、'Token Vault')的终点存在的所有路径的工作,但我想不通了解如何将其转换为可扩展的列表格式。我有一个递归脚本,它确实适用于这样的小例子,但是当我通过link_hops 将它们转换为字典时,我正在使用的实际数据帧可能有数百或数千层深,并且很容易超过递归限制我称之为脚本。

我想知道是否可以跳过将我的数据框转换为字典的中间步骤,直接将其转换为列表列表,或者甚至只使用.map() 或类似的东西直接处理数据框。

【问题讨论】:

    标签: python pandas list networkx


    【解决方案1】:

    #Approach1

    这是一种方法,使用NetworkX 将数据帧中的每一行作为有向图的图边,并从Account 中寻找shortest_path 到不同的目标: p>

    import numpy as np
    a = df.values
    # check correspondence with value in next row and first col
    m = np.r_[False, (a[:-1, 1] != a[1:, 0])].cumsum()
    # array([0, 0, 0, 1, 1, 2], dtype=int32)
    # get indices of where theres is not a correspondence
    m_diff = np.r_[m[:-1] != m[1:], True]
    # array([False, False,  True, False,  True,  True])
    # get targets of all paths
    targets = a[m_diff, 1]
    # array(['Plastic', 'TokenVault', 'SavingsAccount'], dtype=object)
    
    
    # define a directed graph using networkx
    import networkx as nx
    #add edges from the graph
    G = nx.from_pandas_edgelist(df, source='Name', target='Includes')
    #find all shortest paths from Account to the different found targets
    [nx.shortest_path(G, 'Account', target) for target in targets]
    
    [['Account', 'ProductAccount', 'CardAccount', 'Plastic'],
     ['Account', 'ProductAccount', 'CardAccount', 'Token', 'TokenVault'],
     ['Account', 'SavingsAccount']]
    

    #Approach2

    另一种查找图结束节点的方法是查看degree,并保留度数为1的那些:

    G = nx.from_pandas_edgelist(df, source='Name', target='Includes')
    [nx.shortest_path(G, 'Account', node) for node, degree in G.degree() if degree==1]
    
    [['Account', 'ProductAccount', 'CardAccount', 'Plastic'],
     ['Account', 'ProductAccount', 'CardAccount', 'Token', 'TokenVault'],
     ['Account', 'SavingsAccount']]
    

    为了直观地理解正在解决的图形问题:

    pos = nx.spring_layout(G, scale=20)
    nx.draw(G, pos, node_color='lightblue', node_size=500, with_labels=True)
    

    如我们所见,通过知道要查找的来源目标,通过使用nx.shortest_path,我们可以获得Account和获得的目标之间的路径

    【讨论】:

    • 太棒了,我想了十分钟就放弃了。我可以阅读这类问题的特定名称吗?
    • 如果有帮助,您可以阅读Graph theory。最短路径的答案中还有一个链接@Datanovice
    • 太棒了,我想这就是我要找的。可以将此代码配置为处理多个根吗?例如,如果我除了“帐户”之外还有其他东西作为根。
    • 是的@njrob,您可以扩展列表理解以检查多个根节点
    猜你喜欢
    • 2014-10-15
    • 1970-01-01
    • 2021-03-22
    • 2019-07-03
    • 1970-01-01
    • 2018-07-07
    • 2017-06-22
    • 1970-01-01
    • 2017-08-29
    相关资源
    最近更新 更多