groupby之后,针对组中所有行中的列值评估列中的值

时间:2019-12-24 12:03:29

标签: python pandas date pandas-groupby

我正在寻找python中的以下功能:

我有一个带有4列的Pandas DataFrame:ID,StartDate,EndDate,Moment。

我想按ID分组,并在组中的每一行评估Moment变量是否介于StartDate和EndDate之间。问题是我想对组中的每一行进行评估。例如,在下面的DataFrame中,有两个组(ID = 1和ID = 2),并且两个组都包含5行。对于每一行,我都希望两个组中的每一行都为一个布尔值,该行中的矩变量是否属于该组中的任何时间窗口,该窗口为[date1,date2]。

import pandas as pd

i = pd.date_range('2018-04-11', periods=10, freq='2D20min')
i2 = pd.date_range('2018-04-12', periods=10, freq='2D20min')
i3 = pd.date_range('2018-04-9', periods=10, freq='1D6H')
id = ['1', '1', '1', '1', '1', '2', '2', '2', '2', '2']
ts = pd.DataFrame({'date1': i, 'date2': i2, 'moment': i3}, index=id)

ID  date1               date2               moment
1   2018-04-11 00:00:00 2018-04-12 00:00:00 2018-04-09 00:00:00
1   2018-04-13 00:20:00 2018-04-14 00:20:00 2018-04-10 06:00:00
1   2018-04-15 00:40:00 2018-04-16 00:40:00 2018-04-11 12:00:00
1   2018-04-17 01:00:00 2018-04-18 01:00:00 2018-04-12 18:00:00
1   2018-04-19 01:20:00 2018-04-20 01:20:00 2018-04-14 00:00:00
2   2018-04-21 01:40:00 2018-04-22 01:40:00 2018-04-15 06:00:00
2   2018-04-23 02:00:00 2018-04-24 02:00:00 2018-04-16 12:00:00
2   2018-04-25 02:20:00 2018-04-26 02:20:00 2018-04-17 18:00:00
2   2018-04-27 02:40:00 2018-04-28 02:40:00 2018-04-19 00:00:00
2   2018-04-29 03:00:00 2018-04-30 03:00:00 2018-04-20 06:00:00

在这种情况下,第一组第一行中的矩值不会在五个时间间隔中的任何一个中下降。第二个也没有。第三个值2018-04-11 12:00:00确实落在第一行的时间间隔中,因此,我希望返回True

所需结果如下:

ID  date1               date2               moment              result
1   2018-04-11 00:00:00 2018-04-12 00:00:00 2018-04-09 00:00:00 False
1   2018-04-13 00:20:00 2018-04-14 00:20:00 2018-04-10 06:00:00 False
1   2018-04-15 00:40:00 2018-04-16 00:40:00 2018-04-11 12:00:00 True
1   2018-04-17 01:00:00 2018-04-18 01:00:00 2018-04-12 18:00:00 False
1   2018-04-19 01:20:00 2018-04-20 01:20:00 2018-04-14 00:00:00 True
2   2018-04-21 01:40:00 2018-04-22 01:40:00 2018-04-15 06:00:00 False
2   2018-04-23 02:00:00 2018-04-24 02:00:00 2018-04-16 12:00:00 False
2   2018-04-25 02:20:00 2018-04-26 02:20:00 2018-04-17 18:00:00 False
2   2018-04-27 02:40:00 2018-04-28 02:40:00 2018-04-19 00:00:00 False
2   2018-04-29 03:00:00 2018-04-30 03:00:00 2018-04-20 06:00:00 False

编辑

我已经通过以下方法“解决”了这个问题,但是我正在寻找一种更Python化甚至更快的方法...

boolean_result = []
for c in ts.index.unique():
    temp = ts.loc[ts.index == c]
    for row in temp.index:
        current_date = temp['moment'][row]
        boolean_result.append(max((temp['date1'] <= current_date)
                                  & (current_date <= temp['date2'])))
ts['Result'] = boolean_result

1 个答案:

答案 0 :(得分:1)

如果您的数据框太大,这实际上可能会非常慢,并且可能有除此以外的最佳解决方案:

def time_in_range(start, end, x):
    """Return true if x is in the range [start, end]"""
    if start <= x and x <= end:
        return True
    else:
        return False

# empty list to be appended
result = []
test_list = []

for i in ts.index.unique():

    temp_df = ts[ts.index == i]

    for j in range(0, len(temp_df)):
        for k in range(0, len(temp_df)):    
            test_list.append(time_in_range(temp_df.date1.iloc[k], temp_df.date2.iloc[k], temp_df.moment.iloc[j]))

        result.append(any(test_list))
        # reset the list
        test_list = []

ts['result'] = result