Pandas Dataframe使用Groupby从另外两列的唯一值创建下一个未来日期的列



我有一个数据帧,可以用这个创建:

import pandas as pd
import datetime
#create df
data={'id':[1,1,1,1,2,2,2,2],
'date1':[datetime.date(2016,1,1),datetime.date(2016,7,23),datetime.date(2017,2,26),datetime.date(2017,5,28),
datetime.date(2015,11,1),datetime.date(2016,7,23),datetime.date(2017,6,28),datetime.date(2017,5,23)],
'date2':[datetime.date(2017,5,12),datetime.date(2016,8,10),datetime.date(2017,10,26),datetime.date(2017,9,22),
datetime.date(2015,11,9),datetime.date(2016,9,23),datetime.date(2017,8,3),datetime.date(2017,9,22)]}
df=pd.DataFrame.from_dict(data)
df=df[['id','date1','date2']]

看起来是这样的:

df
Out[83]: 
id       date1       date2
0   1  2016-01-01  2017-05-12
1   1  2016-07-23  2016-08-10
2   1  2017-02-26  2017-10-26
3   1  2017-05-28  2017-09-22
4   2  2015-11-01  2015-11-09
5   2  2016-07-23  2016-09-23
6   2  2017-06-28  2017-08-03
7   2  2017-05-23  2017-09-22

我需要做的是创建一个名为"newdate"的新列,在groupby['id']级别,它将从date1和date2列中获取所有按日期分组的唯一值,并从date2中日期之后的这些唯一值中给我下一个未来日期。

因此,新的数据帧看起来像:

df
Out[87]: 
id       date1       date2     newdate
0   1  2016-01-01  2017-05-12  2017-05-28
1   1  2016-07-23  2016-08-10  2017-02-26
2   1  2017-02-26  2017-10-26        None
3   1  2017-05-28  2017-09-22  2017-10-26
4   2  2015-11-01  2015-11-09  2016-07-23
5   2  2016-07-23  2016-09-23  2017-05-23
6   2  2017-06-28  2017-08-03  2017-09-22
7   2  2017-05-23  2017-09-22        None

为了进行澄清,请查看id=2的记录。请注意,第4行中的新日期为2016-07-23。这是因为它是date1&date2,它跟在行4 date2之后。

我们肯定需要使用groupby。我想我们可以使用unique()、np.unique、pd.unique的一些形式来获取日期?但是,你如何选择"下一个"并分配?只是被难住了。。。

其他几点。不要假设数据帧是以任何方式排序的,效率在这里很重要,因为实际的数据帧非常大。还要注意,newdate中的"None"值之所以存在,是因为我们没有表示"NEXT"未来日期,因为子集中的最大日期与date2相同。我们可以用"无"、"南"、"任何"来代表这些。。。

编辑:根据温的回答,如果日期相似,他的回答就会失败。如果您使用此数据集:

data={'id':[1,1,1,1,2,2,2,2],
'date1':[datetime.date(2016,1,1),datetime.date(2016,7,23),datetime.date(2017,2,26),datetime.date(2017,5,28),
datetime.date(2015,11,1),datetime.date(2016,7,23),datetime.date(2017,6,28),datetime.date(2017,5,23)],
'date2':[datetime.date(2017,5,12),datetime.date(2017,5,12),datetime.date(2017,2,26),datetime.date(2017,9,22),
datetime.date(2015,11,9),datetime.date(2016,9,23),datetime.date(2017,8,3),datetime.date(2017,9,22)]}
df=pd.DataFrame.from_dict(data)
df=df[['id','date1','date2']]

那么结果是:

df
Out[104]: 
id       date1       date2     newdate
0   1  2016-01-01  2017-05-12  2017-05-12
1   1  2016-07-23  2017-05-12  2017-05-28
2   1  2017-02-26  2017-02-26  2017-05-12
3   1  2017-05-28  2017-09-22         NaN
4   2  2015-11-01  2015-11-09  2016-07-23
5   2  2016-07-23  2016-09-23  2017-05-23
6   2  2017-06-28  2017-08-03  2017-09-22
7   2  2017-05-23  2017-09-22         NaN

请注意,第0行的"newdate"应为2017-05-28,即date1&id==1的date2。

我相信融化会让我们更接近。。。

可能不是最快的,这取决于实际的数据帧("非常大"可能意味着任何东西)。基本上有两个步骤——首先为每个日期到下一个日期创建一个查找表。然后将该查找与原始表合并。

#get the latest date for each row - just the max of date1 and date2
df['latest_date'] = df.loc[:, ['date1','date2']].max(axis=1)
#for each date, find the next date - basically create a lookup table
new_date_lookup = (df
.melt(id_vars=['id'], value_vars=['date1', 'date2'])
.loc[:, ['id','value']]
)
new_date_lookup = (new_date_lookup
.merge(new_date_lookup, on="id")
.query("value_y > value_x")
.groupby(["id", "value_x"])
.min()
.reset_index()
.rename(columns={'value_x': 'value', 'value_y':'new_date'})
)
#merge the original and lookup table together to get the new_date for each row
new_df = (pd
.merge(df, new_date_lookup, how='left', left_on=['id', 'latest_date'], right_on=['id','value'])
.drop(['latest_date', 'value'], axis=1)
)
print(new_df)

哪个输出:

id       date1       date2    new_date
0   1  2016-01-01  2017-05-12  2017-05-28
1   1  2016-07-23  2016-08-10  2017-02-26
2   1  2017-02-26  2017-10-26         NaN
3   1  2017-05-28  2017-09-22  2017-10-26
4   2  2015-11-01  2015-11-09  2016-07-23
5   2  2016-07-23  2016-09-23  2017-05-23
6   2  2017-06-28  2017-08-03  2017-09-22
7   2  2017-05-23  2017-09-22         NaN

对于第二个例子,添加到编辑中,给出了输出:

id       date1       date2    new_date
0   1  2016-01-01  2017-05-12  2017-05-28
1   1  2016-07-23  2017-05-12  2017-05-28
2   1  2017-02-26  2017-02-26  2017-05-12
3   1  2017-05-28  2017-09-22         NaN
4   2  2015-11-01  2015-11-09  2016-07-23
5   2  2016-07-23  2016-09-23  2017-05-23
6   2  2017-06-28  2017-08-03  2017-09-22
7   2  2017-05-23  2017-09-22         NaN

相关内容

最新更新