合并熊猫中重叠的数据范围

时间:2021-02-16 14:37:26

标签: python pandas dataframe numpy date

给定一个 Pandas 数据框 df1

  column_name  id column_value   from_date     to_date
0       score   8            B  2021-01-01  2021-01-04
1       score   8           B+  2021-01-05  2021-01-10
2       score   9            Z  2021-01-01  2021-01-10

和另一个df2

  column_name  id      column_value   from_date     to_date
0       score   8  AAAAAAA-override  2021-01-03  2021-01-07
1       score   9       B+-override  2021-01-08  2021-01-10

我想创建一个由 id 分组并组合 df1df2 之间重叠日期范围的新数据框。如果重叠,我将采用 df2 的 column_value

最终结果是df

       from_date    to_date  id      column_value
index                                            
1     2021-01-01 2021-01-02   8                 B
2     2021-01-03 2021-01-07   8  AAAAAAA-override
3     2021-01-08 2021-01-10   8                B+
4     2021-01-01 2021-01-07   9                Z
5     2021-01-08 2021-01-10   9       B+-override

我目前的解决方案很慢,因为我将每个日期从 from_date 添加到 to_date,然后我重叠两个数据框和 groupby 新日期并从 { {1}}。然后我将结果压缩回一个 from 和一个 to。

这不适用于我们拥有的数据类型,我们可以拥有超过 10 万个 ID,并且日期范围非常广泛:从 1900 年 1 月 1 日到今天。

谁能想到更具可扩展性的解决方案?也许使用 df2 还是我应该使用普通的 python?

1 个答案:

答案 0 :(得分:1)

  • 看看这个,覆盖总是在你的结果 DF 中。
  • 在覆盖的地方,重叠的非覆盖to_date被修改为覆盖的from_date前一天
  • 重叠 from_date 修改为覆盖 to_date 后一天
  • 这可以在您知道行来源的串联 DF 中完成,查找上一行或下一行作为覆盖,按 id
  • 分组
  • 已显示为新列只是为了透明,显然 assign() 可以是必需的列,另外可以删除 O
df1 = pd.read_csv(io.StringIO("""  column_name  id column_value   from_date     to_date
0       score   8            B  2021-01-01  2021-01-04
1       score   8           B+  2021-01-05  2021-01-10
2       score   9            Z  2021-01-01  2021-01-10"""), sep="\s+")
df1.from_date = pd.to_datetime(df1.from_date)
df1.to_date = pd.to_datetime(df1.to_date)

df2 = pd.read_csv(io.StringIO("""  column_name  id      column_value   from_date     to_date
0       score   8  AAAAAAA-override  2021-01-03  2021-01-07
1       score   9       B+-override  2021-01-08  2021-01-10"""), sep="\s+")
df2.from_date = pd.to_datetime(df2.from_date)
df2.to_date = pd.to_datetime(df2.to_date)

df3 = pd.concat([df1.assign(O=False),df2.assign(O=True)]).sort_values(["id","from_date","to_date"])
df3 = df3.groupby(["id"]).apply(lambda dfa: dfa.assign(
    new_from_date=np.where(~dfa.O & dfa.O.shift(),
                           dfa.to_date.shift()+pd.Timedelta(days=1),
                           dfa.from_date),
    new_to_date=np.where(~dfa.O & dfa.O.shift(-1),
                         dfa.from_date.shift(-1)-pd.Timedelta(days=1),
                         dfa.to_date),

)).reset_index(drop=True)


输出

<头>
column_name id column_value from_date to_date O new_from_date new_to_date
0 得分 8 B 2021-01-01 00:00:00 2021-01-04 00:00:00 2021-01-01 00:00:00 2021-01-02 00:00:00
1 得分 8 AAAAAAA-override 2021-01-03 00:00:00 2021-01-07 00:00:00 2021-01-03 00:00:00 2021-01-07 00:00:00
2 得分 8 B+ 2021-01-05 00:00:00 2021-01-10 00:00:00 2021-01-08 00:00:00 2021-01-10 00:00:00
3 得分 9 Z 2021-01-01 00:00:00 2021-01-10 00:00:00 2021-01-01 00:00:00 2021-01-07 00:00:00
4 得分 9 B+-override 2021-01-08 00:00:00 2021-01-10 00:00:00 2021-01-08 00:00:00 2021-01-10 00:00:00