在 Pandas 中,使用 Groupby 根据列中的值选择连续行的 DataFrame。

4

我有五年的S&P 500数据,我想将其分组成特定的时间段以进行一些分析。我的数据按5分钟为增量。在将其读入名为dated的DataFrame后,我认为可以通过每个交易日Globex开放和关闭之间的时间增量,将其分组为包括连续行的块。Globex开放时间是太平洋标准时间下午3:00(15:00),关闭时间是下午1:15(13:15),22.25小时后。因此,我想将数据从下午3:00开放到下午1:15关闭--这大约是每个块275行。

困难在于,“交易日”跨越2个不同的日期,例如,一个会话在2016年3月6日星期日15:00开始,2016年3月7日星期一13:15结束。我不能按“日期”列分组,因为当然所有3-6都在一个块中,3-7在另一个块中,但我需要数据块跨越两个日期,以便在一个块中获取整个Globex日。

作为相对较新的Pandas和Python使用者,我不知道要使用什么方法来将数据分组为所需的块。一旦数据被分离,我想将每个会话/块的高点和低点分别提取到单独的列中,并提取一个只包含15:05开盘价的列。

这是我的数据样本:

    Date    Time    Open    High    Low Close   Up  Down
0   2015-08-03  15:05   2073.50 2074.00 2073.25 2073.25 210 563
1   2015-08-03  15:10   2073.25 2073.25 2072.25 2072.75 118 632
2   2015-08-03  15:15   2072.75 2072.75 2072.25 2072.50 132 85
3   2015-08-03  15:20   2072.50 2072.75 2072.25 2072.50 95  312
4   2015-08-03  15:25   2072.50 2074.00 2072.50 2073.50 372 264

原来,“日期”列的值如下:8/3/2015。我认为它可能无法被读取为实际的日期对象,因此我使用to_datetime()更改了这些值,以便“日期”列的值看起来像实际的日期对象,就像我的示例DataFrame中显示的那样。

dated['Date'] =pd.to_datetime(dated['Date'])

当我试图使用to_datetime()更改“时间”列中的值时,它成功地将时间从15:05更改为15:05:00,但它还添加了日期,因此看起来像这样:“2016-03-05 15:05:00”,问题在于它使用今天的日期。显然,这对我不起作用,因为我的数据是历史性的,日期和时间是历史价格的参考。
我尝试将“时间”列更改为datetime对象的原因是我认为我将能够在groupby操作期间将其切成所需的块:
dated = dated['Date'].groupby(dated['15:05' : '13:20'])  

这导致了一个错误:

IndexError: invalid slice

我希望您能帮助我解决这个问题,指向正确的研究方向。这个问题与IT技术有关。我一直在逐字逐句地阅读pandas文档,尝试着使用不同的方法,但是由于不确定应该从哪些步骤开始,我随机选择了一些话题去阅读,但是并没有找到答案。

谢谢, 安娜

2个回答

2

这实际上非常复杂。

首先,您可以按以下方式转换时间:

df['Datetime'] = pd.to_datetime(df.Date + ' ' + df.Time)

在这里,我将创建一个更大的数据框:

np.random.seed(0)
idx = pd.date_range('2015-1-1', '2016-1-1', freq='5min')
df = pd.DataFrame(np.random.randn(len(idx), 6),    
                  columns=['Open', 'High', 'Low', 'Close', 'Up', 'Down'])
df['Datetime'] = idx

让我们添加一个布尔标志来指示市场何时开放。

# Create a market open flag.
df['market_open'] = False
mask = (df.Datetime.dt.time > dt.time(15)) | (df.Datetime.dt.time < dt.time(13, 15))
df.loc[mask, 'market_open'] = True

在这里,我们创建一个函数,返回分组条上的开盘价、最高价、最低价、收盘价等信息:

def ohlc(df):
    return (
        df.Datetime.iat[-1], # last timestamp in group.
        df.Open.iat[0], # First Open.
        df.High.max(), 
        df.Low.min(), 
        df.Close.iat[-1], # Last Close.
        df.Up.sum(), 
        df.Down.sum(),
        df.Close.count(), # Count number of closing bars.
        df.market_open.iat[0])   # Take first True/False indicator.

现在我们根据 market_open变化(即True/False标志的变化)进行分组,然后将我们的函数应用于这些分组结果。

bars = pd.DataFrame(
    zip(*df.groupby(
            (df.market_open != df.market_open.shift())
            .cumsum()
             ).apply(ohlc))).T

bars.columns = ['bar_close_time', 'Open', 'High', 'Low', 'Close', 'Up', 'Down', 'bar_count', 'market_open']

我们有对于开市和闭市会话都有单独的条形图。我们可以移除闭市时的条形图。

# Remove bars when market is closed
bars = bars[bars.market_open].iloc[:, :-1]

>>> bars.tail()
          bar_close_time      Open     High      Low      Close        Up     Down bar_count
722  2015-12-28 13:10:00   1.23175  2.88569  -2.7143  -0.785648  -13.3166  14.6094       266
724  2015-12-29 13:10:00 -0.900675   2.6483 -2.61698    -0.8265  0.825872  4.98565       266
726  2015-12-30 13:10:00   1.65299  2.57881 -2.85199  -0.376141  -4.32867  3.62123       266
728  2015-12-31 13:10:00  0.435619  2.93638 -2.74758  -0.461525  -20.0928 -15.8205       266
730  2016-01-01 00:00:00  0.293165  2.39097  -2.1234  0.0684124  -7.83721  1.69182       108

谢谢Alexander, 当我得到这段代码时:dated['markt_open'] =False mask = (dated.Datetime.dt.time > dt.time(15)) | (dated.Datetime.dt.time < dt.time(13, 15)) dated.loc[mask, 'markt_open'] = True我收到了这个错误:AttributeError: 'DataFrame' object has no attribute 'datetime'顺便说一下,我正在使用Python 2.7的Jupyter笔记本。我在谷歌上搜索了解决方案,但是我被引导到与Series构造函数相关的时间序列内容,而不是与DataFrame构造函数相关的内容...有帮助吗? - AnaB29
导入日期时间模块并命名为dt - Alexander
嗨,Alexander,非常感谢您的帮助, 仍然出现相同的错误:AttributeError: 'DataFrame' object has no attribute 'datetime'导入已经调整: import pandas as pd--import numpy as np--import datetime as dt。我也纠正了我的拼写错误。我在这里查找Datetime属性:链接,但没有找到文档。 我不确定我错过了什么。 - AnaB29
你注意到我在上面的Datetime中使用了大写字母D,对吧?df['Datetime'] = pd.to_datetime(df.Date + ' ' + df.Time) - Alexander
发现了错误。与其像你所做的那样创建一个大的samp/DF,我使用了我的ES数据文件,并从dated['Date Time']开始而不是dated['Datetime'],并且在代码中没有意识到这一点。现在它完美地工作了--现在我只需要弄清楚它是如何工作的。我理解所有的内容直到zip()。所以我会分析它。正如你所看到的,我是边学边做。再次感谢您的帮助!除了McKinney的“Python for Data Analysis”(我已经有了这本书),您能推荐其他教如何创建类似于我正在处理的程序的书籍吗? - AnaB29
对于zip,[(a, b) for a, b in zip([1,2,3], [4,5,6])]会产生[(1, 4), (2, 5), 3, 6)]。关于内部的*,请参考这里:https://dev59.com/zHE85IYBdhLWcg3w_I38 - Alexander

0
你可以考虑添加一个辅助日期时间列,该列等于原始列减去14小时。这样每个交易会话都将在同一天内。
这与考虑另一个时区的日期时间相同,在该时区中,交易会话不会跨越两天。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接