【问题标题】:Easily generate edge list from specific structure using pandas使用 pandas 从特定结构轻松生成边缘列表
【发布时间】:2020-06-30 17:36:58
【问题描述】:

这是一个关于如何正确使用 pandas 的问题(我使用版本 1.0)。 假设我有一个带有任务的 DataFrame,其中包含一个起点和一个或多个目的地:

   mid from         to
0    0    A        [C]
1    1    A     [B, C]
2    2    B        [B]
3    3    C  [D, E, F]

例如:对于任务 (mid=1),人们将从AB,然后从BC,最后从CA。请注意,我无法控制输入 DataFrame 的数据模型。

我想计算每次任务旅行的指标。预期的输出将是:

    tid  mid from to
0     0    0    A  C
1     1    0    C  A
2     2    1    A  B
3     3    1    B  C
4     4    1    C  A
5     5    2    B  B
6     6    2    B  B
7     7    3    C  D
8     8    3    D  E
9     9    3    E  F
10   10    3    F  C

我找到了实现目标的方法。请在下面找到 MCVE:

import pandas as pd

# Input:
df = pd.DataFrame(
    [["A", ["C"]],
     ["A", ["B", "C"]],
     ["B", ["B"]],
     ["C", ["D", "E", "F"]]],
    columns = ["from", "to"]
).reset_index().rename(columns={'index': 'mid'})

# Create chain:
df['chain'] = df.apply(lambda x: list(x['from']) + x['to'] + list(x['from']), axis=1)
# Explode chain:
df = df.explode('chain')
# Shift to create travel:
df['end'] = df.groupby("mid")["chain"].shift(-1)
# Remove extra row, clean, reindex and rename:
df = df.dropna(subset=['end']).reset_index(drop=True).reset_index().rename(columns={'index': 'tid'})
df = df.drop(['from', 'to'], axis=1).rename(columns={'chain': 'from', 'end': 'to'})

我的问题是:有没有更好/更简单的方法来使用 Pandas 制作它?我说的更好是指,不需要更高的性能(它可能会偏离路线),但更易读和更直观.

【问题讨论】:

    标签: python-3.x pandas graph code-readability


    【解决方案1】:

    你的操作基本是explodeconcat

    # turn series of lists in to single series
    tmp = df[['mid','to']].explode('to')
    
    # new `from` is concatenation of `from` and the list
    df1 = pd.concat((df[['mid','from']],
                     tmp.rename(columns={'to':'from'})
              )
             ).sort_index()
    
    # new `to` is concatenation of list and `to``
    df2 = pd.concat((tmp,
                     df[['mid','from']].rename(columns={'from':'to'})
                    )
             ).sort_index()
    
    df1['to'] = df2['to']
    

    输出:

       mid from to
    0    0    A  C
    0    0    C  A
    1    1    A  B
    1    1    B  C
    1    1    C  A
    2    2    B  B
    2    2    B  B
    3    3    C  D
    3    3    D  E
    3    3    E  F
    3    3    F  C
    

    【讨论】:

      【解决方案2】:

      如果您不介意重新构建整个 DataFrame,那么您可以使用 np.roll 稍微清理一下以获取目的地对,然后根据行程次数(长度l 中的每个子列表)

      import pandas as pd
      import numpy as np
      from itertools import chain
      
      l = [[fr]+to for fr,to in zip(df['from'], df['to'])]
      
      df1 = (pd.DataFrame(data=chain.from_iterable([zip(sl, np.roll(sl, -1)) for sl in l]),
                          columns=['from', 'to'])
               .assign(mid=np.repeat(df['mid'].to_numpy(), [*map(len, l)])))
      
         from to  mid
      0     A  C    0
      1     C  A    0
      2     A  B    1
      3     B  C    1
      4     C  A    1
      5     B  B    2
      6     B  B    2
      7     C  D    3
      8     D  E    3
      9     E  F    3
      10    F  C    3
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-03-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多