【问题标题】:Pandas: Create Origin-Destination matrix, keeping destination-of-destination on same rowPandas:创建 Origin-Destination 矩阵,将destination-of-destination 保持在同一行
【发布时间】:2022-08-02 20:42:38
【问题描述】:

我正在尝试创建一个 Origin-Destination 矩阵,该矩阵在一行中考虑到destination-of-destination。

我拥有的数据集类似于以下(已编辑given_dataset 和 expected_result 基于@mozway 评论):

origin_id link_type applied_id
1 A 2
2 B 3
2 D 3
3 C 4
5 D 6
1 E 4

预期的结果是:

origin_id A B C D E
1 2 3 4 3 4
2 3 4 3
3 4
5 6

换句话说,由于1链接到2通过一个, 和2链接到3通过D- 电子抄送。电子抄送-,我想将这条路径转回到带有origin_id = 1 的行,其中link_type 成为我的新标题。

值得注意的是:没有场景1去两个23, 和23通过相同的链接类型。

我目前正在使用pivot_table 函数(df.pivot_table(values=\'applied_id\', index=\"origin__id\", columns=\'link_type\', aggfunc=max)),虽然结果接近我想要达到的效果,但它并不完全正确:

origin_id A B C D
1 2
2 3 3
3 4

给定我的起始数据框,什么是实现预期结果的有效方法?

编辑->更多上下文

我有一个数据集,可以将我们 ERP 中的任何事务 (applied_id) 与生成前者的任何其他事务 (origin_id) 进行映射。

例如,销售订单 (origin_id) 通过link_type = \'Invoicing\' 生成发票 (applied_id)

然后,同一张发票 (origin_id) 上可能应用了贷项通知单 (applied_id) (link_type = \'Credit Memo\'),因为客户希望退还他的钱。

应用于发票的付款也是如此。

我的目标是将发票、付款和贷记凭证追溯到原始销售订单行,以及将贷记凭证追溯到发票行和付款行,以及将付款追溯到发票行。

希望这能澄清这里的目标。

编辑 - >工作答案

    G = nx.from_pandas_edgelist(df, source=\'origin_id\', target=\'applied_id\', edge_attr=\'link_type\', create_using=nx.MultiDiGraph)
    dict_for_df = {}
    # Grabbing only link_types I am interested in
    link_type_list = [\'A\', \'B\', \'C\', \'D\']
    
    for n in df[\'origin_id\'].unique():
        value_dict = {}
        for value in link_type_list:
            # As I want the \"arriving\" origin_id for each link_type, I am here grabbing key[1]
            value_list = list(set([key[1] for key, val in nx.get_edge_attributes(G.subgraph({str(n)}|nx.descendants(G, str(n))),\'link_type\').items() if val == value]))
            value_dict[value] = value_list
        dict_for_df[n] = value_dict

    final = pd.DataFrame.from_dict(dict_for_df, orient=\'index\').reset_index().rename(columns={\'index\':\'origin_id\'})
  • 您能否更新您的示例以添加更多行(例如,额外的5/D/61/E/4 会发生什么?)。更多关于真实数据的上下文可能有助于理解你到底想要什么。
  • @Chris 这不是一个简单的pivot
  • @mozway 编辑了给定的数据框和预期结果
  • @mozway 还添加了一些上下文
  • 这似乎是一个使用 networkX 库而不是简单地使用 pandas 更好地解决的问题。请参阅NetworkX 了解更多信息。

标签: python python-3.x pandas dataframe


【解决方案1】:

这是一个可以用networkx 解决的图形问题。

您的(更新的)数据如下所示:

您需要找到每个起源、后代并获取所有边缘。

在这里,我汇总为列表,因为可以有多个选项,请参阅下面的原始数据。

import networkx as nx

G = nx.from_pandas_edgelist(df, source='origin_id', target='applied_id',
                            edge_attr='link_type', create_using=nx.MultiDiGraph)

out = [list(nx.get_edge_attributes(G.subgraph({n}|nx.descendants(G, n)),
                             'link_type').values())
       for n in df['origin_id'].unique()]
# [['A', 'E', 'B', 'D', 'C'], ['B', 'D', 'C'], ['C'], ['D']]
s = pd.Series(out, index=df['origin_id'].unique())

final = (df
 .assign(link=df['origin_id'].map(s)).explode('link')
 .pivot_table(index='origin_id', columns='link', values='applied_id',
              aggfunc=list) # aggregation function can be changed
)

输出:

link            A       B       C       D       E
origin_id                                        
1          [2, 4]  [2, 4]  [2, 4]  [2, 4]  [2, 4]
2             NaN  [3, 3]  [3, 3]  [3, 3]     NaN
3             NaN     NaN     [4]     NaN     NaN
5             NaN     NaN     NaN     [6]     NaN

在您的原始示例中,没有重复项,因此您可以使用 aggfunc='first' 聚合:

输出:

link         A    B    C    D
origin_id                    
1          2.0  2.0  2.0  2.0
2          NaN  3.0  3.0  3.0
3          NaN  NaN  4.0  NaN

【讨论】:

  • 非常感谢您的回答。这确实是一个图形问题,只有知道这对我有很大帮助。您包含一些代码的事实是我需要遵循的教程。预期结果和您的输出之间存在一些不一致之处,我已通过查看和调整nx.get_edge_attributes(G.subgraph({n}|nx.descendants(G, n)), 'link_type') 的输出来修复这些不一致,我将在对原始问题的编辑中包含我的工作代码。再次感谢!
  • @E.Faslo 很高兴它有帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-08
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多