我试图使用np.where()
返回复杂数据结构中元素的索引。这是学习实验的一部分。
但np.where()
在我的测试期间没有始终如一地运作。测试在iPython中进行,在Python 2.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
的数据结构,其中包含以下内容(仅显示本示例中使用的第一部分):
[[[1,2,3,4,5]],
[[[ 0.49555906 0.14471098 0.69386405 0.80504314 0.35316356]
[ 0.40202873 0.40388709 0.67211181 0.52745945 0.49144579]
[ 0.83240025 0.8187909 0.64860856 0.82538625 0.52107398]
[ 0.74900576 0.98173857 0.83579314 0.24578775 0.05530318]]
[[ 0.74250275 0.31464713 0.99314855 0.47654982 0.08117959]
[ 0.11474039 0.16351823 0.24030983 0.1734985 0.10746642]
[ 0.45627385 0.04654085 0.02521171 0.04290553 0.44018312]
[ 0.25114034 0.21058291 0.83786011 0.50925183 0.94918242]]
[[ 0.48894954 0.33250801 0.42154765 0.05738124 0.81262202]
[ 0.73752384 0.98451401 0.0684456 0.17910599 0.00412605]
[ 0.06446881 0.40695243 0.51251566 0.39912532 0.01384556]
[ 0.84967808 0.28460418 0.62816424 0.08959918 0.13076973]]],
# data structure continues with more sub elements not used in this test ...
尝试使用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()
测试仍然有效。
为什么第二次尝试使用np.where()
失败而第一次成功?
答案 0 :(得分:1)
进一步测试证实了对此问题的评论中发布的“浮点”舍入错误说明。这篇文章的目的是解释问题发生的条件以及如何解决这些问题。
此测试在这方面可能有用:
重新创建此对象:
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()
。
我首先意识到在我自己的iPython单元格中输出m3d[0][1][3]
的结果后,用17个小数位进行测试,看到它返回的小数位数多于打印整个对象时查看的小数位数:{{1 }}。
进一步测试表明精度仅在小数点后16位可靠。使用17,如果两个数字在小数点后的前16位数字相同,则它们将被视为相同。
在现实世界中,如果您使用print(md3)
,您应该确切地知道您要查找的号码,或者如果确切的号码未知,则应该对np.where()
感到满意。
原帖中出现的情景更多是由于测试的性质以及作者没有意识到浮点数如何得到舍入/显示,而不是由于现实世界中可能出现的一系列条件使用np.isclose()