按唯一名称和状态以及最后一个日期分组

时间:2019-03-28 09:34:44

标签: python pandas dataframe group-by crosstab

我想分析每辆汽车的统计数据,这些统计数据是修理的和新的。数据样本为:

Name   IsItNew    ControlDate
Car1    True      31/01/2018
Car2    True      28/02/2018
Car1    False     15/03/2018
Car2    True      16/04/2018
Car3    True      30/04/2018
Car2    False     25/05/2018
Car1    False     30/05/2018    

因此,我应该按名称groupby,如果False列中有IsItNew,我应该设置False和第一个日期,当False时发生了。

我用groupby尝试了nunique()

df = df.groupby(['Name','IsItNew', 'ControlDate' ])['Name'].nunique()

但是,它返回每个组中唯一项目的数量。

我怎样才能只收到没有任何计数的分组唯一项目?

Actual result is:

Name   IsItNew       ControlDate
Car1    True         31/01/2018     1
        False        15/03/2018     1
                     30/05/2018     1
Car2    True         28/02/2018     1
                     16/04/2018     1
        False        25/05/2018     1 
Car3    True         30/04/2018     1


Expected Result is:

Name   IsItNew     ControlDate
Car1    False      15/03/2018
Car2    False      25/05/2018
Car3    True       30/04/2018

任何想法,我将不胜感激。谢谢)

2 个答案:

答案 0 :(得分:2)

一种实现方法是GroupBy Name,并通过两个函数在IsItNew上聚合。一个自定义变量,使用any来检查是否有任何False值,然后使用idxmin来查找第一个False的索引,您以后可以使用它来建立索引ControlDate上的数据框:

df_ = df.groupby('Name').agg({'IsItNew':
                                   {'IsItNew':lambda x: ~(~x).any(),
                                    'ControlDate':'idxmin'}})
                        .droplevel(0, axis=1)
                        .reset_index()

df_['ControlDate'] = df.loc[df_['ControlDate'].values, 'ControlDate'].reset_index(drop=True)

  xName  IsItNew ControlDate
0  Car1    False  15/03/2018
1  Car2    False  25/05/2018
2  Car3     True  30/04/2018

答案 1 :(得分:1)

首先按to_datetime将列转换为日期时间,然后按DataFrame.sort_values按3列排序,最后按DataFrame.drop_duplicates按列Name s首先获取行:

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

df = df.sort_values(['Name','IsItNew', 'ControlDate']).drop_duplicates('Name')

print (df)
   Name  IsItNew ControlDate
2  Car1    False  2018-03-15
5  Car2    False  2018-05-25
4  Car3     True  2018-04-30

编辑:

print (df)
   Name  IsItNew ControlDate
0  Car1     True  31/01/2018
1  Car2     True  28/02/2018
2  Car1    False  15/03/2018
3  Car2     True  16/04/2018
4  Car3     True  30/04/2018
5  Car2    False  25/05/2018
6  Car1    False  30/05/2018
7  Car3     True  20/10/2019
8  Car3     True  30/04/2017

#set to datetimes
df['ControlDate'] = pd.to_datetime(df['ControlDate'])
#sorting by 3 columns
df1 = df.sort_values(['Name','IsItNew', 'ControlDate'])

#create Series for replace
s = df1.drop_duplicates('Name', keep='last').set_index('Name')['ControlDate']

#filter by Falses
df2 = df1.drop_duplicates('Name').copy()
#replace True rows by last timestamp
df2.loc[df2['IsItNew'], 'ControlDate'] = df2.loc[df2['IsItNew'], 'Name'].map(s)
print (df2)
   Name  IsItNew ControlDate
2  Car1    False  2018-03-15
5  Car2    False  2018-05-25
8  Car3     True  2019-10-20