Pandas数据帧:选择相互链接的行的复杂问题

2024-05-14 21:25:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个数据帧df

Col1   Col2
A      B
C      A
B      D
E      F
G      D
G      H
K      J

和一系列的ID

ID
A
F

我想要的是,对于id中的所有字母,选择与最多2个中间产物有任何链接的其他字母。 让我们为A做一个例子(这个例子更容易理解):

有两行,包括A,链接到BC,因此到A的直接链接是[B, C]。(无论A在Col1Col2中)

A      B
C      A

但是B也链接到D,并且D链接到G

B      D
G      D

因此A的链接是[B, C, D, G]。 即使GH是链接的,它也会从AA > B > D > G > H生成BDG作为中间产物),所以我不在A链接列表中包含H

G      H

我正在寻找一种方法来搜索链接列表id中的所有ID,并将其保存在id

ID   LinksList
A    [B, C, D, G]
F    [E]

我不介意LinksList的类型(可以是字符串),因为我可以获得特定ID的信息并使用它。我也不介意ID在LinksList中的顺序,只要它是完整的

我已经找到了解决这个问题的方法,但是使用了3for循环,所以需要很长时间。 (对于ID中的k1,对于k2范围(0,3),为LinksList+起始元素的每个元素选择直接链接,如果它们还没有在LinksList中,则将它们放在LinksList中)。 有人能帮我只和熊猫一起做吗? 提前多谢

编辑:这是卡尔评论后的“3个循环”:

i = 0
for k in id:
    linklist = list(df[df['Col1'] == k]['Col2']) + list(df[df['Col2'] == k]['Col1'])
    new = df.copy()
    intermediate_count = 1
    while(len(new) > 0 and intermediate_count <= 2):
        nn = new.copy()
        new = []
        for n in nn:
            toadd = list(df[df['Col1'] == n]['Col2']) + list(df[df['Col2'] == n]['Col1'])
            toadd = list(set(toadd).difference(df))
            df = df + toadd
            new = new + toadd
        
    if(i==0):
        d = {'Id': k, 'Linked': linklist}
        df_result = pd.DataFrame(data=d)
        i = 1
    else:
        d = {'Id': k, 'Linked': linklist}
        df_result.append(pd.DataFrame(data=d))

Tags: iddf列表new链接字母list例子
2条回答

我将首先附加数据帧的倒数,以便能够始终从Col1到Col2。然后,我将使用merges计算可能的结果,包括1和2个中间步骤。最后,我将把所有这些值聚合到集合中。代码可以是:

# append the symetric (Col2 -> Col1) to the end of the dataframe
df2 = df.append(df.reindex(columns=reversed(df.columns)).rename(
    columns={df.columns[len(df.columns)-i]: col
             for i, col in enumerate(df.columns, 1)}), ignore_index=True
                ).drop_duplicates()

# add one step on Col3
df3 = df2.merge(df2, 'left', left_on='Col2', right_on='Col1',
                suffixes=('', '_')).drop(columns='Col1_').rename(
                    columns={'Col2_': 'Col3'})

# add one second stop on Col4
df4 = df3.merge(df2, 'left', left_on='Col3', right_on='Col1',
                suffixes=('', '_')).drop(columns='Col1_').rename(
                    columns={'Col2_': 'Col4'})

# aggregate Col2 to Col4 into a set
df4['Links'] = df4.iloc[:, 1:].agg(set, axis=1)

# aggregate that new column grouped by Col1
result = df4.groupby('Col1')['Links'].agg(lambda x: set.union(*x)).reset_index()

# remove the initial value if present in Links
result['Links'] = result['Links'] - result['Col1'].apply(set)

# and display the result restricted to id
print(result[result['Col1'].isin(id)])

根据样本数据,它给出了预期的结果:

  Col1         Links
0    A  {D, C, B, G}
5    F           {E}

我们可以使用Networkx库:

import networkx as nx
import pandas as pd
import matplotlib.pyplot as plt

# Read in pandas dataframe using copy and paste
df = pd.read_clipboard()

# Create graph network from pandas dataframe
G = nx.from_pandas_edgelist(df, 'Col1', 'Col2')

# Create id, Series
id = pd.Series(['A', 'F'])

# Move values in the index of the Series
id.index=id

# Use `single_source_shortest_path` method in nx for each value in, id, Series
id.apply(lambda x: list(nx.single_source_shortest_path(G, x, 3).keys())[1:])

输出:

A    [B, C, D, G]
F             [E]
dtype: object

打印图形表示:

enter image description here

相关问题 更多 >

    热门问题