获取警告"默认情况下,TimeSeries沿DataFrame索引广播已弃用"

时间:2014-04-17 00:05:29

标签: python error-handling module pandas

我正在使用Python 2.7并继续收到以下错误。如果您需要完整的代码,请告诉我,但它有点长。谢谢你的帮助。

Warning (from warnings module):
  File "C:\Python27\lib\site-packages\pandas\core\frame.py", line 3619
FutureWarning)
FutureWarning: TimeSeries broadcasting along DataFrame index by default is deprecated.     
Please use DataFrame.<op> to explicitly broadcast arithmetic operations along the index

这是类Portfolio

class Portfolio(object):
"""An abstract base class representing a portfolio of 
positions (including both instruments and cash), determined
on the basis of a set of signals provided by a Strategy."""

__metaclass__ = abc.ABCMeta

@abc.abstractmethod
def generate_positions(self):
    raise NotImplementedError("Should implement generate_positions()!")

@abc.abstractmethod
def backtest_portfolio(self):
    raise NotImplementedError("Should implement backtest_portfolio()!")

这是导致&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;如果名称 ==&#34; 主要&#34;

import datetime
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

from pandas.io.data import DataReader
from backtest import Strategy, Portfolio

class MovingAverageCrossStrategy(Strategy):

def __init__(self, symbol, bars, short_window=8, long_window=50):
    self.symbol = symbol
    self.bars = bars

    self.short_window = short_window
    self.long_window = long_window

def generate_signals(self):
    signals = pd.DataFrame(index=self.bars.index)
    signals['signal'] = 0.0

    # Create the set of short and long simple moving averages over the 
    # respective periods
    signals['short_mavg'] = pd.rolling_mean(bars['Close'], self.short_window, min_periods=1)
    signals['long_mavg'] = pd.rolling_mean(bars['Close'], self.long_window, min_periods=1)

    # Create a 'signal' (invested or not invested) when the short moving average crosses the long
    # moving average, but only for the period greater than the shortest moving average window
    signals['signal'][self.short_window:] = np.where(signals['short_mavg'][self.short_window:]
                                                     > signals['long_mavg'][self.short_window:], 1.0, 0.0)   

    # Take the difference of the signals in order to generate actual trading orders
    signals['positions'] = signals['signal'].diff()   

    return signals

class MarketOnClosePortfolio(Portfolio):

def __init__(self, symbol, bars, signals, initial_capital=100000.0):
    self.symbol = symbol        
    self.bars = bars
    self.signals = signals
    self.initial_capital = float(initial_capital)
    self.positions = self.generate_positions()

def generate_positions(self):
    positions = pd.DataFrame(index=signals.index).fillna(0.0)
    positions[self.symbol] = 100*signals['signal']   # This strategy buys 100 shares
    return positions

def backtest_portfolio(self):
    portfolio = self.positions*self.bars['Close']
    pos_diff = self.positions.diff()

    portfolio['holdings'] = (self.positions*self.bars['Close']).sum(axis=1)
    portfolio['cash'] = self.initial_capital - (pos_diff*self.bars['Close']).sum(axis=1).cumsum()

    portfolio['total'] = portfolio['cash'] + portfolio['holdings']
    portfolio['returns'] = portfolio['total'].pct_change()
    return portfolio

if __name__ == "__main__":
# Obtain daily bars of stock from Yahoo Finance for the period
# 1st Jan 1990 to 1st Jan 2014 - This is an example from ZipLine
symbol = 'AAPL'
bars = DataReader(symbol, "yahoo", datetime.datetime(1990,1,1), datetime.datetime(2014,1,1))

# Create a Moving Average Cross Strategy instance with a short moving
# average window of 8 days and a long window of 50 days
mac = MovingAverageCrossStrategy(symbol, bars, short_window=8, long_window=50)
signals = mac.generate_signals()

# Create a portfolio of stock, with $100,000 initial capital
portfolio = MarketOnClosePortfolio(symbol, bars, signals, initial_capital=100000.0)
returns = portfolio.backtest_portfolio()

1 个答案:

答案 0 :(得分:5)

无法运行代码,很难指出确切的原因,但请在generate_positions中使用此行:

portfolio = self.positions*self.bars['Close']

假设self.positions是一个DataFrame,self.bars['Close']是一个系列(在本例中是一个DataFrame列,以系列形式返回)。我尝试用玩具示例来解释这个问题:

首先生成一个数据帧和一个系列(带有datetimeindex):

In [3]: idx = pd.date_range('2012-01-01', periods=3)
In [5]: df = pd.DataFrame({'A':[1,2,3], 'B':[10,20,30]}, index=idx)
In [6]: df
Out[6]: 
            A   B
2012-01-01  1  10
2012-01-02  2  20
2012-01-03  3  30

In [7]: s = pd.Series([1,2,3], index=idx)
In [8]: s
Out[8]: 
2012-01-01    1
2012-01-02    2
2012-01-03    3
Freq: D, dtype: int64

现在,如果我们将两者相乘,我们会收到你注意到的警告:

In [10]: df * s
/home/joris/scipy/pandas-np16/pandas/core/frame.py:2920: FutureWarning: TimeSeries 
broadcasting along DataFrame index by default is deprecated. Please use DataFrame.<op> 
to explicitly broadcast arithmetic operations along the index
  FutureWarning)
Out[10]: 
            A   B
2012-01-01  1  10
2012-01-02  4  40
2012-01-03  9  90

这是因为我在评论中提到的内容在此解释:http://pandas.pydata.org/pandas-docs/stable/dsintro.html?highlight=broadcasting#data-alignment-and-arithmetic。通常,如果数据帧和系列相乘,则系列会在列上广播,而对于时间序列,这是在行上完成的。但这已被弃用 因此,您应该使用等效运算符作为警告建议。在乘法的情况下:

In [13]: df.mul(s, axis=0)
Out[13]: 
            A   B
2012-01-01  1  10
2012-01-02  4  40
2012-01-03  9  90

因此,对于每个运算符(+,*;&lt;,&gt;,/等),都有一个等效的方法。请参阅此处获取方法列表:http://pandas.pydata.org/pandas-docs/stable/api.html#id4 [url updated]


要显示'广播列上'的含义,另一个例子是:

In [14]: s2 = pd.Series([10, 100],  index=['A', 'B'])

In [15]: s2
Out[15]: 
A     10
B    100
dtype: int64

In [16]: df * s2
Out[16]: 
             A     B
2012-01-01  10  1000
2012-01-02  20  2000
2012-01-03  30  3000

正如您所看到的,系列的每个元素都与一列匹配,然后将整列与该值相乘。在时间序列的情况下,系列的每个元素都与一行匹配。