Python панды: Как создать список, сопоставив элемент в одном столбце другой столбец - PullRequest
0 голосов
/ 10 июня 2019

Фрейм данных с:

     Locations      Locations 
        1              2
        1              3
        2              7
        2              8
        7              11

Местоположения попарно, например, птицы в локации 1 будут летать в 2, но они также могут летать в 3. Затем в локации 2 они будут летать в локацию 7, затем в 11.

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

ожидаемая выборка на выходе:

     [1,2,7,11]
     [1,3]
     [2,8]

Ответы [ 4 ]

2 голосов
/ 10 июня 2019

Создать словарь списков для представления графика

g = {}
for _, l0, l1 in df.itertuples():
    g.setdefault(l0, []).append(l1)

print(g)

{1: [2, 3], 2: [7, 8], 7: [11]}

Затем определить рекурсивную функцию для обхода графика

def paths(graph, nodes, path=None):
    if path is None:
        path = []

    for node in nodes:
        new_path = path + [node]
        if node not in graph:
            yield new_path
        else:
            yield from paths(graph, graph[node], new_path)

roots = g.keys() - set().union(*g.values())

p = [*paths(g, roots)]
print(*p, sep='\n')

[1, 2, 7, 11]
[1, 2, 8]
[1, 3]
1 голос
/ 11 июня 2019

, поэтому я нашел этот способ решения вашей проблемы без каких-либо графиков. Но вам придется использовать копию вашего фрейма данных, если вы захотите использовать его позже. И ваши данные должны быть упорядочены, как в вашем примере.

import numpy as np
import pandas as pd

df = pd.DataFrame(columns=["loc1","Loc2"],data=[[1,2],[1,3],[2,7],[2,8],[7,11]])

res = []
n = -1
m = -1
x = 0
for i in df.values:
    if(x in df.index): ###  test wether i has already been deleted
        res.append(i.tolist()) ### saving the value

        m = m +1  ###        m is for later use as index of res
        tmp = i[1]
        for j in df.values:
            n = n +1       ### n is the index of the df rows
            if(j[0] == tmp):
                res[m].append(j[1])
                df = df.drop(df.index[n])   ### deleting the row from which the value was taken
                tmp = res[m][len(res[m])-1]
                n = n -1

        n = -1
    x = x+1
print(res)

[[1, 2, 7, 11], [1, 3], [2, 8]]

Я знаю, что это не самый привлекательный вид, но он работает.

1 голос
/ 10 июня 2019

Возможно, вам понадобится DiGraph из networkx

import networkx as nx

G=nx.from_pandas_edgelist(df,source='Locations',
                                   target='Locations.1',edge_attr=True,
                                   create_using=nx.DiGraph())
roots = list(v for v, d in G.in_degree() if d == 0)
leaves = list(v for v, d in G.out_degree() if d == 0)

[nx.shortest_path(G, x, y) for y in leaves for x in roots]

Out[58]: [[1, 3], [1, 2, 8], [1, 2, 7, 11]]
0 голосов
/ 10 июня 2019

Это может быть больше, чем вы просили, но этот вопрос хорошо вписался бы в график с использованием Networkx.Вы можете искать все простые пути между каждым узлом (местоположением) в пределах ориентированного графа, определенного вашим фреймом данных:

import networkx as nx
from itertools import combination

# Create graph from dataframe of pairs (edges)
G = nx.DiGraph()
G.add_edges_from(df.values)

# Find paths
paths = []
for pair in combinations(G.nodes(), 2):
    paths.extend(nx.all_simple_paths(G, source=pair[0], target=pair[1]))
    paths.extend(nx.all_simple_paths(G, source=pair[1], target=pair[0]))

paths:

[[1, 2],
 [1, 3],
 [1, 2, 7],
 [1, 2, 8],
 [1, 2, 7, 11],
 [2, 7],
 [2, 8],
 [2, 7, 11],
 [7, 11]]
...