【问题标题】:How to cut unsorted time-series data into bins with a minimum interval?如何以最小间隔将未排序的时间序列数据切割成箱?
【发布时间】:2019-09-28 19:12:20
【问题描述】:

我有一个这样的数据框

x = pd.DataFrame({'a':[1.1341, 1.13421, 1.13433, 1.13412, 1.13435, 1.13447, 1.13459, 1.13452, 1.13471, 1.1348, 1.13496,1.13474,1.13483,1.1349,1.13502,1.13515,1.13526,1.13512]})

我们如何拆分这个系列以获得以下输出,使得最小差异至少为 0.0005

x['output'] =  [1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0]

【问题讨论】:

  • “我们如何拆分这个系列以获得以下输出,使得最小差异至少为 0.0005”:差异是什么?在子系列的任意两个数字之间?
  • 计算效率对您的情况重要吗?另外,数据的特点是什么? (可能有几个满足条件的子列表,例如,如果您的列表是 (1, 1.0001, 2, 2.0001)
  • 效率很重要。我想将此应用于 1M 行。子集应该在原始列表中。在这种情况下,答案应该是 [1.1341,1.13471,1.13526],因为 1.1341 - 1.13471 = 0.00061 和 1.13471 - 1.13526 = 0.00055。差异不一定总是积极的。
  • 1.13512 - 1.13483 ?
  • 我不清楚为什么 1.13410 有 1?这是因为 1.3410 - 1.3421 > 0.0005?

标签: python pandas time-series


【解决方案1】:

我不相信有一种矢量化的方法可以做到这一点,所以你可能需要循环遍历这些值。

x = x.assign(output=0)  # Initialize all the output values to zero.
x['output'].iat[0] = 1
threshold = 0.0005
prior_val = x['a'].iat[0]
for n, val in enumerate(x['a']):
    if abs(val - prior_val) >= threshold:
        x['output'].iat[n] = 1
        prior_val = val  # Reset to new value found that exceeds threshold.

【讨论】:

  • 我是这么认为的,但正在寻找确认。
  • @Alexander 如果您使用 x = pd.DataFrame({'a':[1.00001, 1.2, 1.00001]}) 运行它,您将选择所有三个数字,即使两个数字相同.或者也许我误解了(因此编辑错误)了这个问题?
  • @Gabriel 我刚刚回滚了那个编辑。我不相信这是 OP 的意图,因为人们可以通过在期望的结果中观察给定的output 来推断。
【解决方案2】:

这是我对矢量化和递归函数的最大尝试。

递归函数构建一个单行数据帧发送给调用者并在主函数末尾连接。

它使用 0.24 版本中添加到 pandas 的可空整数类型。

编辑:此解决方案比带循环的解决方案慢十倍。你不应该使用它。

import pandas as pd


def find_next_step(df, initial_value, threshold):
    try:
        following_index = (
            df.loc[lambda x: (x['a'] - initial_value).abs() >= threshold]
            .loc[:, 'a']
            .index[0]
        )
    except IndexError:
        return []
    to_append = find_next_step(
        df.loc[following_index + 1:, :], x.loc[following_index, 'a'], threshold
    )
    to_append.append(
        pd.DataFrame({'output': [1]}, index=[following_index], dtype=pd.Int64Dtype())
    )
    return to_append


if __name__ == '__main__':
    x = pd.DataFrame({'a':[1.1341, 1.13421, 1.13433, 1.13412, 1.13435, 1.13447, 1.13459, 1.13452, 1.13471, 1.1348, 1.13496,1.13474,1.13483,1.1349,1.13502,1.13515,1.13526,1.13512]})
    output_list = find_next_step(x.iloc[1:, :], x.loc[:, 'a'].iloc[0], 0.0005)
    output_list.append(pd.DataFrame({'output': [1]}, index=[0], dtype=pd.Int64Dtype()))
    output_series = pd.concat(
        [x, pd.concat(output_list).sort_index()], axis='columns'
    ).assign(output=lambda x: x['output'].fillna(0))

它适用于您的示例,打印:

          a  output
0   1.13410       1
1   1.13421       0
2   1.13433       0
3   1.13412       0
4   1.13435       0
5   1.13447       0
6   1.13459       0
7   1.13452       0
8   1.13471       1
9   1.13480       0
10  1.13496       0
11  1.13474       0
12  1.13483       0
13  1.13490       0
14  1.13502       0
15  1.13515       0
16  1.13526       1
17  1.13512       0

【讨论】:

  • 我尝试在更大的数据帧上运行它来测试时序,但达到了最大递归深度。此解决方案比简单的循环慢很多
  • 我应该测试一下时间。它慢了 10 倍。 :-( 我编辑我的帖子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-07
  • 2021-05-10
  • 1970-01-01
  • 2012-04-07
  • 1970-01-01
相关资源
最近更新 更多