如何按分组依据另一列为DataFrame创建最近值新列
按分组生成最近参考值的新列解决方案
嘿,我看你需要基于分组,从DataFrame里生成包含最近参考值的新列。结合你给出的mydata_tsample数据,我猜你想要的是为每个交易匹配时间上最近的基准refPrice(尤其是当contra_party_type为D时的refPrice,看起来这是基准更新点)。下面是具体的实现步骤:
首先,先把你的数据还原成可运行的pandas代码,方便后续操作:
import pandas as pd # 还原你的DataFrame data = [ ["BUHADU", "01.04.2016", "01:10:50", 101.00, "C", 102.10], ["BUHADU", "01.04.2016", "02:10:50", 101.50, "C", 102.10], ["BUHADU", "01.04.2016", "08:10:50", 102.10, "D", 102.10], ["BUHADU", "01.04.2016", "09:10:50", 102.10, "C", 102.10], ["BUHADU", "02.04.2016", "07:12:50", 90.50, "C", 90.85], ["BUHADU", "02.04.2016", "09:10:55", 90.85, "D", 90.85], ["BUHADU", "02.04.2016", "12:11:40", 90.90, "C", 91.00], ["BUHADU", "02.04.2016", "12:12:02", 91.00, "D", 91.00], ["XDSEOI", "03.04.2016", "06:52:51", 50.00, "D", 50.00] ] mydata_tsample = pd.DataFrame( data, columns=["cusip_id", "trd_exctn_dt", "trd_exctn_tm", "price", "contra_party_type", "refPrice"] ) # 合并日期和时间为datetime类型,这是时间匹配的关键 mydata_tsample["trd_datetime"] = pd.to_datetime( mydata_tsample["trd_exctn_dt"] + " " + mydata_tsample["trd_exctn_tm"], format="%d.%m.%Y %H:%M:%S" )
接下来分两种常见场景给出解决方案:
场景1:分组内向前填充最近的基准值
如果你的需求是:按cusip_id分组,让每个交易(尤其是C类型)继承时间上最近的、之前出现的D类型基准refPrice,可以用向前填充(ffill)的方式:
# 第一步:标记出所有D类型的基准refPrice,其他行设为缺失值 mydata_tsample["latest_refPrice"] = mydata_tsample.apply( lambda row: row["refPrice"] if row["contra_party_type"] == "D" else pd.NA, axis=1 ) # 第二步:按cusip_id分组,对缺失值进行向前填充 mydata_tsample["latest_refPrice"] = mydata_tsample.groupby("cusip_id")["latest_refPrice"].ffill() # 可选:如果分组内第一个交易是C类型,ffill会留空,用bfill补全为后续的第一个基准值 # mydata_tsample["latest_refPrice"] = mydata_tsample.groupby("cusip_id")["latest_refPrice"].apply(lambda x: x.ffill().bfill())
运行后,你会得到这样的结果(截取BUHADU的部分):
| cusip_id | trd_exctn_dt | trd_exctn_tm | price | contra_party_type | refPrice | trd_datetime | latest_refPrice |
|---|---|---|---|---|---|---|---|
| BUHADU | 01.04.2016 | 01:10:50 | 101.0 | C | 102.1 | 2016-04-01 01:10:50 | |
| BUHADU | 01.04.2016 | 02:10:50 | 101.5 | C | 102.1 | 2016-04-01 02:10:50 | |
| BUHADU | 01.04.2016 | 08:10:50 | 102.1 | D | 102.1 | 2016-04-01 08:10:50 | 102.1 |
| BUHADU | 01.04.2016 | 09:10:50 | 102.1 | C | 102.1 | 2016-04-01 09:10:50 | 102.1 |
场景2:精确匹配时间上最近的基准(支持跨日期)
如果需要更精准的时间匹配——比如即使跨日期,也要找到整个cusip_id分组内时间最接近当前交易的基准refPrice,推荐使用merge_asof方法:
# 提取所有D类型的基准数据,重命名列方便后续合并 ref_benchmarks = mydata_tsample[mydata_tsample["contra_party_type"] == "D"].rename( columns={"refPrice": "latest_refPrice", "trd_datetime": "benchmark_datetime"} )[["cusip_id", "benchmark_datetime", "latest_refPrice"]] # 使用merge_asof按cusip_id分组,匹配最近的不晚于当前交易时间的基准 mydata_tsample = pd.merge_asof( mydata_tsample.sort_values("trd_datetime"), ref_benchmarks.sort_values("benchmark_datetime"), by="cusip_id", left_on="trd_datetime", right_on="benchmark_datetime", direction="backward" # 可选:"forward"找之后最近的,"nearest"找最接近的 )
这个方法的灵活性更高,你可以通过修改direction参数来调整匹配逻辑:
backward:找时间上早于或等于当前交易的最近基准forward:找时间上晚于或等于当前交易的最近基准nearest:找时间上最接近当前交易的基准(无论前后)
额外提示
- 一定要先把日期和时间合并成
datetime类型,否则时间排序和匹配会出错; - 如果你的分组依据是
cusip_id + trd_exctn_dt(即每天的基准只在当天生效),只需要把groupby的参数改成["cusip_id", "trd_exctn_dt"],或者在merge_asof的by参数里加上trd_exctn_dt即可; - 对于分组内没有匹配到基准的行,可以根据业务需求填充默认值,比如
mydata_tsample["latest_refPrice"] = mydata_tsample["latest_refPrice"].fillna(0)。
内容的提问来源于stack exchange,提问作者Brian
相关产品推荐
相关产品推荐

