我刚刚开始使用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中产生有效的结果。
有人可以提供一个指针,说明我应该如何优雅地编码,或打我的头,告诉我只是使用一个循环?
伊恩
答案 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
的相同语法。