在Python中,获取“merge as of”以根据日期范围将一个数据帧的多个(可能是重复的)行与另一个数据帧的行匹配

问题描述 投票:0回答:1

我有两个数据框,我想根据日期合并它们。我希望 df2 的任何行与 df1 的行匹配,条件是 df2 条目上的日期位于 df1 条目日期的 5 年之前的窗口内。
详细来说,假设 df1 看起来像这样:

公司ID 确认日期
12345 1994年11月30日
12345 1995年3月31日
67890 1994年12月31日
67890 1995年3月31日

df2 看起来像这样:

公司ID 专利 ID 专利申请日期
12345 14526368 1989年12月15日
12345 75896328 1994年5月6日
12345 42589651 1995年2月20日
67890 54216987 1990年2月20日
67890 65874139 1993年7月12日
67890 65874139 1994年5月17日
67890 58792543 1995年2月13日

所需的输出如下所示:

公司ID 数据日期 专利 ID 专利申请日期
12345 1994年11月30日 14526368 1989年12月15日
12345 1994年11月30日 75896328 1994年5月6日
12345 1995年3月31日 75896328 1994年5月6日
12345 1995年3月31日 42589651 1995年2月20日
67890 1994年12月31日 54216987 1990年2月20日
67890 1994年12月31日 65874139 1993年7月12日
67890 1995年3月31日 65874139 1993年7月12日
67890 1995年3月31日 65874139 1994年5月17日
67890 1995年3月31日 58792543 1995年2月13日

如您所见,df2 中的一行可以与 df1 中的多行匹配,只要其日期位于 df1 日期的 5 年之前的窗口内即可。

到目前为止,我已经想出了以下代码:

df_merge = pd.merge_asof(df2, df1 , left_on='patent_filing_date' , right_on='datadate', 
direction='forward', tolerance=pd.Timedelta(1824, unit="d"), by='firm_id')

问题是,上面的代码只匹配从 df2 到 df1 的每一行一次,并且在必要时不会重复这些行。也就是说,看起来我得到了以下内容:

公司ID 数据日期 专利 ID 专利申请日期
12345 1994年11月30日 14526368 1989年12月15日
12345 1994年11月30日 75896328 1994年5月6日
67890 1994年12月31日 54216987 1990年2月20日
67890 1994年12月31日 65874139 1993年7月12日
67890 1995年3月31日 65874139 1994年5月17日
67890 1995年3月31日 58792543 1995年2月13日

然而,我希望 df2 中的每个条目与 df1 中所有可能的条目匹配,无论它们是否与 df1 的另一行匹配。

感谢任何有关 merge as of 或替代功能的帮助。 谢谢

python pandas dataframe date merge
1个回答
0
投票

无法使用

merge_asof
并返回多个匹配项。 您可以对
df1
中的每一行应用一个函数来过滤专利数据 (
df2
):

def merge_firm_patents(
    firm_id: int,
    firm_date: dt.date,
    patent_data: pd.DataFrame,
    date_tolerance: pd.Timedelta
) -> pd.DataFrame:
    # filter patent df for patent filing date within date range and for firm_id
    active_patents = patent_data[
        (patent_data["patent_filing_date"].le(firm_date))
        & (patent_data["patent_filing_date"].ge(firm_date - date_tolerance))
        & patent_data["firm_id"].eq(firm_id)
    ]
    # assign the datadate column and keep only last row for each patent ID
    #  note this assumes patent_data sorted by date already
    return (
        active_patents
        .assign(datadate=firm_date)
        .drop_duplicates("patent_id", keep="last")
    )


# apply function per row, and concatenate dataframe outputs
df_merged = pd.concat(
    df1.apply(
        lambda x: merge_firm_patents(
            x.firm_id, x.firm_date, df2, pd.Timedelta(1824, unit="d")
        ),
        axis=1
    )
    .values
)
© www.soinside.com 2019 - 2024. All rights reserved.