取空值的最小值和最大值 - pandas groupby
Take min and max with null values - pandas groupby
我有一个 pandas.DataFrame
,看起来像这样:
| id | start | end |
|:--:|:-----------------:|:----------------:|
| a | 1/1/20 12:00 AM | 1/2/20 12:00 AM |
| b | 1/1/20 6:37 PM | 1/2/20 7:11 PM |
| b | 1/4/20 1:17 AM | |
| c | 2/4/20 12:00 AM | 7/13/20 12:00 AM |
| d | 4/19/20 8:45 PM | 4/23/20 12:13 AM |
| d | 11/21/20 12:00 AM | 3/2/21 12:00 AM |
我正在尝试为每个 id
确定 min()
start
和 max()
end
。我的问题是,在某些情况下,end
可以为空,在这种情况下,它应该算作最大值(即问题未关闭)。
理想情况下,结果应该是这样的:
| id | start | end |
|:--:|:---------------:|:----------------:|
| a | 1/1/20 12:00 AM | 1/2/20 12:00 AM |
| b | 1/1/20 6:37 PM | |
| c | 2/4/20 12:00 AM | 7/13/20 12:00 AM |
| d | 4/19/20 8:45 PM | 3/2/21 12:00 AM |
我查看了 this question 以获得灵感,但没有找到解决方案。
MRE 下面:
import pandas as pd, numpy as np
df = pd.DataFrame.from_dict({'id': {0: 'a', 1: 'b', 2: 'b', 3: 'c', 4: 'd', 5: 'd'}, 'start': {0: '1/1/20 12:00 AM', 1: '1/1/20 6:37 PM', 2: '1/4/20 1:17 AM', 3: '2/4/20 12:00 AM', 4: '4/19/20 8:45 PM', 5: '11/21/20 12:00 AM'}, 'end': {0: '1/2/20 12:00 AM', 1: '1/2/20 7:11 PM', 2: np.nan, 3: '7/13/20 12:00 AM', 4: '4/23/20 12:13 AM', 5: '3/2/21 12:00 AM'}})
df['start'] = pd.to_datetime(df['start'])
df['end'] = pd.to_datetime(df['end'])
starts = df.groupby('id')['start'].min().reset_index()
ends = df.groupby('id')['end'].max().reset_index()
_df = pd.merge(starts, ends, on='id')
然而,这会产生:
| id | start | end |
|:--:|:---------------:|:--------------:|
| a | 1/1/2020 0:00 | 1/2/2020 0:00 |
| b | 1/1/2020 18:37 | 1/2/2020 19:11 |
| c | 2/4/2020 0:00 | 7/13/2020 0:00 |
| d | 4/19/2020 20:45 | 3/2/2021 0:00 |
我怎样才能达到我想要的结果?
IIUC,DataFrame.mask
设置 NaN,其中每个组都有任何 nan 和 col
new_df = \
df.groupby('id')\
.agg({'start':'min', 'end':'max'})\
.mask(df[['start', 'end']].isna()
.groupby(df['id'])
.max())\
.reset_index()
print(new_df)
id start end
0 a 2020-01-01 00:00:00 2020-01-02
1 b 2020-01-01 18:37:00 NaT
2 c 2020-02-04 00:00:00 2020-07-13
3 d 2020-04-19 20:45:00 2021-03-02
详情:
print(df[['start', 'end']].isna()
.groupby(df['id'])
.max())
start end
id
a False False
b False True
c False False
d False False
在多列分组的情况下:
new_df = \
df.groupby(['id', 'status'])\
.agg({'start':'min', 'end':'max'})\
.mask(df[['start', 'end']].isna()
.groupby([df['id'], df['status']])
.max())\
.reset_index()
按日期排序并使用 iloc
获取最后一个值
df.sort_values(["start", "end"]).groupby("id").agg({"start": "first",
"end": lambda x: x.iloc[-1]})
# start end
# id
# a 2020-01-01 00:00:00 2020-01-02
# b 2020-01-01 18:37:00 NaT
# c 2020-02-04 00:00:00 2020-07-13
# d 2020-04-19 20:45:00 2021-03-02
我有一个 pandas.DataFrame
,看起来像这样:
| id | start | end |
|:--:|:-----------------:|:----------------:|
| a | 1/1/20 12:00 AM | 1/2/20 12:00 AM |
| b | 1/1/20 6:37 PM | 1/2/20 7:11 PM |
| b | 1/4/20 1:17 AM | |
| c | 2/4/20 12:00 AM | 7/13/20 12:00 AM |
| d | 4/19/20 8:45 PM | 4/23/20 12:13 AM |
| d | 11/21/20 12:00 AM | 3/2/21 12:00 AM |
我正在尝试为每个 id
确定 min()
start
和 max()
end
。我的问题是,在某些情况下,end
可以为空,在这种情况下,它应该算作最大值(即问题未关闭)。
理想情况下,结果应该是这样的:
| id | start | end |
|:--:|:---------------:|:----------------:|
| a | 1/1/20 12:00 AM | 1/2/20 12:00 AM |
| b | 1/1/20 6:37 PM | |
| c | 2/4/20 12:00 AM | 7/13/20 12:00 AM |
| d | 4/19/20 8:45 PM | 3/2/21 12:00 AM |
我查看了 this question 以获得灵感,但没有找到解决方案。
MRE 下面:
import pandas as pd, numpy as np
df = pd.DataFrame.from_dict({'id': {0: 'a', 1: 'b', 2: 'b', 3: 'c', 4: 'd', 5: 'd'}, 'start': {0: '1/1/20 12:00 AM', 1: '1/1/20 6:37 PM', 2: '1/4/20 1:17 AM', 3: '2/4/20 12:00 AM', 4: '4/19/20 8:45 PM', 5: '11/21/20 12:00 AM'}, 'end': {0: '1/2/20 12:00 AM', 1: '1/2/20 7:11 PM', 2: np.nan, 3: '7/13/20 12:00 AM', 4: '4/23/20 12:13 AM', 5: '3/2/21 12:00 AM'}})
df['start'] = pd.to_datetime(df['start'])
df['end'] = pd.to_datetime(df['end'])
starts = df.groupby('id')['start'].min().reset_index()
ends = df.groupby('id')['end'].max().reset_index()
_df = pd.merge(starts, ends, on='id')
然而,这会产生:
| id | start | end |
|:--:|:---------------:|:--------------:|
| a | 1/1/2020 0:00 | 1/2/2020 0:00 |
| b | 1/1/2020 18:37 | 1/2/2020 19:11 |
| c | 2/4/2020 0:00 | 7/13/2020 0:00 |
| d | 4/19/2020 20:45 | 3/2/2021 0:00 |
我怎样才能达到我想要的结果?
IIUC,DataFrame.mask
设置 NaN,其中每个组都有任何 nan 和 col
new_df = \
df.groupby('id')\
.agg({'start':'min', 'end':'max'})\
.mask(df[['start', 'end']].isna()
.groupby(df['id'])
.max())\
.reset_index()
print(new_df)
id start end
0 a 2020-01-01 00:00:00 2020-01-02
1 b 2020-01-01 18:37:00 NaT
2 c 2020-02-04 00:00:00 2020-07-13
3 d 2020-04-19 20:45:00 2021-03-02
详情:
print(df[['start', 'end']].isna()
.groupby(df['id'])
.max())
start end
id
a False False
b False True
c False False
d False False
在多列分组的情况下:
new_df = \
df.groupby(['id', 'status'])\
.agg({'start':'min', 'end':'max'})\
.mask(df[['start', 'end']].isna()
.groupby([df['id'], df['status']])
.max())\
.reset_index()
按日期排序并使用 iloc
获取最后一个值
df.sort_values(["start", "end"]).groupby("id").agg({"start": "first",
"end": lambda x: x.iloc[-1]})
# start end
# id
# a 2020-01-01 00:00:00 2020-01-02
# b 2020-01-01 18:37:00 NaT
# c 2020-02-04 00:00:00 2020-07-13
# d 2020-04-19 20:45:00 2021-03-02