Python在不同的日期和日期范围内重新采样特定的小时数

Python在不同的日期和日期范围内重新采样特定的小时数,python,pandas,Python,Pandas,我有不同实体的数据记录,每个实体在一天中的某个特定时间内记录了整整一个月的计数。 例如: entity_id time counts 0 175 2019-03-01 05:00:00 3 1 175 2019-03-01 06:00:00 4 2 175 2019-03-01 07:00:00 6 3 175 2019-03-01 08:00:00 6 4

我有不同实体的数据记录,每个实体在一天中的某个特定时间内记录了整整一个月的计数。 例如:

     entity_id    time              counts
0      175  2019-03-01 05:00:00       3
1      175  2019-03-01 06:00:00       4
2      175  2019-03-01 07:00:00       6
3      175  2019-03-01 08:00:00       6
4      175  2019-03-01 09:00:00       7
5      178  2019-03-01 05:00:00       8
6      178  2019-03-01 06:00:00       4
7      178  2019-03-01 07:00:00       5
8      178  2019-03-01 08:00:00       6
9      200  2019-03-01 05:00:00       7
10     200  2019-03-01 08:00:00       3
11     175  2019-03-03 05:00:00       3
12     175  2019-03-03 07:00:00       6
13     175  2019-03-03 08:00:00       6
14     175  2019-03-03 09:00:00       7
15     178  2019-03-03 05:00:00       8
16     178  2019-03-03 06:00:00       4
17     178  2019-03-03 07:00:00       5
18     178  2019-03-03 08:00:00       6
19     200  2019-03-03 05:00:00       7
20     200  2019-03-03 08:00:00       3
21     200  2019-03-03 09:00:00       7
...
我希望能够为每个实体汇总整个月内一周中不同天数内几个小时范围内的计数平均值。例如:

  • 周日上午(6-10点)的平均值
  • 星期日和星期四上午(6-10点)的平均值
  • 周日至周四中午(上午11点至下午1点)的平均值
  • 周五至周六中午(上午11点至下午1点)的平均值
  • 周五晚上(下午6点至9点)的平均值
  • 等等
因此,我希望得到这样的df(部分示例):

我通过对数据进行迭代、切片和提取不同的元素来部分实现这一点,但我认为有一种更有效的方法


我开始的时候是,但是我仍然有太多的for循环。您知道如何优化性能吗?

如果您的时间列是pandas中的datetime对象,您可以使用datatime方法创建新列

您可以按照以下步骤操作

  • 您可以创建一个列,将周中的日表示为
  • df[“周中的天”]=df[“时间”].dt.dayofweek
    
  • 然后使用一个简单的.apply函数,根据您的需求制作列,通过比较函数中的时间,将时间划分为早上、晚上等时段

  • 然后根据之前创建的两列创建另一列,指示您的组合

  • 然后在要获取该组的分组数据或指标的列上使用groupby

  • 我知道这个过程有点长,但它没有任何for循环,它使用pandas已经提供的
    df.apply
    datetime
    属性,以及根据您的要求提供的一些if-else条件

    步骤2、3、4完全依赖于数据,因为我没有数据,所以无法编写准确的代码。我尽力解释可以使用的方法


    我希望这有帮助。

    如果您的时间列是pandas中的datetime对象,您可以使用datatime方法创建新列

    您可以按照以下步骤操作

  • 您可以创建一个列,将周中的日表示为
  • df[“周中的天”]=df[“时间”].dt.dayofweek
    
  • 然后使用一个简单的.apply函数,根据您的需求制作列,通过比较函数中的时间,将时间划分为早上、晚上等时段

  • 然后根据之前创建的两列创建另一列,指示您的组合

  • 然后在要获取该组的分组数据或指标的列上使用groupby

  • 我知道这个过程有点长,但它没有任何for循环,它使用pandas已经提供的
    df.apply
    datetime
    属性,以及根据您的要求提供的一些if-else条件

    步骤2、3、4完全依赖于数据,因为我没有数据,所以无法编写准确的代码。我尽力解释可以使用的方法


    我希望这能有所帮助。

    我的解决方案是基于一个带有定义的辅助数据框 要计算其平均值的范围(周中的天、日中的时间) 以及上述属性的相应CustomBusinessHour)

    这个数据框架(我称之为日历)的创建从 周中的日、日列中的时间:

    如果您想要更多这样的定义,请在此处添加它们

    然后,要添加相应的CustomBusinessHour对象:

  • 定义一个函数以获取小时限制:

    def getHourLimits(name):
        if name == 'morning':
            return '06:00', '10:00'
        elif name == 'noon':
            return '11:00', '13:00'
        elif name == 'eve':
            return '18:00', '21:00'
        else:
            return '8:00', '16:00'
    
  • 定义获取周掩码(开始时间和结束时间)的函数:

  • 定义生成CustomBusinessHour对象的函数:

  • 将CustomBusinessHour对象添加到日历:

  • 然后定义一个函数,用于计算给定 实体Id:

    def getSums(entId):
        outRows = []
        wrk = df[df.entity_id.eq(entId)]    # Filter for entity Id
        for _, row in calendars.iterrows():
            dd = row.day_in_week
            hh = row.time_in_day
            cbh = row.CBH
            # Filter for the current calendar
            cnts = wrk[wrk.time.apply(lambda val: cbh.is_on_offset(val))]
            cnt = cnts.counts.mean()
            if pd.notnull(cnt):
                outRows.append(pd.Series([entId, dd, hh, cnt],
                    index=['entity_id', 'day_in_week', 'time_in_day', 'counts_mean']))
        return pd.DataFrame(outRows)
    
    如您所见,结果只包含非空的平均值

    要生成结果,请运行:

    pd.concat([getSums(entId) for entId in df.entity_id.unique()], ignore_index=True)
    
    对于您的数据样本(仅包含早晨的读数), 结果是:

       entity_id day_in_week time_in_day  counts_mean
    0        175         sun     morning     6.333333
    1        175     sun-thu     morning     6.333333
    2        178         sun     morning     5.000000
    3        178     sun-thu     morning     5.000000
    4        200         sun     morning     5.000000
    5        200     sun-thu     morning     5.000000
    

    我的解决方案的思想是基于一个带有定义的辅助数据帧 要计算其平均值的范围(周中的天、日中的时间) 以及上述属性的相应CustomBusinessHour)

    这个数据框架(我称之为日历)的创建从 周中的日、日列中的时间:

    如果您想要更多这样的定义,请在此处添加它们

    然后,要添加相应的CustomBusinessHour对象:

  • 定义一个函数以获取小时限制:

    def getHourLimits(name):
        if name == 'morning':
            return '06:00', '10:00'
        elif name == 'noon':
            return '11:00', '13:00'
        elif name == 'eve':
            return '18:00', '21:00'
        else:
            return '8:00', '16:00'
    
  • 定义获取周掩码(开始时间和结束时间)的函数:

  • 定义生成CustomBusinessHour对象的函数:

  • 将CustomBusinessHour对象添加到日历:

  • 然后定义一个函数,用于计算给定 实体Id:

    def getSums(entId):
        outRows = []
        wrk = df[df.entity_id.eq(entId)]    # Filter for entity Id
        for _, row in calendars.iterrows():
            dd = row.day_in_week
            hh = row.time_in_day
            cbh = row.CBH
            # Filter for the current calendar
            cnts = wrk[wrk.time.apply(lambda val: cbh.is_on_offset(val))]
            cnt = cnts.counts.mean()
            if pd.notnull(cnt):
                outRows.append(pd.Series([entId, dd, hh, cnt],
                    index=['entity_id', 'day_in_week', 'time_in_day', 'counts_mean']))
        return pd.DataFrame(outRows)
    
    如您所见,结果只包含非空的平均值

    要生成结果,请运行:

    pd.concat([getSums(entId) for entId in df.entity_id.unique()], ignore_index=True)
    
    对于您的数据样本(仅包含早晨的读数), 结果是:

       entity_id day_in_week time_in_day  counts_mean
    0        175         sun     morning     6.333333
    1        175     sun-thu     morning     6.333333
    2        178         sun     morning     5.000000
    3        178     sun-thu     morning     5.000000
    4        200         sun     morning     5.000000
    5        200     sun-thu     morning     5.000000
    

    我会试一试:)如果我按照第3步做,那么我会得到一个列:“3_morning”“0_morning”等等。假设他们我想将这两行分为3次:第0天一次,第3天一次,两天一次-我如何在groupby中表达这一点?这会有帮助!我会试一试:)如果我按照第3步做,那么我会得到一个列:“3_morning”“0_morning”等等。假设他们我想将这两行分为3次:第0天一次,第3天一次,两天一次-我如何在groupby中表达这一点?这会有帮助!
       entity_id day_in_week time_in_day  counts_mean
    0        175         sun     morning     6.333333
    1        175     sun-thu     morning     6.333333
    2        178         sun     morning     5.000000
    3        178     sun-thu     morning     5.000000
    4        200         sun     morning     5.000000
    5        200     sun-thu     morning     5.000000