Groupby - 如何将逻辑检查结果应用于所有行

时间:2016-05-07 14:58:10

标签: python python-3.x pandas

我有一个看起来像这样的集合:

In [127]: df
Out[127]: 
   ID                Date regular_entry
0   1 2014-01-31 12:13:14          True
1   2 2014-02-28 12:13:14         False
2   1 2014-03-31 12:13:14          True
3   1 2014-04-30 12:13:14          True
4   2 2014-05-31 12:13:14         False
5   2 2014-06-30 12:13:14          True
6   3 2014-07-31 12:13:14         False
7   3 2014-08-31 12:13:14          True
8   3 2014-09-30 12:13:14         False
9   1 2014-10-31 12:13:14          True

我需要查找每个组是否有任何行,例如'regular_entry' == False(如果按'ID'分组)。

我正在使用pandas.Series.all()transform()来实现这一目标 - 如下所示 - 并且效果很好:

In [134]: df['ever_irregular'] = df.groupby('ID')['regular_entry'].transform(lambda x: False if x.all() else True )

In [135]: df
Out[135]: 
   ID                Date regular_entry ever_irregular
0   1 2014-01-31 12:13:14          True          False
1   2 2014-02-28 12:13:14         False           True
2   1 2014-03-31 12:13:14          True          False
3   1 2014-04-30 12:13:14          True          False
4   2 2014-05-31 12:13:14         False           True
5   2 2014-06-30 12:13:14          True           True
6   3 2014-07-31 12:13:14         False           True
7   3 2014-08-31 12:13:14          True           True
8   3 2014-09-30 12:13:14         False           True
9   1 2014-10-31 12:13:14          True          False

现在,我还需要查找每个组的最后一个条目(如果按'ID'分组并考虑'Date'的值)是否'regular_entry' == False

我知道我可以像这样获得每组的最后一个条目:

In [138]: df.sort_values(by='Date').groupby('ID').nth(-1)['regular_entry']
Out[138]: 
ID
1     True
2     True
3    False
Name: regular_entry, dtype: bool

我现在已经想到我可以尝试加入这两个:

In [152]: df_new = pd.DataFrame(latest_row_regular).rename(columns={'regular_entry':'latest_regular'})

In [155]: pd.merge(df, df_new, left_on='ID', right_index=True).sort_values(by='Date')
Out[155]: 
   ID                Date regular_entry ever_irregular latest_regular
0   1 2014-01-31 12:13:14          True          False           True
1   2 2014-02-28 12:13:14         False           True           True
2   1 2014-03-31 12:13:14          True          False           True
3   1 2014-04-30 12:13:14          True          False           True
4   2 2014-05-31 12:13:14         False           True           True
5   2 2014-06-30 12:13:14          True           True           True
6   3 2014-07-31 12:13:14         False           True          False
7   3 2014-08-31 12:13:14          True           True          False
8   3 2014-09-30 12:13:14         False           True          False
9   1 2014-10-31 12:13:14          True          False           True

这似乎工作正常,然而,它看起来似乎很长。是否有一些更容易/更快的方法来获取每个组的值(在groupby()后分组)并直接应用而不是遵循所有中间步骤?

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

我认为您可以transform使用iloc

df['latest_regular'] = df.groupby('ID')['regular_entry'].transform(lambda x: x.iloc[-1])
print df
   ID                Date regular_entry latest_regular
0   1 2014-01-31 12:13:14          True           True
1   2 2014-02-28 12:13:14         False           True
2   1 2014-03-31 12:13:14          True           True
3   1 2014-04-30 12:13:14          True           True
4   2 2014-05-31 12:13:14         False           True
5   2 2014-06-30 12:13:14          True           True
6   3 2014-07-31 12:13:14         False          False
7   3 2014-08-31 12:13:14          True          False
8   3 2014-09-30 12:13:14         False          False
9   1 2014-10-31 12:13:14          True           True

我认为测试是最好的使用自定义函数print instaed of lambda:

def f(x):
    print x
    print x.iloc[-1]
    return x.iloc[-1]


df['latest_regular'] = df.groupby('ID')['regular_entry'].transform(f)
print df

测试后使用lambda函数。

答案 1 :(得分:1)

您可以通过以下方式使用相同的.transform来电:

df['latest_regular'] = (df.groupby('ID')['regular_entry']
                        .transform(lambda x: x.iloc[-1]))

工作示例:

df['last_regular'] = df.groupby('ID')['regular_entry'].transform(lambda x: x.iloc[-1])

17:41:18 [26]: df
Out[26]:
   ID regular_entry last_regular
0   1          True         True
1   2         False         True
2   1          True         True
3   1          True         True
4   2         False         True
5   2          True         True
6   3         False        False
7   3          True        False
8   3         False        False
9   1          True         True