Python 查找每个组的唯一项目数
我有一个Python 查找每个组的唯一项目数,python,pandas,dataframe,Python,Pandas,Dataframe,我有一个dfa看起来像 type number date 1 1 2017-10-01 2 1 2017-10-31 1 2 2017-09-01 1 2 2017-08-01 2 2 2017-06-01 type number date type_2_before_type_1 1 1
df
a
看起来像
type number date
1 1 2017-10-01
2 1 2017-10-31
1 2 2017-09-01
1 2 2017-08-01
2 2 2017-06-01
type number date type_2_before_type_1
1 1 2017-10-01 True
2 1 2017-10-31 True
1 2 2017-09-01 False
1 2 2017-08-01 False
2 2 2017-06-01 False
首先,我想按编号分组,并选择每个组需要至少包含一行type==1
和一行type==2
的组;为了做到这一点,我首先检查每个组的大小必须大于2
g = A.groupby('number')
B = g.filter(lambda x: len(x) > 1) # df B gets the filter results on g
但我不知道如何也检查type
值1
和2
是否包含在上述各组中
第二,基于从步骤1中获得的组,我想在a
中创建一个布尔列,称为type\u 2\u,在
之前,如果type 1的最早date
减去type 2的最早date
为每个组的0
,则赋值为True
,和False
否则。因为每组中可能有许多行的type==1
和许多行的type==2
(如何获得g['A'].transform('min')
,用于类型1和类型2行?)。因此,结果df
A
如下所示
type number date
1 1 2017-10-01
2 1 2017-10-31
1 2 2017-09-01
1 2 2017-08-01
2 2 2017-06-01
type number date type_2_before_type_1
1 1 2017-10-01 True
2 1 2017-10-31 True
1 2 2017-09-01 False
1 2 2017-08-01 False
2 2 2017-06-01 False
e、 g.对于编号=2的组,类型1的最早日期2017-08-01
减去类型2的最早日期2017-06-01
,结果为61天;因此,将False
设置为type\u 2\u然后再键入\u 1
对于第一部分,使用groupby
+nunique
-
df.groupby('number').type.transform('nunique')
0 2
1 2
2 2
3 2
4 2
Name: type, dtype: int64
df = df[df.groupby('number').type.transform('nunique').gt(1)]
type number date
0 1 1 2017-10-01
1 2 1 2017-10-31
2 1 2 2017-09-01
3 1 2 2017-08-01
4 2 2 2017-06-01
第二部分有点挑战性,但您可以groupby
,unstack
,调用diff
,然后获得一个掩码-
df['type_2_before_type_1'] = \
df.groupby(['number', 'type'])\
.first()\
.unstack()\
.diff(-1, axis=1)\
.iloc[:, 0]\
.reindex(df.number)\
.astype(int)\
.lt(0)\
.values
df
type number date type_2_before_type_1
0 1 1 2017-10-01 True
1 2 1 2017-10-31 True
2 1 2 2017-09-01 False
3 1 2 2017-08-01 False
4 2 2 2017-06-01 False
对于第一部分,使用groupby
+nunique
-
df.groupby('number').type.transform('nunique')
0 2
1 2
2 2
3 2
4 2
Name: type, dtype: int64
df = df[df.groupby('number').type.transform('nunique').gt(1)]
type number date
0 1 1 2017-10-01
1 2 1 2017-10-31
2 1 2 2017-09-01
3 1 2 2017-08-01
4 2 2 2017-06-01
第二部分有点挑战性,但您可以groupby
,unstack
,调用diff
,然后获得一个掩码-
df['type_2_before_type_1'] = \
df.groupby(['number', 'type'])\
.first()\
.unstack()\
.diff(-1, axis=1)\
.iloc[:, 0]\
.reindex(df.number)\
.astype(int)\
.lt(0)\
.values
df
type number date type_2_before_type_1
0 1 1 2017-10-01 True
1 2 1 2017-10-31 True
2 1 2 2017-09-01 False
3 1 2 2017-08-01 False
4 2 2 2017-06-01 False
例如,在您的号码2中,如果日期是2017-09-01 2017-02-01 2017-06-01,结果会是什么?@Wen对于编号为的组,它会将True
设置为type_2_,然后再键入_1
,因为2017-02-01-2017-06-01=-120<0
,例如,在您的号码2中,如果日期是2017-09-01 2017-02-01 2017-06-01,结果会是什么?@Wen对于number
==2的组,它会将True
设置为type_2_,然后再键入_1
,因为2017-02-01-2017-06-01=-120<0
很好的组,只需要反转掩码。@cᴏʟᴅsᴘᴇᴇᴅ 啊哈,你是对的:-)我借用了你的段落名称:-)@Wen或者干脆用(I
代替~(I>j)
?@Wen这个解决方案有一个问题,即对于一个组,它可能没有类型1或类型2,因此运行g.apply(lambda x:min(x['date'][x.type==1])
和g.apply(da x:min(x['date'][x.type==2])
在确保每组中都有类型1和类型2之前,可能会得到min()arg是一个空序列
错误?我应该在op中指出它,sry。很好的一个,只需要反转掩码。@cᴏʟᴅsᴘᴇᴇᴅ 啊哈,你是对的:-)我借用了你的段落名称:-)@Wen或者干脆用(I
代替~(I>j)
?@Wen这个解决方案有一个问题,即对于一个组,它可能没有类型1或类型2,因此运行g.apply(lambda x:min(x['date'][x.type==1])
和g.apply(da x:min(x['date'][x.type==2])
在确保每组中都有类型1和类型2之前,可能会得到min()arg是一个空序列
错误?我应该在op,sry中指出它。