You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于多列条件生成DataFrame邻接CLLI列的高效Pandas方案

高效实现Pandas多条件邻接CLLI列生成

问题背景

现有如下Pandas DataFrame:

RING    CLLI      CIRCUIT       SITE
0   N100    M200      Circuit1      M200
1   N100    M200      Circuit2      M200
2   N100    M201      Circuit3      M201
3   N101    M200 23   Circuit1      M200
4   N101    M300      Circuit1      M300
5   N101    M304 XK   Circuit11     M304
6   N101    M147      Circuit10     M147
7   N102    M304E5    Circuit11     M304
8   N102    M874      Circuit114    M874
9   N102    M874      Circuit113    M874
10  N102    M874      Circuit112    M874
11  N104    M643      Circuit2      M643
12  N104    M643      Circuit234    M643
13  N104    M304      Circuit11     M304

需要新增NeigbourCLLI列,判断逻辑:

  • 筛选相同CIRCUIT的行
  • 在这些行中,筛选RING不同且SITE匹配的记录
  • 将符合条件的CLLI值用逗号拼接填入对应行的NeigbourCLLI,无匹配则为NaN

示例:

  • Circuit1仅行0和3满足SITE匹配且RING不同,因此行0的NeigbourCLLI为M200 23,行3的为M200,行4无匹配
  • Circuit11的行5、7、13均满足条件,因此行5的NeigbourCLLI为M304E5, M643,行7为M304 XK, M643,行13为M304 XK, M304E5

原实现代码在50万行以上的DataFrame中效率极低:

import numpy as np
import pandas as pd

grouped = df.groupby('CIRCUIT').apply(lambda x: x['RING'].nunique() > 1)

def find_neighboring_cllis(row):
    circuit, ring, site = row['CIRCUIT'], row['RING'], row['site']
    if grouped[circuit]:
        neighbors = df[(df['CIRCUIT'] == circuit) & (df['RING'] != ring) & (df['SITE'] == site)]['CLLI'].unique()
        if neighbors.size > 0:
            return ', '.join(neighbors)
    return np.nan

df['NeigbourCLLI'] = df.apply(find_neighboring_cllis, axis=1)

高效实现方案

原代码效率低的核心原因是apply逐行遍历+每次重新过滤整个DataFrame,时间复杂度为O(n²)。以下是基于Pandas原生特性的O(n)级优化方案:

方案一:分组映射+合并

import pandas as pd

# 1. 按CIRCUIT+SITE分组,预存每组内的RING-CLLI映射关系
grouped = df.groupby(['CIRCUIT', 'SITE']).apply(
    lambda x: x[['RING', 'CLLI']].set_index('RING')['CLLI'].to_dict()
).reset_index(name='ring_clli_map')

# 2. 将分组结果合并回原表,让每行直接获取所在组的映射
df_merged = df.merge(grouped, on=['CIRCUIT', 'SITE'], how='left')

# 3. 生成邻接CLLI:排除自身RING对应的CLLI后拼接
def get_neighbors(row):
    ring_clli = row['ring_clli_map']
    current_ring = row['RING']
    neighbors = [clli for ring, clli in ring_clli.items() if ring != current_ring]
    return ', '.join(neighbors) if neighbors else pd.NA

df['NeigbourCLLI'] = df_merged.apply(get_neighbors, axis=1)

# 清理临时列(可选)
df.drop(columns=['ring_clli_map'], errors='ignore', inplace=True)

方案二:分组内直接处理(性能更优)

import pandas as pd

def process_group(g):
    # 提取组内的RING和CLLI列表
    ring_list = g['RING'].tolist()
    clli_list = g['CLLI'].tolist()
    # 对组内每个元素,生成排除自身RING的CLLI拼接字符串
    neighbor_list = []
    for i, ring in enumerate(ring_list):
        neighbors = [clli for r, clli in zip(ring_list, clli_list) if r != ring]
        neighbor_list.append(', '.join(neighbors) if neighbors else pd.NA)
    g['NeigbourCLLI'] = neighbor_list
    return g

# 按CIRCUIT+SITE分组处理,直接生成结果列
df = df.groupby(['CIRCUIT', 'SITE']).apply(process_group).reset_index(drop=True)

优化逻辑说明

  1. 预分组减少重复计算:一次性按CIRCUIT+SITE分组,把每组内的RING与CLLI的对应关系提前存储,避免逐行查询时重复过滤整个DataFrame
  2. 内存内操作:所有匹配逻辑都在分组内部或预存的映射中完成,无需多次IO或全表扫描
  3. 避免逐行遍历的开销:利用Pandas分组的批量处理能力,替代低效的apply(axis=1)逐行操作

内容的提问来源于stack exchange,提问作者user14073111

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 21:15:19