切片时的 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

然后我使用这些索引位置从我拥有的其他一些列表中返回值。

我遇到的问题是,有时没有大于或小于中点的值,所以indexgtrindexlt 返回一个空列表[],我收到错误IndexError: index 0 is out of bounds for axis 0 with size 0

我可以添加一些东西来捕捉这个并将值 0 替换为空列表吗?

【问题讨论】:

我得到的错误和你的不一样,我运行你的代码得到的错误是我所期望的。首先,表达式Values[i] &gt;= midpoint[i]list 与一个标量值进行比较,而在Python 2 中它只返回一个布尔值(Python 3 给出了不可排序的类型错误)。因此,如果它是True,您正在访问numbers[1],如果它是False,您正在访问numbers[0],并且然后尝试进一步访问numbers[1][-1]numbers[0][-1],这会报错,因为numbers[i] 是一个标量,不能为每个i 编制索引。 以上数据只是一个例子,因为我的真实数据非常大,解释起来也比较复杂。我知道它返回一个布尔值,但它不仅仅是FalseTrue,它更多的是[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

注意:我已将&lt;=&gt;= 替换为&lt;&gt; 以更好地显示矢量化结果。请注意,对于&lt; 的情况,第一行没有任何小于0.2 的列,但会返回0(因为它是满是Falses 的行的第一次出现)。

.argmax(axis=1) 找到最大值在第二个轴上的位置。因为它是一个布尔数组,所以它返回第一个出现的True

【讨论】:

很好,但我认为np.argwherenp.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 已排序,您还可以使用minmax 执行某些操作,而不是选择第一个或最后一个值。

使用以下内容测试表达式:

In [39]: x=np.arange(0)
In [40]: x[0] if len(x) else 0
Out[40]: 0

我假设您将在此循环中使用 indexgtrindexlt 做一些事情,然后再转到下一个 i

【讨论】:

这基本上就是我最终要做的。我实际上将该值附加到一个新列表中,所以就像您的回答一样,我设置了一个 if 循环来检查数组的长度。如果它是空的,那么我附加一个 0.0 的值,否则我运行我的代码。它也很罗嗦,但并不昂贵。

以上是关于切片时的 if 语句的主要内容,如果未能解决你的问题,请参考以下文章

Golang 切片追加

PSD切片良好实践

熊猫切片不包括末端

为啥graphQl在尝试对查询进行切片时返回“字段上的未知参数'first'......”错误?

python序列

附加到结构切片时无效的内存地址或 nil 指针取消引用