0

我在熊猫(python)中有一个数据框,它是来自具有时间索引的实验的测量变量。我希望提取出该值低于某个值的时间。然而,噪音有时会导致变量高于和低于阈值,所以我也只想在变量高于另一个阈值时找到一个新的时间点。到目前为止我写的代码是:

def findPriming(df,col,sphigh,splow):
    #start the counter and the pastPrime detector
    i = 1 # this ignores the first value but lets us check with the one before with no errors.
    currentlyPriming = False
    primeTimes = []
        #Right iteratre through the series here:
    while i < range(len(df)):
        # If the value is above 20, everything is fine and its not priming
        if df[col].iloc[i] > sphigh:
            currentlyPriming = False

        #If its below 16:
        elif df[col].iloc[i] < splow:
            #Check if we are currently priming:
            if not currentlyPriming:
                # We are now priming and haven't been before. So let's log it
                primeTimes.append(df.index[i])
            # Now we are priming we need to set the flag!
            currentlyPriming = True
        # Nowincrement the counter
        i += 1  # Increment counter

    return primeTimes

但我可以想象这是非常低效的(而且它需要永远运行的事实会告诉我同样的事情)。

我试图考虑如何删除这两个 if 的每个数据点,但无法使其正常工作。

有人对改进有任何想法吗?我试图搜索类似的代码,但似乎找不到任何东西。

编辑以包含我的数据框的示例:

DateTime                      Data
2013-08-08 15:46:41           25.203461
2013-08-08 15:46:51           23.241514
2013-08-08 15:47:01           22.256216
2013-08-08 15:47:11           21.256216
2013-08-08 15:47:21           16.261763
2013-08-08 15:47:31           13.249237
2013-08-08 15:47:41           17.249237
2013-08-08 15:47:51           18.238962
2013-08-08 15:48:01           13.207640
2013-08-08 15:48:11           20.207640

以及我(严重)绘制的示例图的链接 [inlined --ed]

示例图像

4

2 回答 2

4

IIUC 你的情况是正确的,你想找到你低于 16 岁的时间,但前提是它是在 20 岁以下的同一时期的新下降。我可以想到几种方法来做到这一点。有些比下面的要短一些,但这个技巧很有用,适用于许多问题,所以值得了解。

groupby+ cumsum.

基本思想是用于groupby将时间分组为上线以下的时间集群。不幸的是,出于我们的目的groupby,将组合不连续的组,但我们可以通过使用cumsum. (也许groupby应该增加一个contiguous=True/False默认的标志False以使这更容易..)

如果您将时间作为开始的索引,那么

df = df.reset_index()
upper_limit = 20
lower_limit = 16
above_upper_line = df.Data > upper_limit
upper_line_crossed = above_upper_line != above_upper_line.shift()
clusters = upper_line_crossed.cumsum()
below_lower_line = df.Data < lower_limit

times = df[below_lower_line].groupby(clusters)["DateTime"].first().tolist()

生产

>>> times
array(['2013-08-08T11:47:31.000000000-0400'], dtype='datetime64[ns]')

[以后有机会我会试着写一个解释。]

于 2013-11-11T18:28:59.943 回答
1

编辑: 使用您包含的图表,下面的解决方案过于简单。我将把它留在下面,因为我想它将成为更完整方法的一个组成部分。

您不需要任何循环来执行此操作。您可以只使用布尔(逻辑)索引。您的示例没有运行(我们没有您的任何数据),所以这是一个玩具示例:

In [1]: import numpy as np

In [2]: import pandas

In [3]: dateindex = pandas.DatetimeIndex(freq='10T', start='2013-11-11 06:30', end='2013-11-11 12:30')

In [4]: df = pandas.DataFrame(np.random.normal(size=(len(dateindex),3)), columns=list('ABC'), index=dateindex)

In [5]: df.head()
Out[5]: 
                            A         B         C
2013-11-11 06:30:00  0.958990  0.234201  0.216744
2013-11-11 06:40:00 -2.173221  0.232468  0.696578
2013-11-11 06:50:00 -0.089300  2.081265 -0.482739
2013-11-11 07:00:00 -0.621272  0.226189  1.025683
2013-11-11 07:10:00  1.091428 -0.097205 -0.570189

In [6]: df[df['A'] < -1.0].index.tolist()
Out[6]: 
[Timestamp('2013-11-11 06:40:00', tz=None),
 Timestamp('2013-11-11 09:20:00', tz=None),
 Timestamp('2013-11-11 09:30:00', tz=None),
 Timestamp('2013-11-11 10:40:00', tz=None),
 Timestamp('2013-11-11 11:00:00', tz=None),
 Timestamp('2013-11-11 12:20:00', tz=None)]

在这种情况下,我只是使用随机数据来-1.0代替splow您示例中的位置。还'A'映射到col您的函数中。

于 2013-11-11T16:38:42.920 回答