切片时的 if 语句
Posted
技术标签:
【中文标题】切片时的 if 语句【英文标题】:if statement whilst slicing 【发布时间】:2016-06-24 06:35:54 【问题描述】:我有许多要切片的列表,例如(使用示例数据):
midpoint = [[0.2], [0.5], [0.6]]
Values = [[0.1, 0.3, 0.6, 0.8], [0.2,0.3,0.5,0.7], [0.2,0.5,0.6,0.9]]
numbers = numpy.arange(0, len(Values), 1)
然后我有一个循环,从numbers
中找到大于或小于midpoint
值的第一个值的索引位置。我有:
for i in range(len(Values)):
indexgtr = numbers[Values[i]>=midpoint[i]][-1] # The position of the first number larger than the midpoint
indexlt = numbers[Values[i]<=midpoint[i]][0] # The position of the first number larger than the midpoint
然后我使用这些索引位置从我拥有的其他一些列表中返回值。
我遇到的问题是,有时没有大于或小于中点的值,所以indexgtr
或indexlt
返回一个空列表[]
,我收到错误IndexError: index 0 is out of bounds for axis 0 with size 0
。
我可以添加一些东西来捕捉这个并将值 0 替换为空列表吗?
【问题讨论】:
我得到的错误和你的不一样,我运行你的代码得到的错误是我所期望的。首先,表达式Values[i] >= midpoint[i]
将list
与一个标量值进行比较,而在Python 2 中它只返回一个布尔值(Python 3 给出了不可排序的类型错误)。因此,如果它是True
,您正在访问numbers[1]
,如果它是False
,您正在访问numbers[0]
,并且然后尝试进一步访问numbers[1][-1]
或numbers[0][-1]
,这会报错,因为numbers[i]
是一个标量,不能为每个i
编制索引。
以上数据只是一个例子,因为我的真实数据非常大,解释起来也比较复杂。我知道它返回一个布尔值,但它不仅仅是False
的True
,它更多的是[True, True, True, False, False, False]
,具体取决于列表的长度。然后,这将适当地切片 numbers
并根据需要向我提供索引位置 [0]
或 [-1]
,除非我弄错了?
【参考方案1】:
您可以获得所需的结果向量化并沿第二个轴使用argmax
:
>>> midpoint = np.array([[0.2], [0.5], [0.6], [0.3]])
>>> values = np.array([[0.1, 0.3, 0.6, 0.8],
[0.2, 0.3, 0.5, 0.7],
[0.2, 0.5, 0.6, 0.9],
[0.3, 0.1, 0.8, 0.9]])
>>> (values > midpoint).argmax(axis=1) # indexgtr vectorized
array([1, 3, 3, 2]) # first >= occurrence for each row
>>> (values < midpoint).argmax(axis=1)
array([0, 0, 0, 1]) # first < occurrence for each row
注意:我已将<=
和>=
替换为<
和>
以更好地显示矢量化结果。请注意,对于<
的情况,第一行没有任何小于0.2
的列,但会返回0
(因为它是满是False
s 的行的第一次出现)。
.argmax(axis=1)
找到最大值在第二个轴上的位置。因为它是一个布尔数组,所以它返回第一个出现的True
。
【讨论】:
很好,但我认为np.argwhere
比np.argmax
更合适,因为您正在处理一个布尔数组
@wim 这将返回所有元素(满足条件)的索引,并且需要额外的后处理步骤来过滤每行的第一个元素。【参考方案2】:
您可以通过多种方式表达测试:
for i in range(len(Values)):
indexgtr = numbers[Values[i]>=midpoint[i]]
if indexgtr.shape[0]==0:
indexgtr = 0
else:
indexgtr = indexgtr[-1]
indexlt = numbers[Values[i]<=midpoint[i]]
if indexlt.shape[0]: # alt expression
indexlt = indexlt[0]
else:
indexlt = 0
# indexlt = indexlt[0] if len(indexlt) else 0
它们都有点罗嗦,但我不认为它们很贵。您在这里没有对向量做任何事情 - 除了从 numbers
中选择子值。由于numbers
已排序,您还可以使用min
或max
执行某些操作,而不是选择第一个或最后一个值。
使用以下内容测试表达式:
In [39]: x=np.arange(0)
In [40]: x[0] if len(x) else 0
Out[40]: 0
我假设您将在此循环中使用 indexgtr
和 indexlt
做一些事情,然后再转到下一个 i
。
【讨论】:
这基本上就是我最终要做的。我实际上将该值附加到一个新列表中,所以就像您的回答一样,我设置了一个if
循环来检查数组的长度。如果它是空的,那么我附加一个 0.0 的值,否则我运行我的代码。它也很罗嗦,但并不昂贵。以上是关于切片时的 if 语句的主要内容,如果未能解决你的问题,请参考以下文章