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

基于Pandas的groupby、apply、transform实现列值对比与新列生成

解决Pandas分组生成Listing-history字段的问题

原始DataFrame

import pandas as pd

d= {'Time': [0,1,2,0,1,2,2,3,4], 
    'Price': ['Auction', 'Auction','800','900','By Negotiation','700','250','250','Make Offer'],
    'Item': ['Picasso', 'Picasso', 'Picasso', 'DaVinci', 'DaVinci', 'DaVinci', 'Dali', 'Dali', 'Dali']}
df = pd.DataFrame(data=d)

需求规则

  • 若为该商品首次出现的记录,标记为first seen(不一定是Time == 0)
  • 若相邻时间点的Price字段无变化,标记为ongoing listing
  • 若Price字段从数值型字符串变为非数值字符串(如'Auction'、'By Negotiation'),标记为Price->[目标非数值字符串]
  • 若Price字段从非数值字符串变为数值型字符串,标记为[原非数值字符串]->Price
  • 需按Item分组后应用上述逻辑

解决方案

可以通过groupby.apply对每个分组单独处理,结合自定义函数实现所有规则:

完整代码

import pandas as pd

d= {'Time': [0,1,2,0,1,2,2,3,4], 
    'Price': ['Auction', 'Auction','800','900','By Negotiation','700','250','250','Make Offer'],
    'Item': ['Picasso', 'Picasso', 'Picasso', 'DaVinci', 'DaVinci', 'DaVinci', 'Dali', 'Dali', 'Dali']}
df = pd.DataFrame(data=d)

# 标记每个Price是否为数值型字符串
df['is_numeric'] = pd.to_numeric(df['Price'], errors='coerce').notna()

def process_group(group):
    listing_history = []
    for i in range(len(group)):
        if i == 0:
            # 分组第一条记录标记为first seen
            listing_history.append('first seen')
        else:
            prev_price = group.iloc[i-1]['Price']
            curr_price = group.iloc[i]['Price']
            prev_is_num = group.iloc[i-1]['is_numeric']
            curr_is_num = group.iloc[i]['is_numeric']
            
            if curr_price == prev_price:
                listing_history.append('ongoing listing')
            else:
                if prev_is_num and not curr_is_num:
                    # 数值转非数值格式
                    listing_history.append(f'Price->{curr_price}')
                elif not prev_is_num and curr_is_num:
                    # 非数值转数值格式
                    listing_history.append(f'{prev_price}->Price')
                else:
                    # 同类型但内容变化的情况(可根据需求调整标记)
                    listing_history.append('price updated')
    group['Listing-history'] = listing_history
    return group

# 按Item分组处理,group_keys=False避免保留分组索引
df = df.groupby('Item', group_keys=False).apply(process_group)

# 移除辅助列
df = df.drop('is_numeric', axis=1)

print(df)

代码说明

  1. 标记数值型Price:通过pd.to_numeric(..., errors='coerce').notna()生成is_numeric列,快速判断每个Price是否为可转换的数值型字符串。
  2. 分组处理逻辑:
    • 分组内第一条记录直接标记为first seen
    • 后续记录对比前一条的Price内容与类型:
      • 内容完全一致则标记ongoing listing
      • 数值转非数值时,生成Price->[目标值]格式的标记
      • 非数值转数值时,生成[原值]->Price格式的标记
      • 同类型但内容不同的场景(如两个不同非数值、两个不同数值),暂时标记为price updated,可根据实际需求修改
  3. 分组应用:使用groupby.apply将逻辑应用到每个Item分组,保证规则仅在同商品内生效。

运行结果

Time          Price      Item      Listing-history
0     0        Auction    Picasso          first seen
1     1        Auction    Picasso    ongoing listing
2     2           800    Picasso  Auction->Price
3     0           900    DaVinci          first seen
4     1  By Negotiation    DaVinci      Price->By Negotiation
5     2           700    DaVinci  By Negotiation->Price
6     2           250       Dali          first seen
7     3           250       Dali    ongoing listing
8     4      Make Offer       Dali      Price->Make Offer

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 15:40:07