条件循环数组的Pythonic代码(Market Meaness Index)

时间:2017-01-18 23:04:55

标签: python arrays algorithmic-trading

我刚刚开始使用Python,我之前的所有经验都是C ++类型语言。

试图学习"好" Python我一直在尝试将这种类似C的函数转换为Python。

var MMI(var *Data,int Length)
{
  var m = Median(Data,Length);
  int i, nh=0, nl=0;
  for(i=1; i<Length; i++) {
    if(Data[i] > m && Data[i] > Data[i-1])
      nl++;
    else if(Data[i] < m && Data[i] < Data[i-1])
      nh++;
  }
  return 100.*(nl+nh)/(Length-1);
}

我非常确定我可以使用for循环轻松完成,但我一直尝试使用一系列数组操作,而不是显式循环。我提出了:

import numpy as np
import pandas as pd
from pandas import Series 

def MMI( buffer, mmi_length ):
    window = Series( buffer[:mmi_length] )
    m      = window.median()

    nh = np.logical_and( [window > m], [window > window.shift(1)] ) 
    nl = np.logical_and( [window < m], [window < window.shift(1)] ) 
    nl = np.logical_and( [not nh], [nl] )

    return 100 * ( nh.sum() + nl.sum() ) / mmi_length

最终的np.logical_and( [not nh], [n] )给出了一个不明确的真实值&#34;错误,我不明白,但更重要的是,我不确定这种方法是否真的会在Python中产生有效的结果。

有人可以提供一个指针,说明我应该如何优雅地编码,或打我的头,告诉我只是使用一个循环?

伊恩

1 个答案:

答案 0 :(得分:4)

Python是隐式的,与C ++不同,你几乎必须声明一切。 Python,numpy / pandas或其他模块,内置了大量优化的功能 - 为了让你在没有很多循环或价值比较的情况下工作(模块在后台做什么,通常是for循环虽然 - 所以不要认为它必然更快,它通常只是一个漂亮的封面。

现在,让我们看看你的代码

import numpy as np # no need for pandas here


def MMI( buffer, mmi_length ):
    # we will need to define two arrays here,
    # shift(n) does not do what you want
    window = np.asarray(buffer[1:mmi_length])
    window_shifted = np.asarray(buffer[:mmi_length-1])
    m = np.median(window)

    # instead using all these explicit functions simply do:
    nh = (window > m) & (window > window_shifted) 
    nl = (window < m) & (window < window_shifted) 
    nl = ~nh & nl                                # ~ inverts a lot of things,
                                                 # one of them are boolean arrays

    # this does the right thing
    return 100*(nh.sum()+nl.sum())/mmi_length

现在让我们解释一下:

A Series基本上是一个数组,在这种情况下,一个系列似乎是一种矫枉过正。如果将这样的对象与标量进行比较,您将得到一个布尔数组,表示哪个值满足条件,哪个不符合(比较两个数组,它将导致布尔数组通过值比较表示值) )。

在第一步中,将数组与标量进行比较(记住,这将是一个布尔数组),将另一个数组与另一个数组进行比较(我们将转到移位部分),然后想要逻辑并组合比较的结果。好的是,你想要组合两个布尔数组,这将由&操作隐式地工作。 第二步是类似的,并且隐含地相同。

在第三步中,您要反转布尔数组并将其与另一个布尔数组合并。反演由~运算符完成,并且可以在其他地方的批次中使用(例如,用于反转子集选择等)。你不能在这里使用not运算符,因为它的目的是将其参数转换为真值(True / False)并返回相反的 - 但数组的真值是多少?所有组件的逻辑和组合?它没有定义,因此您得到ambiguous错误。

布尔数组的sum()始终是数组中True个值的计数,因此它将产生正确的结果。

您的代码唯一的问题是,如果您将shift(1)应用于此系列,它将添加NaN并截断系列的最后一个元素,以便您最终获得相同的结果长度的对象。现在你的比较不再产生你想要的东西了,因为与numpy.NaN相比的任何东西都会返回False。 为了克服这个问题,你可以在开头简单地定义第二个数组(然后使pandas过时),使用你之前用于window的相同语法。

PS:一个numpy数组不是python列表(以上所有都是numpy数组!)numpy数组是一个复杂的对象,允许所有这些操作,使用标准的python列表,你必须自己的for循环