groupby查找具有最大值的行是将对象转换为datetime

时间:2015-01-22 18:23:18

标签: python pandas

我想通过两个变量['CIN','calendar']进行分组,并返回该组MCelig列在该特定组中最大的行。可能多行将具有最大值,但我只想要一行。

例如:

  AidCode CIN  MCelig   calendar
0    None  1e       1 2014-03-08
1      01  1e       2 2014-03-08
2      01  1e       3 2014-05-08
3    None  2e       4 2014-06-08
4      01  2e       5 2014-06-08

由于前两行是一组,我想要MCelig = 2的行 我想出了这一行

test=dfx.groupby(['CIN','calendar'], group_keys=False).apply(lambda x: x.ix[x.MCelig.idxmax()])

并且它似乎有效,除非我对列的组中的所有值都有“无”或“np.nan”,该列将转换为日期时间!请参阅下面的示例,观看AidCode从一个对象转到一个日期。

import datetime as DT
import numpy as np
d = {'CIN' : pd.Series(['1e','1e','1e','2e','2e']),
'AidCode' : pd.Series([np.nan,'01','01',np.nan,'01']),
'calendar' : pd.Series([DT.datetime(2014, 3, 8), DT.datetime(2014, 3, 8),DT.datetime(2014, 5, 8),DT.datetime(2014, 6, 8),DT.datetime(2014, 6, 8)]),
'MCelig' : pd.Series([1,2,3,4,5])}
dfx=pd.DataFrame(d)
#testing whether it was just the np.nan that was the problem, it isn't
#dfx = dfx.where((pd.notnull(dfx)), None)
test=dfx.groupby(['CIN','calendar'], group_keys=False).apply(lambda x: x.ix[x.MCelig.idxmax()])

输出

Out[820]: 
                  AidCode CIN  MCelig   calendar
CIN calendar                                    
1e  2014-03-08 2015-01-01  1e       2 2014-03-08
    2014-05-08 2015-01-01  1e       3 2014-05-08
2e  2014-06-08 2015-01-01  2e       5 2014-06-08

更新

刚刚想出了这个简单的解决方案

x=dfx.sort(['CIN','calendar',"MCelig"]).groupby(["CIN",'calendar'], as_index=False).last();x

因为它有效,我想我选择它是为了简单起见。

1 个答案:

答案 0 :(得分:2)

Pandas通过识别看起来像日期的列并将列转换为datetime64 dtype来尝试更有帮助。它在这里过于咄咄逼人。

解决方法是使用transform为每个选择最大行的组生成布尔掩码

def onemax(x):
    mask = np.zeros(len(x), dtype='bool')
    idx = np.argmax(x.values)
    mask[idx] = 1
    return mask

dfx.loc[dfx.groupby(['CIN','calendar'])['MCelig'].transform(onemax).astype(bool)]

产量

  AidCode CIN  MCelig   calendar
1      01  1e       2 2014-03-08
2      01  1e       3 2014-05-08
4      01  2e       5 2014-06-08

技术细节:当使用groupby-apply时,当各个DataFrames(由应用函数返回)粘合在一起形成一个DataFrame时,Pandas会尝试猜测列是否 对象dtype是类似日期的对象,如果是,convert the column to an actual date dtype。如果值是字符串,它会尝试将它们解析为 使用dateutil.parser的日期:

无论好坏,dateutil.parser都会将'01'解释为日期:

In [37]: import dateutil.parser as DP

In [38]: DP.parse('01')
Out[38]: datetime.datetime(2015, 1, 1, 0, 0)

这会导致Pandas尝试将整个AidCode列转换为日期。由于没有发生错误,它认为它只是帮助你:))