我需要根据这两个条件获取时间序列数据帧的切片:
- 每个切片的开始日期可在第二个数据帧索引中找到。
- 每个切片的开始时间和切片的长度是函数的参数。
让我们看一个例子
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/