如何筛选Pandas DataFrame指定节点行并重新整理列对顺序?
筛选并重排节点数据
原始数据
import pandas as pd import numpy as np df = pd.DataFrame({'node1': ['_abc-1', 'xyz-1', 'abc-1', '-xyz-2', 'xyz-2', 'abc-2'], 'p1': [1, 10, 3, 1, 2, 6], 'p2': [9, 2, 11, 4, 5, 3], 'node2': ['xyz-1', 'abc-1', '-xyz-1', 'def-2', 'def-2', '-xyz-1']})
原始表格输出:
node1 p1 p2 node2 0 _abc-1 1 9 xyz-1 1 xyz-1 10 2 abc-1 2 abc-1 3 11 -xyz-1 3 -xyz-2 1 4 def-2 4 xyz-2 2 5 def-2 5 abc-2 6 3 -xyz-1
需求
- 仅保留node1和node2中同时包含abc和xyz的行(两个节点分属两类,顺序不限)
- 重排列对:强制将含xyz的节点放在左侧
node1列,对应数值列p1匹配该节点数值;含abc的节点放在右侧node2列,对应p2数值。
原代码问题
原代码用np.sort按字典序排序节点,无法实现“xyz在左”的指定规则,输出不符合预期:
mask1 = ( (df["node1"].str.contains("abc", case=False) & df["node2"].str.contains("xyz", case=False)) | (df["node2"].str.contains("abc", case=False) & df["node1"].str.contains("xyz", case=False)) ) df = df.loc[mask1] final = df[['node1', 'node2']].apply(np.sort, axis=1).apply(pd.Series) final.columns = ['node1', 'node2'] mask2 = final.eq(df[['node1', 'node2']]).all(axis=1) final[['p1', 'p2']] = df[['p1', 'p2']].where(mask2, other=df[['p2', 'p1']].values) final = final[df.columns] print(final)
原输出:
node1 p1 p2 node2 0 _abc-1 1 9 xyz-1 1 abc-1 2 10 xyz-1 2 -xyz-1 11 3 abc-1 5 -xyz-1 3 6 abc-2
期望输出
node1 p1 p2 node2 0 xyz-1 9 1 _abc-1 1 xyz-1 10 2 abc-1 2 -xyz-1 11 3 abc-1 5 -xyz-1 3 6 abc-2
修复后的简化代码
import pandas as pd import numpy as np df = pd.DataFrame({'node1': ['_abc-1', 'xyz-1', 'abc-1', '-xyz-2', 'xyz-2', 'abc-2'], 'p1': [1, 10, 3, 1, 2, 6], 'p2': [9, 2, 11, 4, 5, 3], 'node2': ['xyz-1', 'abc-1', '-xyz-1', 'def-2', 'def-2', '-xyz-1']}) # 1. 筛选符合条件的行:node1和node2分别包含abc和xyz(顺序不限) mask = ( (df['node1'].str.contains('abc', case=False) & df['node2'].str.contains('xyz', case=False)) | (df['node1'].str.contains('xyz', case=False) & df['node2'].str.contains('abc', case=False)) ) filtered_df = df.loc[mask].copy() # 2. 判断哪些行需要交换:node1不含xyz的行需要交换列顺序 swap_mask = ~filtered_df['node1'].str.contains('xyz', case=False) # 3. 对需要交换的行,同步交换node和p列的数值 filtered_df.loc[swap_mask, ['node1', 'node2']] = filtered_df.loc[swap_mask, ['node2', 'node1']].values filtered_df.loc[swap_mask, ['p1', 'p2']] = filtered_df.loc[swap_mask, ['p2', 'p1']].values print(filtered_df)
运行输出与期望完全一致:
node1 p1 p2 node2 0 xyz-1 9 1 _abc-1 1 xyz-1 10 2 abc-1 2 -xyz-1 11 3 abc-1 5 -xyz-1 3 6 abc-2
代码解释
- 筛选行:用布尔掩码精准保留符合要求的行,逻辑与原代码一致但更简洁。
- 交换判断:直接检查
node1是否不含xyz,标记出需要调整顺序的行。 - 执行交换:对标记行同步交换节点列和数值列,完全贴合“xyz在左”的指定规则,避免了原代码中字典序排序的问题。
内容的提问来源于stack exchange,提问作者VERBOSE
相关产品推荐
相关产品推荐

