【问题标题】:apply two lambda functions on a pandas dataframe at column and row levels在 pandas 数据帧的列和行级别上应用两个 lambda 函数
【发布时间】:2020-12-08 13:09:00
【问题描述】:

我想groupby一个基于 key_col 列表的 pandas 数据框,并在每个组中执行两件事:

  1. 首先根据 from_date_col 对值进行排序
  2. to_date_col 列上执行移位并进行比较,返回一个布尔值并说明日期是否重叠(参见下面的测试示例)

我当前的代码如下所示:

def get_overlapping_date_range(df, key_col, from_date_col, to_date_col):

df['is_overlap'] = (df
                    .groupby(key_col)
                    .apply(lambda x: x.sort_values(from_date_col))
                    .apply(lambda x: (x[to_date_col].shift() - x[from_date_col]) > timedelta(0))
                    .reset_index(level=0, drop=True))

return df

这些 lambda 单独工作,但不能一起工作。我得到的错误是:KeyError: ('to', 'occurred at index id')

为了清楚起见,我想给出这个输入:

df = pd.DataFrame(columns=['id','from','to'], index=range(7),
                  data=[[878, date(2006,1,1), date(2007,10,1)],
                        [878, date(2007,10,2), date(2008,12,1)],
                        [878, date(2008,12,2), date(2010,4,3)],
                        [879, date(2010,4,4), date(2199,5,10)],
                        [879, date(2016,5,12), date(2199,12,31)],
                        [880, date(2011,7,8), date(2013,3,3)],
                        [880, date(2010,2,12), date(2015,5,5)]])

并调用get_overlapping_date_range(df, 'id', 'from', 'to') 并获得以下输出:

        id        from          to  is_overlap
0  878  2006-01-01  2007-10-01       False
1  878  2007-10-02  2008-12-01       False
2  878  2008-12-02  2010-04-03       False
3  879  2010-04-04  2199-05-10       False
4  879  2016-05-12  2199-12-31        True
5  880  2011-07-08  2013-03-03       False
6  880  2010-02-12  2015-05-05        True

我想在 groupby 中进行排序的原因是数据框太大。 当混合使用 col 和 row 操作时,如何在 groupby 上应用两个 lambda?我发现的所有solutions 都是基于列的活动。

【问题讨论】:

  • 第三个索引 - 年份是否正确?提到 2199 ?
  • 以2019年为年份。
  • 下面的代码好吗?
  • 回复有问题吗?
  • 请回复,以便我关闭此问题

标签: pandas lambda pandas-groupby


【解决方案1】:
from datetime import datetime
import pandas as pd

df = pd.DataFrame(columns=['id','from','to'], index=range(7),
              data=[[878, datetime(2006,1,1), datetime(2007,10,1)],
                    [878, datetime(2007,10,2), datetime(2008,12,1)],
                    [878, datetime(2008,12,2), datetime(2010,4,3)],
                    [879, datetime(2010,4,4), datetime(2199,5,10)],
                    [879, datetime(2016,5,12), datetime(2199,12,31)],
                    [880, datetime(2011,7,8), datetime(2013,3,3)],
                    [880, datetime(2010,2,12), datetime(2015,5,5)]])
print(df)

id       from         to
0  878 2006-01-01 2007-10-01
1  878 2007-10-02 2008-12-01
2  878 2008-12-02 2010-04-03
3  879 2010-04-04 2199-05-10
4  879 2016-05-12 2199-12-31
5  880 2011-07-08 2013-03-03
6  880 2010-02-12 2015-05-05

def check_date_by_id(df):

    df['prevFrom'] = df['from'].shift()
    df['prevTo'] = df['to'].shift()

    def check_date_by_row(x):

        if pd.isnull(x.prevFrom) or pd.isnull(x.prevTo):
             x['overlap'] = False
             return x

        latest_start = max(x['from'], x.prevFrom)
        earliest_end = min(x['to'], x.prevTo)
        x['overlap'] = int((earliest_end - latest_start).days) + 1 > 0
        return x

    return df.apply(check_date_by_row, axis=1).drop(['prevFrom','prevTo'], axis=1)

print(df.groupby('id').apply(check_date_by_id))

id       from         to  overlap
0  878 2006-01-01 2007-10-01    False
1  878 2007-10-02 2008-12-01    False
2  878 2008-12-02 2010-04-03    False
3  879 2010-04-04 2199-05-10    False
4  879 2016-05-12 2199-12-31     True
5  880 2011-07-08 2013-03-03    False
6  880 2010-02-12 2015-05-05     True

【讨论】:

    猜你喜欢
    • 2019-11-23
    • 1970-01-01
    • 2019-01-30
    • 2019-01-19
    • 2015-09-13
    • 2018-12-30
    • 2014-10-03
    • 2016-10-23
    • 2017-09-13
    相关资源
    最近更新 更多