Python 在由随机数创建的特定复杂数据结构上的问题w np.where

Python 在由随机数创建的特定复杂数据结构上的问题w np.where,python,numpy,indexing,Python,Numpy,Indexing,我试图使用np.where()返回复杂数据结构中元素的索引。这是学习实验的一部分 但是np.where()在我的测试中并没有一致地工作。测试在iPython中进行,在Python2.7和3.6中表现相同 原始数据结构: import numpy as np import pandas as pd m3d=np.random.rand(3,4,5) n3d=m3d.reshape(4,3,5) o3d=np.random.rand(2,3,4,5) simp1=np.array([[1,2,3,

我试图使用
np.where()
返回复杂数据结构中元素的索引。这是学习实验的一部分

但是
np.where()
在我的测试中并没有一致地工作。测试在iPython中进行,在Python2.7和3.6中表现相同

原始数据结构:

import numpy as np
import pandas as pd

m3d=np.random.rand(3,4,5)
n3d=m3d.reshape(4,3,5)
o3d=np.random.rand(2,3,4,5)
simp1=np.array([[1,2,3,4,5]])
simp2=np.array([[10,9,8,7,6]])
simp3=[11,12,13]
# a dictionary
dfrm1 = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
        'year': [2000, 2001, 2002, 2001, 2002],
        'population': [1.5, 1.7, 3.6, 2.4, 2.9]}
# convert dictionary to DataFrame
dfrm1 = pd.DataFrame(dfrm1)

crazyList = [simp1, m3d, simp2, n3d, simp3, dfrm1, o3d]
trueSimp1=np.array([10,9,8,7,6])
crazyList.append(trueSimp1)
crazyList2 = list(crazyList)
由于两个嵌套的子结构由随机生成的数字填充,因此在测试
np.where()
时,必须将要在
np.where()中使用的值从数据结构单元格的输出复制并粘贴到测试单元格中的代码中

奇怪的是,有些人试图使用
np.where()
来定位索引,但有些人却没有

上面的代码为
crazyList2
生成了一个数据结构,其中包括以下内容(仅显示本例中使用的第一部分):

尝试使用
np.where()
查找第一个子元素上的索引是成功的:

测试代码:

print(crazyList[0])
np.where(crazyList[0]==2)
将索引报告为:

[[1 2 3 4 5]]
(array([0], dtype=int64), array([1], dtype=int64))
但是在第二个元素中更复杂的结构上运行相同测试的尝试失败了。它产生空输出

测试代码:

print(np.where(crazyList2[1]==0.83579314))
输出:

(array([], dtype=int64), array([], dtype=int64), array([], dtype=int64))
上面测试中使用的数字是从打印数据结构的输出复制而来的,没有重新运行它,因此我们知道我们正在处理子元素中存在的数字。此外,正如注释中所建议的,使用带有
np.isclose()
的测试代替
=
是可行的,但并不像我们希望的那样具体。您可以通过将测试值的最后一位向上或向下按1来修改测试值,
np.isclose()
test仍然有效,即使数据结构中不存在更改的数字


为什么第二次尝试使用
np.where()
失败了,而第一次成功了?

进一步的测试证实了在对这个问题的评论中发布的“浮点”舍入错误解释。这篇文章的目的是解释问题发生的条件以及如何解决这些条件

在这方面,该测试可能证明是有用的:

重新创建此对象:

import numpy as np
m3d=np.random.rand(3,4,5)
现在访问对象中的一个数字,但以此处显示的所有不同方式格式化输出:

print(m3d[0][1][3])
print("{0:.17f}".format(m3d[0][1][3]))
print("{0:.20f}".format(m3d[0][1][3]))
print("{0:.25f}".format(m3d[0][1][3]))
print("{0:.30f}".format(m3d[0][1][3]))
由于数字是随机生成的,所以您将得到不同的输出。当我这样做时,我的输出是:

0.640593901718
0.64059390171803487
0.64059390171803487490
0.6405939017180348749036511
0.640593901718034874903651143541
如果没有使用足够的小数位,即使在该点之前的所有数字上都匹配,
T/F
条件也会返回
False
。但应该注意的是,如果使用了太多的小数位数,
np.where()
将不支持该精度级别,并且在该特定场景中的行为更像
np.isclose()

在我将m3d[0][1][3]
的结果输出到它自己的iPython单元格中后,我第一次意识到要用17位小数进行测试,并且看到它返回的小数位数比打印整个对象时多:
print(md3)

进一步的测试表明,精确到小数点后16位才可靠。对于17,如果两个数字在小数点后的前16位完全相同,则它们将被视为相同的数字

在现实世界中,如果您使用的是
np.where()
,您应该确切知道您要查找的数字,或者如果不知道确切数字,您应该对
np.isclose()
感到满意


原始帖子中出现的情况更多地是由于测试的性质和作者没有意识到浮点数是如何取整/显示的,而不是由于现实世界中可能出现的一组条件,在使用
np.where()时会导致代码问题。

您遇到了浮点数问题。在这种情况下使用
np.isclose
,而不是
=
。理解有趣的
的关键在于理解条件测试。其中
所做的就是在
A==B
中找到
True
元素。谢谢您的评论。做了更多的调查,调查了你写的东西。第一条评论:
np.isclose
似乎从表面上解决了这个问题。但是如果你需要一个精确的匹配,那么精度的损失就是一个问题。我测试了另外两个数组中找不到的数字,只将最后一个数字增加或减少1,它们返回相同的索引结果。第二条评论——我知道它正在做一个正确/错误的测试。我不明白为什么我的第一个有效,而我的第二个无效。我在crazyList之外做了一个简单的浮点测试,它似乎可以工作。这个测试也可以工作,而我上面的例子的行为如下所示:
np.where(np.array([[0.98822145,0.09783841,0.07314108,0.54074233,0.3720003]==0.07314108)
问题修改为更好地反映问题的性质。测试揭示了症状的一种模式,如果它对其他人有帮助的话,这些症状也会作为答案公布。
0.640593901718
0.64059390171803487
0.64059390171803487490
0.6405939017180348749036511
0.640593901718034874903651143541