【问题标题】:Python: Filter DataFrame in Pandas by hour, day and month grouped by yearPython:按年分组的小时、日和月过滤 Pandas 中的 DataFrame
【发布时间】:2017-02-28 06:51:28
【问题描述】:

作为 Pandas 的新手,我必须进行大量研究才能找到解决此问题的方法。考虑到我仍然需要解决边界问题,我想知道一个更好的方法来解决这个问题。

我有一组从 2009 年到 2012 年的 10 分钟“功率”度量,并希望获得所有年份的小时和日/月窗口(即按年分组的小时、日和月过滤)。

我得出的结论如下:

import pandas as pd
import numpy as np
import datetime

dates = pd.date_range(start="08/01/2009",end="08/01/2012",freq="10min")
df = pd.DataFrame(np.random.rand(len(dates), 1)*1500, index=dates, columns=['Power'])

def filter(df, day, month, hour, daysWindow, hoursWindow):
    """
    Filter a Dataframe by a date window and hour window grouped by years

    @type df: DataFrame
    @param df: DataFrame with dates and values

    @type day: int
    @param day: Day to focus on

    @type month: int
    @param month: Month to focus on

    @type hour: int
    @param hour: Hour to focus on

    @type daysWindow: int
    @param daysWindow: Number of days to perform the days window selection

    @type hourWindow: int
    @param hourWindow: Number of hours to perform the hours window selection

    @rtype: DataFrame
    @return: Returns a DataFrame with the
    """
    df_filtered = None
    grouped = df.groupby(lambda x : x.year)
    for year, groupYear in grouped:
        groupedMonthDay = groupYear.groupby(lambda x : (x.month, x.day))
        for monthDay, groupMonthDay in groupedMonthDay:
            if monthDay >= (month,day - daysWindow) and monthDay <= (month,day + daysWindow):
                new_df = groupMonthDay.ix[groupMonthDay.index.indexer_between_time(datetime.time(hour - hoursWindow), datetime.time(hour + hoursWindow))]
                if df_filtered is None:
                    df_filtered = new_df
                else:
                    df_filtered = df_filtered.append(new_df)
    return df_filtered

df_filtered = filter(df,day=8, month=10, hour=8, daysWindow=1, hoursWindow=1)
print len(df)
print len(df_filtered)

作为输出返回:

>>> 
157825
117

当然,在选择像 1 和 hoursWindow 2 这样的小时时,此代码需要对边框问题进行改进。即:

>>> filter(df,day=8, month=10, hour=1, daysWindow=1, hoursWindow=2)
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
  File "D:\tmp\test_filtro.py", line 40, in filter
    new_df = groupMonthDay.ix[groupMonthDay.index.indexer_between_time(datetime.time(hour - hoursWindow), datetime.time(hour + hoursWindow))]
ValueError: hour must be in 0..23

选择像 1 或 30 这样的一天时会发生类似的问题。

如何改进这段代码?

【问题讨论】:

    标签: python datetime pandas dataframe


    【解决方案1】:

    filter 函数的更新代码确保没有边框问题:

    import pandas as pd
    import numpy as np
    import datetime
    
    dates = pd.date_range(start="08/01/2009",end="08/01/2012",freq="10min")
    df = pd.DataFrame(np.random.rand(len(dates), 1)*1500, index=dates, columns=['Power'])
    
    def filter(df, day, month, hour, minute=0, daysWindow=1, hoursWindow=1):
        """
        Filter a Dataframe by a date window and hour window grouped by years
    
        @type df: DataFrame
        @param df: DataFrame with dates and values
    
        @type day: int
        @param day: Day to focus on
    
        @type month: int
        @param month: Month to focus on
    
        @type hour: int
        @param hour: Hour to focus on
    
        @type daysWindow: int
        @param daysWindow: Number of days to perform the days window selection
    
        @type hoursWindow: int
        @param hourWindow: Number of hours to perform the hours window selection
    
        @rtype: DataFrame
        @return: Returns a DataFrame with the
        """
        df_filtered = None
        grouped = df.groupby(lambda x : x.year)
        for year, groupYear in grouped:
            date = datetime.date(year, month, day)
            dateStart = date - datetime.timedelta(days=daysWindow)
            dateEnd = date + datetime.timedelta(days=daysWindow+1)
            df_filtered_days = df[dateStart:dateEnd]
            timeStart = datetime.time(0 if hour-hoursWindow < 0 else hour-hoursWindow, minute)
            timeEnd = datetime.time(23 if hour+hoursWindow > 23 else hour+hoursWindow, minute)
            new_df = df_filtered_days.ix[df_filtered_days.index.indexer_between_time(timeStart, timeEnd)]
            if df_filtered is None:
                df_filtered = new_df
            else:
                df_filtered = df_filtered.append(new_df)
        return df_filtered
    
    df_filtered = filter(df,day=8, month=10, hour=1, daysWindow=1, hoursWindow=2)
    print len(df)
    print len(df_filtered)
    

    输出是:

    >>> 
    157825
    174
    

    【讨论】:

      猜你喜欢
      • 2018-09-04
      • 1970-01-01
      • 2014-03-12
      • 1970-01-01
      • 2021-10-16
      • 1970-01-01
      • 2015-01-24
      相关资源
      最近更新 更多