这个问题实际上与我之前的问题非常相似(此处给出:将数据框中的日期拆分为两个单独的数据框(,但有点复杂,所以在尝试了一个多小时后,我认为我应该问这个问题。
我有一个数据帧,其中两列Start
和End
是日期列表。我想做的是创建一个新的数据帧,其中Start
日期与最近的End
日期匹配,并为每个匹配对在输出的数据帧中创建一个新行
基本上,如果Start
列中有两个值,那么只要End
列中的日期在第一个日期之后和第二个日期之前(如以下示例中BBB行所示(,那么我就希望将这些值保留为输出的数据帧。此外,即使End
列中没有日期(如下面示例中的EEE行(,我仍然希望将其拆分。如果Start
和End
列中的一列或两列都为空,则它们将保留在数据帧中。
例如,对于下面的数据帧:
Name Start End
AAA 2017-09-13
BBB 2021-11-20, 2022-06-04 2022-04-07
CCC 2022-09-29
DDD
EEE 2021-04-28, 2022-06-14
FFF 2021-06-25, 2022-06-19 2022-03-18, 2024-07-22
GGG 2020-10-23,2021-06-10, 2022-03-02 2021-03-06, 2022-01-04, 2024-08-15
最后的数据帧看起来像这样:
Name Start End
AAA 2016-09-13
BBB 2022-06-04 2022-04-07
CCC 2022-09-29
DDD
EEE 2022-06-14
FFF 2021-06-25 2022-03-18
FFF 2022-06-19 2024-07-22
GGG 2020-10-23 2021-03-06
GGG 2021-06-10 2022-01-04
GGG 2022-03-02 2024-08-15
我试图修改上面链接中给出的代码,但我无法获得我想要的输出(不幸的是,我对Python还很陌生…(。因此,如果有任何帮助,我们将不胜感激,谢谢!
这实际上与您的其他问题非常不同,而且不那么简单。
我会使用merge_asof
,其中有一个小技巧,用一个伪日期临时替换End的NaN值(这里我使用了"1970-01-01"(:
# pre-process the dataframe to split the strings into lists
df2 = df.set_index('Name').apply(lambda s: s.str.split(',s*'))
out = (pd.merge_asof(
# explode End and fill NaN with 0 to get 1970-01-01
pd.to_datetime(df2['End'].explode().fillna(0))
.sort_values().reset_index(),
pd.to_datetime(df2['Start'].explode().dropna())
.sort_values().reset_index(),
by='Name', left_on='End', right_on='Start',
direction='nearest'
)
.sort_values(by='Name')
[['Name', 'Start', 'End']]
.assign(End=lambda d: d['End'].mask(d['End'].eq('1970-01-01')))
)
输出:
Name Start End
0 AAA 2017-09-13 NaT
7 BBB 2022-06-04 2022-04-07
1 CCC 2022-09-29 NaT
2 DDD NaT NaT
3 EEE 2021-04-28 NaT
6 FFF 2022-06-19 2022-03-18
8 FFF 2022-06-19 2024-07-22
4 GGG 2021-06-10 2021-03-06
5 GGG 2022-03-02 2022-01-04
9 GGG 2022-03-02 2024-08-15