【问题标题】:Filtering a datetime column过滤日期时间列
【发布时间】:2021-02-11 08:51:03
【问题描述】:

我有一个包含两列的数据框:DateTime 和 x。

DateTime = [‘2005-10-02’,’2005-10-03’,’2005-10-04, ‘2005-10-15’,’2005-10-16’,’2006-11-04’, ’2006-11-05’, ’2006-11-06’, ’2010-01-21’, ’2010-01-22’, ’2010-01-23’, ’2010-01-25’]

x = [20,29,31,22,25,25,21,29,28,22,21,26]

我想在第一次 x >= 25 时创建一个仅包含这些日期和 x 的新数据框,然后选择下一个日期,使两个日期之间的差异最小为 150 天。所以结果看起来像:

DateTime = [‘2005-10-03’,’2006-11-04’,’2010-01-21’]
x = [29,25,28]

感谢您的帮助。

【问题讨论】:

    标签: python datetime filtering


    【解决方案1】:

    下面的代码是一个执行基于列的过滤的函数示例:

    def filter_cols(x, DateTime):
        from datetime import datetime
    
        # dt1, dt2 are tuples of the form (int, <datetime.datetime object>) 
        # checks if the difference, in days, 
        # between two datetime objects is at least equal to 'days'
        cond = lambda dt1, dt2, days=150: abs((dt1[1] - dt2[1]).days) >= days
    
        def filt(it, li=[]):
            try:
                if not li:
                    li.append(next((xi, di) for xi, di in it if xi >= 25))
                li.append(next(df for df in it if cond(li[-1], df) and df[0] >= 25))
                filt(it, li)
            except StopIteration:
                pass
            finally:
                return li
    
        # preprocessing step
        # parse DateTime elements into datetime objects
        dt = list(map(lambda s: datetime.strptime(s, '%Y-%m-%d'), DateTime))
    
        # main step        
        # call filtering function
        li_tup = filt(zip(x, dt))
    
        # if li_tup is empty return two empty lists
        if not li_tup:
            return [], []
    
        # postprocessing step
        # split the list of tuples into two tuples
        x_filt, dt_filt = zip(*li_tup)
    
        # format dates back to their string representation
        dt_filt = list(map(lambda dt: dt.strftime('%Y-%m-%d'), dt_filt))    
        
        return list(x_filt), dt_filt
    

    请记住,函数可以写得更密集,但为了清楚起见,步骤被分解了。

    虽然没有明确说明,但我假设您的 DateTime 列表 是按时间升序排列的。

    做了这个假设,上面例子背后的主要思想 是首先将DateTime 列表解析为一个对象 可以操作日期数据并提供天差功能。
    这是通过使用内置的datetime 模块实现的,但您可以使用最适合您的任何方式。 map() 函数将datetime 类的strptime() 类方法应用于DateTime,以便将字符串元素解析为上述日期时间对象,并返回一个转换为列表的迭代器。

    filt(it, li: list=[]) 函数接受一个迭代器和一个默认为空列表但可以初始化的参数,应该是必需的。该列表包含有效的 xDateTime 元素对的元组,例如[(29, datetime.datetime(2005, 10, 3, 0, 0)), (25, datetime.datetime(2006, 11, 4, 0, 0))]

    li 为空列表时,filt() 内的以下块附加第一个xDatetime 到列表的元组,这样x 至少等于25

     if not li:
        li.append(next((xi, di) for xi, di in it if xi >= 25))
    

    为了过滤DateTime 列,迭代将继续,直到找到满足问题陈述中设置的条件的 x 对元组为止。如果 li 的最后一个元组中的 datatime 对象与迭代器产生的当前元组中的 datetime 对象之间的差异至少有 150 天,则实用函数 cond(li[-1], df) 返回 True。另一个条件是 x(df[0],当前元组的第一个元素)必须至少再次等于 25。这是我的假设,因为问题陈述中没有明确说明如果其对应的x 小于25,则是否允许满足日期差异条件的一对。如果是这种情况,请随意省略第二个条件df[0] &gt;= 25

    next(df for df in it if cond(li[-1], df) and df[0] >= 25)
    

    cond = lambda dt1, dt2, days=150: abs((dt1[1] - dt2[1]).days) >= days
    

    两个对象之间的天数差异存储在日期时间的days 属性中。

    然后函数在next 有效元组附加到li 后递归调用自身。 当it 迭代器被消耗时递归结束,引发StopIteration 异常。

    后处理步骤,通过解开filt() 的输出然后调用zip(),将元组列表转换为两个元组。

    x_filt, dt_filt = zip(*li_tup)
    

    另外一步,将过滤后的datetime 对象列表格式化回字符串。

    filter_cols() 函数返回两个过滤列。

    示例运行:

     >>> filter_cols(x, DateTime)
         ([29, 25, 28], ['2005-10-03', '2006-11-04', '2010-01-21'])
    

    【讨论】:

    • 添加了几行来检查 li_tup 是否为空,当 x 中没有元素满足至少等于 25 的条件时会发生边缘情况。如果是这种情况,则两个为空返回列表。
    • 谢谢你的详细解释。感谢您的帮助。
    • 不客气,如果答案解决了您的问题,也许您可​​以考虑接受它,因为这可能也有助于其他有类似问题的人。
    猜你喜欢
    • 2013-10-20
    • 1970-01-01
    • 1970-01-01
    • 2018-01-25
    • 2020-12-29
    • 2021-09-01
    • 2021-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多