python - 如何根据多个条件对 Pandas 中的时间序列数据帧进行切片?

标签 python pandas time-series dataframe subset

我需要根据这两个条件获取时间序列数据帧的切片:

  1. 每个切片的开始日期可在第二个数据帧索引中找到。
  2. 每个切片的开始时间和切片的长度是函数的参数。

让我们看一个例子

df1 - 这是我们从中获取切片的地方

                     A  B      
DateTime                                               
2011-01-02 00:00:00  1  2  
2011-01-02 04:00:00  2  4    
2011-01-02 08:00:00  3  5      
2011-01-02 12:00:00  2  6   
2011-01-02 16:00:00  5  6
2011-01-02 20:00:00  2  1
2011-01-03 00:00:00  5  2 
2011-01-03 04:00:00  3  3
2011-01-03 08:00:00  2  2
2011-01-03 12:00:00  0  4
2011-01-03 16:00:00  5  4
2011-01-03 20:00:00  1  1

<class 'pandas.tseries.index.DatetimeIndex'>
[2011-01-02 00:00:00, ..., 2011-01-03 20:00:00]
Length: 12, Freq: 240T, Timezone: None

df2 - 这是切片开始的日期部分所在的位置。

                     N  
DateTime                                                                  
2011-01-10 00:00:00  1  
2011-03-10 00:00:00  2

<class 'pandas.tseries.index.DatetimeIndex'>
[2011-01-02, ..., 2011-01-03]
Length: 2, Freq: None, Timezone: None

假设我们想要以 length=4 为间隔对 df1['A'] 进行切片,每个间隔在时间 '04:00 开始: 00',在 df2 的每个日期......所需的输出示例为:

func(df1['A'], df2, lenght=4, start_time='04:00')

                     A    
DateTime                                                 
2011-01-02 04:00:00  2   
2011-01-02 08:00:00  3    
2011-01-02 12:00:00  2   
2011-01-02 16:00:00  5     
2011-01-03 04:00:00  3   
2011-01-03 08:00:00  2   
2011-01-03 12:00:00  0   
2011-01-03 16:00:00  5   

需要考虑的事情:

  • df1 的频率不必始终为“240T”
  • df2 中的日期不需要连续,为了示例简单起见,我只是这样设置。
  • 并非 df1 上的所有日期都在 df2 上,但 df2 上的所有日期都在 df1 上
  • df2中的N列可以忽略
  • df2 freq 属性始终为“None”
  • 切片的长度可以是任意长度,因此可以是多天。

我尝试过什么:

在此处的一些帮助下,我尝试了这种方法,但只有当两个 df 的频率均为“无”时才能正常工作。

def next_n_asof(x, t, n):
    i = np.argmax(df1.index >= t)
    return x[i:i + n]

pd.concat(next_n_asof(df1.A, t, 4)
               for t in df2.index)

提前致谢

最佳答案

next_n_asof 进行很小的更改即可产生所需的结果。如果代替

i = np.argmax(df1.index >= t)

你使用

i = np.argmax(df1.index > t)

然后你的代码会产生

2011-01-02 04:00:00    2
2011-01-02 08:00:00    3
2011-01-02 12:00:00    2
2011-01-02 16:00:00    5
2011-01-03 04:00:00    3
2011-01-03 08:00:00    2
2011-01-03 12:00:00    0
2011-01-03 16:00:00    5
Name: A, dtype: int64

也许我误解了这个问题,因为这看起来太简单了。


尽管如此,这里有一个可能更快的替代方案: 请注意,此代码使用 for 循环len(df2.index) 迭代

pd.concat(next_n_asof(df1.A, t, 4) for t in df2.index)

你可以使用

start = df1.index.get_indexer_for(df2.index)

查找 df2.index 中的时间戳等于 df1.index 中的时间戳的索引。例如,

In [93]: df1.index.get_indexer_for(df2.index)
Out[93]: array([0, 6])

使用 DatetimeIndex 的 get_indexer_for 方法比使用此列表理解更快:

In [101]: [np.argmax(df1.index >= t) for t in df2.index]
Out[101]: [0, 6]

In [103]: %timeit [np.argmax(df1.index >= t) for t in df2.index]
10000 loops, best of 3: 85.5 µs per loop

In [104]: %timeit df1.index.get_indexer_for(df2.index)
100000 loops, best of 3: 14.5 µs per loop

从这里开始,不难为 df1 中您想要选择的行创建所有所需索引的 bool 掩码:

mask = np.zeros(len(df), dtype='bool')
for i in range(length):
    mask[start+i] = True

然后您可以使用

df1中选择所需的行
df1.loc[mask]

而不是创建(可能)许多较小的 DataFrame,然后 使用 pd.concat 连接它们,如果有很多子 DataFrame,则速度会更慢。

因此,这种替代方法将 for 循环len(df2.index) 迭代进行交换 对于具有 n=4 迭代的 for-loop (在您提出的示例问题中)。如果 df2 是 大但 n 小,这种替代方法应该更快。


import numpy as np
import pandas as pd

df1 = pd.DataFrame({'A': [1, 2, 3, 2, 5, 2, 5, 3, 2, 0, 5, 1],
                    'B': [2, 4, 5, 6, 6, 1, 2, 3, 2, 4, 4, 1]},
                   index=pd.date_range('2011-1-2', '2011-01-03 20:00', freq='240T'))

df2 = pd.DataFrame({'N': 1}, index=pd.date_range('2011-1-2', '2011-01-03'))

def next_n_asof(x, t, n):
    i = np.argmax(df1.index > t)
    return x[i:i + n]

print(pd.concat(next_n_asof(df1.A, t, 4)
               for t in df2.index))


def func(df, index, length):
    start = df.index.get_indexer_for(index)
    mask = np.zeros(len(df), dtype='bool')
    for i in range(length):
        mask[start+i] = True
    return df.loc[mask]

index = df2.index + pd.DateOffset(hour=4)
print(func(df1['A'], index, length=4))

产量

2011-01-02 04:00:00    2
2011-01-02 08:00:00    3
2011-01-02 12:00:00    2
2011-01-02 16:00:00    5
2011-01-03 04:00:00    3
2011-01-03 08:00:00    2
2011-01-03 12:00:00    0
2011-01-03 16:00:00    5
Name: A, dtype: int64

关于python - 如何根据多个条件对 Pandas 中的时间序列数据帧进行切片?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25854977/

相关文章:

python list.sort() 与 list.sort(key=itemgetter(0))

R:如何通过前一天的信息改变证券交易所日指数时间序列的缺口(假期)?

python - 如何将从 csv 文件导入 python 的数据转换为时间序列?

python - 与日期时间索引上的日期/时间进行区间比较(检查一个小时是否在两个时间段之间)

Python:滑动窗口均值,忽略缺失数据

python - 如何使用 FastAPI + uvicorn 在工作人员之间共享数据库连接?

javascript - 将 python `time` 对象返回到前端?

python - Bokeh 日期范围 slider

python - 根据条目从 pandas.Dataframe 中删除行

python - 基于索引对DataFrame进行分箱