【问题标题】:How to clean up or smoothen a time series using two criteria in Pandas如何使用 Pandas 中的两个标准清理或平滑时间序列
【发布时间】:2021-04-03 00:19:40
【问题描述】:

对不起,令人困惑的标题。我正在尝试清理在不同时间间隔报告引擎小时数的数据集。我正在尝试检测和解决两种情况:

  1. 报告的发动机小时数少于上次记录的发动机小时数

  2. 两个日期之间报告的发动机小时数大于所述日期之间的小时差

    Sampled Date    Meter   eng_hours_diff  date_hours_diff
     2017-02-02     5336         24                24
     2017-02-20     5578         242               432
     2017-02-22     5625         47                48
     2017-03-07     5930         305               312
     2017-05-16     6968         1038              1680
     2017-06-01     7182         214               384
     2017-06-22     7527         345               504
     2017-07-10     7919         392               432
     2017-07-25     16391        8472              360
     2017-08-20     8590        -7801              624
     2017-09-05     8827         237               384
     2017-09-26     9106         279               504
     2017-10-16     9406         300               480
     2017-10-28     9660         254               288
     2017-11-29     10175        515               768
    

如果出现上述两种情况中的任何一种,我想做的是重新编写 ['Meter'] 系列并取其周围点之间的平均值。

我认为这可能需要两个步骤,一个是消除由于发动机小时数大于日期之间的小时数而导致的任何不准确性,然后重新计算 ['eng_hours_diff'] 列并检查是否还有一些是负面的。

我计算的最后两列是这样的:

dfa['eng_hours_diff'] = dfa['Meter'].diff().fillna(24)

dfa['date_hours_diff'] = dfa['Sampled Date'].diff().apply(lambda x:str(x)).apply(lambda x: x.split(' ')[0]).apply(lambda x:x.replace('NaT',"1")).apply(lambda x: int(x)*24)
    

编辑: 好的,我想我已经到了某个地方,但还没有到那里..

dfa['MeterReading'] = [x if y>0 & y<z else 0 for x,y,z in 
                       zip(dfa['Meter'],dfa['eng_hours_diff'], dfa['date_hours_diff'])]

编辑 2:

感谢比尔的回答,我离得更近了。

应用此函数将用零替换任何不符合条件的记录。然后我用 np.nan 替换这些零并使用 interpolate 方法。

我唯一缺少的是当它们也以 np.nan 形式出现时如何填写最后一个值,我正在寻找是否有外推方法。

这是一个功能,以防将来有人偶然发现类似的问题:

dfa['MeterReading'] = dfa['MeterReading'].replace({0:np.nan}).interpolate(method='polynomial', order=2, limit=5, limit_direction='both').bfill()

这是我最后遇到的问题。遗漏了两个值,但由于差值变为负数,它会丢弃所有 4 个值。

【问题讨论】:

  • 如果你用np.nan而不是零替换丢失的仪表读数,那么eng_hours_diff列也会产生nans而不是负值。制作一个单独的插值列,然后根据一些逻辑选择最终的填充值。
  • 对于最后的填充,与其尝试用多项式进行推断(可能导致预测不佳),不如保持滚动平均小时/天值(或者可能只是全球平均小时数)天使用带有ffill 方法选项的fillna),然后使用它来线性推断数据的末尾?
  • 滚动均值也不错,事实上我可以在整个系列中都这样做,因为我真正关心的是那个日期的大概时间,最重要的是我想要删除胖手指条目,如 1000000 小时或小于前一个的条目。也许我可以简单地做一个 ffill() 然后滚动平均值
  • 听起来不错。滚动平均值会很好,或者如果小时/天变化很大并且您想要更多响应过滤器,请查看exponentially-weighted moving average

标签: python pandas time-series


【解决方案1】:

您的代码的一个问题是逻辑条件没有按照我的想法进行。 y&gt;0 &amp; y&lt;z(y&gt;0) &amp; (y&lt;z) 不同(例如第一行)。

除此之外,通常有三种方法可以对 pandas Dataframe 中的行元素进行操作。

对于像您这样的操作可向量化的简单情况,您可以在没有 for 循环或列表理解的情况下执行它们:

dfa['MeterReading'] = dfa['Meter']
condition = (dfa['eng_hours_diff'] > 0) & (dfa['eng_hours_diff'] < dfa['date_hours_diff'])
dfa.loc[~condition, 'MeterReading'] = 0

对于更复杂的逻辑,您可以使用这样的 for 循环:

dfa['MeterReading'] = 0
for i, row in dfa.iterrows():
    if (row['eng_hours_diff'] > 0) & (row['eng_hours_diff'] < row['date_hours_diff']):
        dfa.loc[i, 'MeterReading'] = row['Meter']

或者,将apply 与自定义函数一起使用,例如:

def calc_meter_reading(row):
    if (row['eng_hours_diff'] > 0) & (row['eng_hours_diff'] < row['date_hours_diff']):
        return row['Meter']
    else:
        return 0

dfa['MeterReading'] = dfa.apply(calc_meter_reading, axis=1)

【讨论】:

  • 非常感谢您花时间整理这些内容。我已经使用 apply 方法尝试了最后一个,但我不想返回 0 我想返回前一个值和下一个值的平均值。我现在正在尝试使用 interpolate 函数,所以如果我让它工作,我会结合你的答案发布答案​​。再次感谢!
  • 对不起,我犯了一些错误,我刚刚修复了。
  • 是的,Series.interpolate 可能是填充缺失数据的好解决方案(以及用于基本填充操作的 fillna)。
猜你喜欢
  • 2020-07-12
  • 2016-07-03
  • 1970-01-01
  • 2018-04-01
  • 2013-09-18
  • 2020-08-11
  • 2011-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多