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

基于多条件与GroupBy的Pandas列匹配值累计计数优化问询

更高效的Pandas实现方案

原始数据

商家商品排名
Merchant 1apple1
Merchant 1banana2
Merchant 1mango3
Merchant 1grapes4
Merchant 1kiwi5
Merchant 2orange1
Merchant 2apple2
Merchant 2banana3
Merchant 2grapes4
Merchant 3mango1
Merchant 3grapes2
Merchant 3orange3

需求回顾

按商家统计从排名1开始的第一组连续匹配商品的累计数量,计算调整后排名:

  • 匹配规则:apple|banana|orange
  • 调整后排名公式:累计总数 + 1,若累计总数 ≤ 2则重置为1
  • 最终输出每个商家对应排名1的调整后排名结果

理想输出

商家排名调整后排名
Merchant 113
Merchant 214
Merchant 311

优化实现方案

方案一:向量化分组实现(最高效,适合大数据集)

该方案完全依赖Pandas向量化操作,避免循环,性能远优于原代码:

import pandas as pd
import numpy as np

# 读取数据,实际使用时替换为 pd.read_csv('data.csv')
data = [
    ["Merchant 1", "apple", 1],
    ["Merchant 1", "banana", 2],
    ["Merchant 1", "mango", 3],
    ["Merchant 1", "grapes", 4],
    ["Merchant 1", "kiwi", 5],
    ["Merchant 2", "orange", 1],
    ["Merchant 2", "apple", 2],
    ["Merchant 2", "banana", 3],
    ["Merchant 2", "grapes", 4],
    ["Merchant 3", "mango", 1],
    ["Merchant 3", "grapes", 2],
    ["Merchant 3", "orange", 3],
]
df = pd.DataFrame(data, columns=["商家", "商品", "排名"])

pattern = r'apple|banana|orange'

# 1. 标记商品是否匹配规则
df['match'] = df['商品'].str.contains(pattern)

# 2. 分组标记首组连续匹配项:从排名1开始,连续匹配直到第一个不匹配
df['is_first_consecutive'] = df.groupby('商家')['match'].transform(
    lambda x: x & (x.cumsum() == np.arange(1, len(x)+1))
)

# 3. 按商家统计首组连续匹配的总数
consecutive_counts = df.groupby('商家')['is_first_consecutive'].sum()

# 4. 计算调整后排名
adjusted_ranks = consecutive_counts.apply(lambda x: x + 1 if x > 2 else 1)

# 5. 生成最终结果
result = pd.DataFrame({
    '商家': adjusted_ranks.index,
    '排名': 1,
    '调整后排名': adjusted_ranks.values
}).reset_index(drop=True)

print(result)

方案二:分组Apply实现(逻辑直观,适合小数据集)

如果数据量不大,用apply的方式逻辑更直观,容易理解:

import pandas as pd

df = pd.DataFrame(data, columns=["商家", "商品", "排名"])
pattern = r'apple|banana|orange'

def compute_rank(group):
    # 确保按排名排序(原始数据已排序时可省略)
    group_sorted = group.sort_values('排名')
    # 生成匹配标记
    matches = group_sorted['商品'].str.contains(pattern)
    
    if not matches.iloc[0]:
        # 第一个商品就不匹配,累计数为0
        count = 0
    else:
        # 找到第一个不匹配的位置,计算连续匹配数
        first_non_match_idx = matches.idxmin() if not matches.all() else len(matches)
        count = matches.loc[:first_non_match_idx].sum()
    
    # 计算调整后排名
    adjusted = count + 1 if count > 2 else 1
    return pd.Series([group_sorted['商家'].iloc[0], 1, adjusted], 
                     index=['商家', '排名', '调整后排名'])

# 分组计算并生成结果
result = df.groupby('商家', group_keys=False).apply(compute_rank).reset_index(drop=True)
print(result)

优化点说明

  1. 减少冗余操作:原代码创建多个中间列、多次过滤合并,优化方案直接在分组内完成所有计算,避免不必要的数据复制和操作。
  2. 向量化优先:方案一使用transform和cumsum实现全向量化操作,避免循环,在大数据集下性能提升显著。
  3. 逻辑更紧凑:直接聚焦“首组连续匹配”的核心需求,避免了原代码中复杂的分组累计和过滤逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 06:31:02