2016-08-25 148 views
7

这给了我很多麻烦,而且我对numpy数组与pandas系列的不兼容性感到困惑。当我使用一系列创建布尔数组时,例如用布尔数组掩盖一系列

x = np.array([1,2,3,4,5,6,7]) 
y = pd.Series([1,2,3,4,5,6,7]) 
delta = np.percentile(x, 50) 
deltamask = x- y > delta 

delta掩码创建布尔熊猫系列。

但是,如果你这样做

x[deltamask] 
y[deltamask] 

您发现该阵列完全忽略面膜。没有错误发生,但最终会得到两个不同长度的对象。这意味着,像

x[deltamask]*y[deltamask] 

导致错误的操作:

print type(x-y) 
print type(x[deltamask]), len(x[deltamask]) 
print type(y[deltamask]), len(y[deltamask]) 

更令人费解的,我注意到,运营商<被区别对待。例如

print type(2*x < x*y) 
print type(2 < x*y) 

将分别给你一个pd.series和np.array。

此外,

5 < x - y 

产生一系列,如此看来,该系列优先,而一系列掩模的布尔元素传递到numpy的阵列时,并导致一个切片被提升到整数阵列。

这是什么原因?

+2

'pandas'数据结构建立在'numpy'数组之上。 ''系列'确实有点***'numpy'阵列,它们不是'numpy'阵列。另外,你的意思是:_系列完全忽略了面具。 'deltamask'全部是'False',所以'Series'不应该返回任何值。 – Abdou

+0

对不起,我的意思是相反的。系列不尊重阵列蒙版,阵列不尊重系列蒙版。 – michel

+0

我认为'系列'尊重'numpy阵列'口罩;再检查一遍。但是numpy数组似乎没有采用'Series'掩码(实际上这很有趣)。但是'x [deltamask.values]'确实有效。 – Abdou

回答

3

花式索引

作为numpy的目前维持在numpy的花哨索引的工作原理如下:

  1. 如果括号内的东西是一个tuple(是否有明确的括号或没有)时,元组的元素是x不同维度的索引。例如,在这种情况下,x[(True, True)]x[True, True]都将增加IndexError: too many indices for array,因为x是1D。但是,在发生异常之前,还会发出警告:VisibleDeprecationWarning: using a boolean instead of an integer will result in an error in the future

  2. 如果括号之间的事情是恰好一个ndarray,而不是一个子类或其它阵列状,并有一个布尔类型,它将被作为掩模施加。这就是为什么x[deltamask.values]给出了预期结果(空数组因为deltamask是所有False

  3. 如果括号内的事情是任何阵列状,无论是像Series或只是一个list,还是其他什么东西的子类,它被转换到np.intp数组(如果可能的话)并用作整数索引,所以x[deltamask] yeilds东西相当于x[[False] * 7]或者只是x[[0] * 7]在这种情况下,len(deltamask)==7x[0]==1所以结果是[1, 1, 1, 1, 1, 1, 1]

这种行为是违反直觉的,它生成的FutureWarning: in the future, boolean array-likes will be handled as a boolean array index表示修复正在进行中。我会更新这个答案,因为我发现/对numpy进行了任何更改。

这个信息可以在塞巴斯蒂安伯格对我对Numpy讨论here的最初查询的回应中找到。

关系运算符

现在让我们来解决您在比较是如何工作的问题的第二部分。关系运算符(<,>,<=,>=)通过调用被比较对象之一的相应方法来工作。对于<这是__lt__。然而,Python实际上并没有为表达式x < y调用x.__lt__(y),而是检查被比较对象的类型。如果y是实现比较的x的子类型,则不管您如何编写原始比较,Python都倾向于调用y.__gt__(x)。如果yx的子类,则x.__lt__(y)将被调用的唯一方式是如果y.__gt__(x)返回NotImplemented以指示在该方向上不支持该比较。

当你做5 < x - y时会发生类似的事情。虽然ndarray不是int的子类,但比较int.__lt__(ndarray)返回NotImplemented,因此Python实际上最终调用(x - y).__gt__(5),这当然是定义的,并且工作得很好。

Python docs可以找到更简洁的解释。