Pandas Dataframe中的高级间隔切片

时间:2014-09-10 02:41:55

标签: python pandas time-series dataframe subset

我需要从一个用Freq:120T索引的数据帧中切出几个间隔。每个所需间隔的开始日期由用Freq:None索引的第二个数据帧给出。我的想法是,我需要考虑每个开始日期,并包括构建每个间隔的时间和周期数。所有时间间隔的时间属性和时间段都相同。

让我们看看这个混乱的例子

假设我们的开始时间是'18:00:00',我们的周期数是3.要切片的数据帧是df1,包含开始日期的数据帧是df2。

df1

                      A   B     
DateTime                                               
2005-09-06 16:00:00   1   5  
2005-09-06 18:00:00   2   6  
2005-09-06 20:00:00   3   7  
2005-09-06 22:00:00   4   8 
2005-12-07 16:00:00   9   8  
2005-12-07 18:00:00   7   6  
2005-12-07 20:00:00   5   4  
2005-12-07 22:00:00   3   2  

<class 'pandas.tseries.index.DatetimeIndex'>
[2005-09-06 16:00:00, ..., 2005-12-07 22:00:00]
Length: 8, Freq: 120T, Timezone: None

df2

             Num
DateTime                                                                    
2005-09-07     1
2005-12-07     2

<class 'pandas.tseries.index.DatetimeIndex'>
[2005-09-07, 2005-12-07]
Length: 2, Freq: None, Timezone: None

期望的输出:

df3 = func(source=df1['B'], start_dates=df2.index, time_start='18:00:00', periods=3)

           1   2
18:00:00   6   6  
20:00:00   7   4  
22:00:00   8   2 

我做了什么和考虑因素:

其中一个困难是df1中的数据频率为120T,但仅为工作日。考虑到这一点,我会做这样的事情:

start = df2.index[0]   ##  And somehow add to this formula the fact that we want to start at         
                           '18:00'
df3 = df1['B'][(df1.index > start) & (df1.index < start + 3)]  ##  Somehow iterate this over the 
                                                                   dates in the df2 index

我感谢任何见解

提前致谢

2 个答案:

答案 0 :(得分:2)

您正在寻找pivot ...至少在您提取了您感兴趣的行后。

同一天,请使用normalizeisin

In [11]: res = df.loc[df.index.normalize().isin(df2.index), 'B']

In [12]: res
Out[12]:
2005-09-06 16:00:00    5
2005-09-06 18:00:00    6
2005-09-06 20:00:00    7
2005-09-06 22:00:00    8
2005-12-07 16:00:00    8
2005-12-07 18:00:00    6
2005-12-07 20:00:00    4
2005-12-07 22:00:00    2
Name: B, dtype: int64

一旦它以该形式转移(如果可能缺少数据,您可能必须使用pivot_table,这会更灵活一点)!

In [14]: pd.pivot(res.index.time, res.index.normalize(), res.values)
Out[14]:
          2005-09-06  2005-12-07
16:00:00           5           8
18:00:00           6           6
20:00:00           7           4
22:00:00           8           2

&#34;肉&#34;使用isin进行行选择,检查标准化为午夜的时间是否包含在df2.index中。

df.index.normalize().isin(df2.index)

如果我们也关心时间,我们可以使用indexer_between_time

In [15]: df.ix[df.index.indexer_between_time('18:00', '00:00'), 'B']
Out[15]:
2005-09-06 18:00:00    6
2005-09-06 20:00:00    7
2005-09-06 22:00:00    8
2005-12-07 18:00:00    6
2005-12-07 20:00:00    4
2005-12-07 22:00:00    2
Name: B, dtype: int64

好的,在这个例子中它们是相同的(因为只有我们想要的日期!),但一般来说你真的想要这两个条件(到&#34;和&#34;它们)...

# I had tried to make this a one-liner but utterly failed!
in_time = np.zeros(len(df), dtype=bool)
in_time[df.index.indexer_between_time('18:00', '00:00')] = True
res = df.loc[df.index.normalize().isin(df2.index) & in_time, 'B']

In [17]: res
Out[17]:
2005-09-06 16:00:00    5
2005-09-06 18:00:00    6
2005-09-06 20:00:00    7
2005-09-06 22:00:00    8
2005-12-07 16:00:00    8
2005-12-07 18:00:00    6
Name: B, dtype: int64

您可以映射透视结果的列:

In [21]: pv = pd.pivot(res.index.time, res.index.normalize(), res.values)

In [22]: pv
Out[22]:
          2005-09-06  2005-12-07
18:00:00           6           6
20:00:00           7           4
22:00:00           8           2

In [23]: pv.columns = pv.columns.map(df2.Num.get)

In [24]: pv
Out[24]:
          1  2
18:00:00  6  6
20:00:00  7  4
22:00:00  8  2

瞧。

答案 1 :(得分:1)

完全不同的方法:

def next_n_asof(x, t, n):
    """The next n rows after time t in x
    """
    i = np.argmax(df.index >= t)
    return x[i:i + n]

In [11]: next_n_asof(df.B, pd.Timestamp('2005-09-06 18:00:00'), 3)
Out[11]:
2005-09-06 18:00:00    6
2005-09-06 20:00:00    7
2005-09-06 22:00:00    8
Name: B, dtype: int64

我们可以在索引中的每一天的concat中使用它:

In [12]: pd.concat(next_n_asof(df.B, t, 3)
                   for t in df2.index + pd.tseries.timedeltas.to_timedelta(18, unit='h'))
Out[12]:
2005-09-06 18:00:00    6
2005-09-06 20:00:00    7
2005-09-06 22:00:00    8
2005-12-07 18:00:00    6
2005-12-07 20:00:00    4
2005-12-07 22:00:00    2
Name: B, dtype: int64

我们必须在df2.index中添加时间:

In [13]: df2.index + pd.tseries.timedeltas.to_timedelta(18, unit='h')
Out[13]:
<class 'pandas.tseries.index.DatetimeIndex'>
[2005-09-06 18:00:00, 2005-12-07 18:00:00]
Length: 2, Freq: None, Timezone: None

注意:我无法让自己干净利落地工作......这可能会更有效率。