基于Pandas数据框中的列值获取更改日期

3
我有以下数据框:
fid         date       stage
test_fid    4/22/2019   a1
test_fid    4/23/2019   a1
test_fid    4/24/2019   a2
test_fid    4/25/2019   a2
test_fid    4/26/2019   a2
test_fid    4/27/2019   a3
test_fid    4/28/2019   a3
test_fid    4/29/2019   a3
test_fid1   4/30/2019   a1
test_fid1   5/1/2019    a1
test_fid1   5/2/2019    a1
test_fid1   5/3/2019    a1
test_fid1   5/4/2019    a2
test_fid1   5/5/2019    a2
test_fid1   5/6/2019    a2
test_fid1   5/7/2019    a2
test_fid1   5/8/2019    a3
test_fid1   5/9/2019    a3
test_fid1   5/10/2019   a3

我想确定阶段列值开始和结束的日期,例如test_fid从2019年4月22日到2019年4月23日有a1阶段。结果应该如下所示:

fid        stage    start_date  end_date
test_fid    a1  4/22/2019   4/23/2019
test_fid    a2  4/24/2019   4/26/2019
test_fid    a3  4/27/2019   4/29/2019
test_fid1   a1  4/30/2019   5/3/2019
test_fid1   a2  5/4/2019    5/7/2019
test_fid1   a3  5/8/2019    5/10/2019

我尝试了这个:

df['stage_change'] = df['stage'].diff()
df_filtered = df[df['stage_change'] != 0]
2个回答

3

使用 sort_values 函数对日期进行排序,然后使用 groupby 分组。接着,对第一个和最后一个日期进行聚合。

df.sort_values('date').groupby(['stage','fid']).agg({'date':['first', 'last']}).reset_index()

结果

    stage   fid date
                        first   last
0   a1  test_fid    2019-04-22  2019-04-23
1   a1  test_fid1   2019-04-30  2019-05-03
2   a2  test_fid    2019-04-24  2019-04-26
3   a2  test_fid1   2019-05-04  2019-05-07
4   a3  test_fid    2019-04-27  2019-04-29
5   a3  test_fid1   2019-05-08  2019-05-10

编辑:我首先转换为日期时间格式

df['date'] = pd.to_datetime(df['date'])

我认为在这里使用sort_values['fid', 'date', 'stage'])会更安全。 - Erfan
groupby 文档 中可以看出:groupby 会保留每个组内行的顺序。因此,通过日期排序应该足够了。 - pythonic833

3
你可能忘了将你的date列解析为一个日期对象,你可以像@pythonic所说的那样,用以下方法实现:
df['date'] = pd.to_datetime(df['date'])

可能最稳健的方式是计算每个组的date的最小值和最大值,例如:

>>> df.groupby(['fid', 'stage'])['date'].agg({'start_date': 'min', 'end_date':'max'})
                    start_date       end_date
fid       stage                              
test_fid  a1         4/22/2019      4/23/2019
          a2         4/24/2019      4/26/2019
          a3         4/27/2019      4/29/2019
test_fid1 a1         4/30/2019       5/3/2019
          a2          5/4/2019       5/7/2019
          a3         5/10/2019       5/9/2019

如果您不希望使用fidstage作为空索引,那么您可以重置索引:

>>> df.groupby(['fid', 'stage'])['date'].agg({'start_date': 'min', 'end_date':'max'}).reset_index()
         fid stage     start_date       end_date
0   test_fid    a1      4/22/2019      4/23/2019
1   test_fid    a2      4/24/2019      4/26/2019
2   test_fid    a3      4/27/2019      4/29/2019
3  test_fid1    a1      4/30/2019       5/3/2019
4  test_fid1    a2       5/4/2019       5/7/2019
5  test_fid1    a3      5/10/2019       5/9/2019

你的最后一行有问题。开始日期比结束日期晚。问题在于你使用了字符串比较,而不是时间日期比较。最简单的解决方法可能是先转换为时间日期。 - pythonic833
“min”和“max”实际上比“first”和“last”更安全,但您没有将其转换为日期时间。 - Erfan
好的,我首先按日期排序,因此两者都是同样安全的。但最小值和最大值是更优雅的解决方案。 - pythonic833

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接