Развертывание двух столбцов в фрейме данных Pandas в список списков - PullRequest
2 голосов
/ 19 февраля 2020

У меня есть два столбца в кадре данных Pandas, значения которых логически следуют друг за другом. См. Следующее:

Name                Includes

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

Учетная запись> Учетная запись продукта> Учетная запись карты и т. Д. c. В конечном итоге я хочу создать список списков, где root («Аккаунт») является первым элементом каждого списка. Вывод должен выглядеть следующим образом:

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

Я в основном хочу найти любые возможные пути между элементами dataframe, которые могут существовать. В настоящее время у меня есть код, который преобразует два столбца данных в структуру словаря:

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']}]}]}]}

Этот код выполняет работу по определению всех путей которые существуют от root («Учетная запись») до конечной точки для каждого пути («Сберегательный счет», «Plasti c», «Token Vault»), но я не могу понять, как преобразовать это в формат списка это масштабируемо У меня есть сценарий рекурсии, который работает на таких небольших примерах, как это, но реальные фреймы данных, с которыми я работаю, могут иметь глубину в сотни или тысячи уровней, когда я преобразую их в словари с помощью link_hops, и легко преодолеть предел рекурсии, когда Я называю этот сценарий.

Я хочу знать, можно ли пропустить промежуточный этап преобразования моего фрейма данных в словарь и напрямую преобразовать его в список списков, или даже просто использовать .map() или что-то еще аналогично работе с датафреймами напрямую.

1 Ответ

2 голосов
/ 19 февраля 2020

# Approach1

Вот один из подходов: каждая строка из кадра данных берется в качестве края графа ориентированного графа с использованием NetworkX и ищет shortest_path из Account к различным целям :

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

Другой способ найти график конечные узлы можно посмотреть на градус и оставьте те, которые имеют степень 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)

enter image description here

Как мы видим, зная источники и цели , которые нужно искать, используя nx.shortest_path, мы можем получить путь между Account и полученными целями

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...