首页 > 解决方案 > 重塑 pandas 数据框以匹配特定输出

问题描述

我正在努力寻找一些elegant解决方案来从我的数据中获取我需要的东西。我能够得到我想要的,但通过too much努力,我相信可以做得更好,这就是我正在寻找的。

所以这是我的 DataFrame 的示例

>>> df = pd.DataFrame({'device_name': ['tap_switch_1', 'tap_switch_1', 'tap_switch_1', 'tap_switch_1', 'tap_switch_1', 'tap_switch_1', 'tap_switch_1', 'tap_switch_1', 'tap_switch_1'], 'interface': ['ethernet3', 'ethernet4', 'ethernet38', 'ethernet7', 'ethernet8', 'ethernet31', 'ethernet1', 'ethernet12', 'ethernet20'], 'tap_port': ['1-tx-a-rx', '1-tx-b-rx', '1-b', '2-tx-a-rx', '2-tx-b-rx', '2-b', '3-tx-a-rx', '3-tx-b-rx', '3-b'], 'switch_name': ['sw_ag1', 'sw_ag1', 'sw_client1', 'sw_ag1', 'sw_ag1', 'sw_client2', 'sw_ag1', 'sw_ag1', 'sw_client3']})

当前 DataFrame 形状:

device_name     interface   tap_port    switch_name
tap_switch_1    ethernet3   1-tx-a-rx   sw_ag1
tap_switch_1    ethernet4   1-tx-b-rx   sw_ag1
tap_switch_1    ethernet38  1-b         sw_client1
tap_switch_1    ethernet7   2-tx-a-rx   sw_ag1
tap_switch_1    ethernet8   2-tx-b-rx   sw_ag1
tap_switch_1    ethernet31  2-b         sw_client2
tap_switch_1    ethernet1   3-tx-a-rx   sw_ag1
tap_switch_1    ethernet12  3-tx-b-rx   sw_ag1
tap_switch_1    ethernet20  3-b         sw_client3

我希望得到的期望输出是这样的:

device_name   id  agg_switch   rx_int     tx_int    client_switch client_port
tap_switch_1   1  sw_ag1       ethernet3  ethernt4  sw_client1    ethernet38
tap_switch_1   2  sw_ag1       ethernet7  ethernt8  sw_client2    ethernet31
tap_switch_1   3  sw_ag1       ethernet1  ethernt12 sw_client3    ethernet20

逻辑

所以基本上我有网络设置,其中一个开关用于分接多个接口。每一个client switch port都有两个device_name接口 - 每个方向一个(RX/TX)。我使用tap_port名称将所有这些组合成一个组,基于我看到的第一个整数,它表示“tap_group”。

当前的“解决方案”

这是我现在这样做的方式,我不完全这样做并且它没有给我desired output

# Add new `id` column
>>> df['id']=df.tap_port.str[0]

# Get RX/TX direction as new column `direction`
>>> df['direction']=df.tap_port.apply(lambda x: x[-4:] if 'x' in x else '-')

# Trying to get the desired output
>>> df.pivot(index='id', columns='direction')[['switch_name','interface']]
          switch_name                   interface
direction           -    a-rx    b-rx           -       a-rx        b-rx
id
1          sw_client1  sw_ag1  sw_ag1  ethernet38  ethernet3   ethernet4
2          sw_client2  sw_ag1  sw_ag1  ethernet31  ethernet7   ethernet8
3          sw_client3  sw_ag1  sw_ag1  ethernet20  ethernet1  ethernet12

这非常接近我的需要,但不完全符合desired output.

非常感谢您的帮助!

标签: pythonpandas

解决方案


我不认为这是一个最佳解决方案,但它是所需的输出。

df = pd.DataFrame({'device_name': ['tap_switch_1', 'tap_switch_1', 'tap_switch_1', 'tap_switch_1', 'tap_switch_1', 'tap_switch_1', 'tap_switch_1', 'tap_switch_1', 'tap_switch_1'], 'interface': ['ethernet3', 'ethernet4', 'ethernet38', 'ethernet7', 'ethernet8', 'ethernet31', 'ethernet1', 'ethernet12', 'ethernet20'], 'tap_port': ['1-tx-a-rx', '1-tx-b-rx', '1-b', '2-tx-a-rx', '2-tx-b-rx', '2-b', '3-tx-a-rx', '3-tx-b-rx', '3-b'], 'switch_name': ['sw_ag1', 'sw_ag1', 'sw_client1', 'sw_ag1', 'sw_ag1', 'sw_client2', 'sw_ag1', 'sw_ag1', 'sw_client3']})
df['col']=pd.DataFrame([i.split('-') for i in df['tap_port']])[2].fillna('').replace({'a':'rx_int','b':'tx_int','':'client port'})
df['id']=[i.split('-')[0] for i in df['tap_port']]
df_pvt=df.pivot(index='id',columns='col',values='interface').reset_index()
x=df_pvt.join(df[['switch_name','device_name']][df['col']=='client port'].rename(columns={'switch_name':'client switch'}).reset_index(drop=True))
final=x.join(df[['switch_name']][df['col']=='tx_int'].rename(columns={'switch_name':'agg_switch'}).reset_index(drop=True))

Out[126]: 
  id client port     rx_int      tx_int client switch   device_name agg_switch
0  1  ethernet38  ethernet3   ethernet4    sw_client1  tap_switch_1     sw_ag1
1  2  ethernet31  ethernet7   ethernet8    sw_client2  tap_switch_1     sw_ag1
2  3  ethernet20  ethernet1  ethernet12    sw_client3  tap_switch_1     sw_ag1

推荐阅读