简体   繁体   English

执行 if 条件嵌套在 Python 中的 for 循环中的有效方法

[英]Efficient way to perform if condition nested in for loop in python

Is there an efficient pythonic way to perform if conditions in nested for loops:是否有一种有效的 Pythonic 方式来执行嵌套 for 循环中的 if 条件:

import numpy as np

big = 3
med = 2
small = 5

mat1 = np.zeros((big, 3))
mat2 = np.zeros((big, med, 3))
mat3 = np.zeros((big, med, small))

mat1 = np.array([
[0,0,0],\
[1.0,0.5,0.2],\
[0.2,0.1,-0.1]])

mat2 = np.array([[
[1.0,0.5,0.2],\
[0.1,0.1,0.1]],\
[[0.2,0.2,0.2],\
[1.0,-0.5,-0.2]],\
[[1.0,-0.5,-0.2],\
[-1.0,0.5,-0.2]]])

mat3 = np.array([[
[1,1,1,1,1],\
[0,21,1,3,5]],\
[[1,2,3,4,5],\
[-1,-2,-2,-3,-4]],\
[[1.0,1.2,1.3,1.4,1.5],\
[5,4,3,2,1]]])

sol = np.zeros((small))
for ii in np.arange(big):
  found = False
  for jj in np.arange(big):
    for kk in np.arange(med):
      if all(abs(mat1[ii, :] - mat2[jj, kk, :]) < 1E-8):
        found = True
        sol = mat3[jj, kk, :]
        print(sol)
        break
    if found:
      break

where big and med can be much bigger. big 和 med 可以更大。 The above dummy code works but is very slow.上面的虚拟代码有效,但速度很慢。 Is there a way to speed it up ?有没有办法加快速度?

Note: the mat1, mat2 and mat3 are floats (not integer) and are not zeros in practice.注意:mat1、mat2 和 mat3 是浮点数(不是整数),实际上不是零。

Solution:解决方案:

The solution for me was the following (greatly benefiting from @LRRR answer):我的解决方案如下(从@LRRR 回答中受益匪浅):

for ii in np.arange(big):
  tmp = mat1[ii, :]
  A = np.tile(tmp[:], (med, 1))
  AA = np.repeat(A[np.newaxis, :], big, 0)
  sub = abs(AA - mat2) < 1E-8
  tmp2 = mat3[sub.all(axis=2)]
  if (len(tmp2) > 0):
    val = tmp2[0, :]  

Note that because I had other complications I kept the outer loop.请注意,因为我有其他并发症,所以我保留了外循环。 The if statement is required as I want the first occurrence of a match. if语句是必需的,因为我想要匹配的第一次出现。 Also worth noting, this is significantly faster but probably can be made even faster since we could stop at the match rather than having all matches.同样值得注意的是,这明显更快,但可能可以做得更快,因为我们可以在比赛中停下来而不是进行所有比赛。

If I understand correctly your goal is for each row of mat1, subtract each row in each matrix of mat2, check if all values in the resultant vector are negative, and if true then use that index to return the values from mat3?如果我理解正确,您的目标是针对 mat1 的每一行,减去 mat2 的每个矩阵中的每一行,检查结果向量中的所有值是否为负,如果为真,则使用该索引从 mat3 返回值?

Here's an example on smaller data:以下是较小数据的示例:

import random
import numpy as np

random.seed(10)

big = 5
med = 3
small = 2

mat1 = np.random.randint(0, 10, (big, 3)) 
mat2 = np.random.randint(0, 10, (big, med, 3)) 
mat3 = np.random.randint(0, 10, (big, med, small)) 


# Row subtractions  
A = abs(np.repeat(mat1[:, np.newaxis], med, 1) - mat2) < 1E-8

# Extract from mat3  
mat3[A.all(axis = 2)]

Breaking it down mat1[:, np.newaxis] increases the array by another dimension and np.repeat() will duplicate each row, so the sizes of mat1 and mat2 will line up to do a simple subtraction between the two.将其分解mat1[:, np.newaxis]将数组增加另一个维度, np.repeat()将复制每一行,因此 mat1 和 mat2 的大小将对齐以在两者之间进行简单的减法。

Note: I left out the abs() from your original code on the line if all(abs(mat1[ii, :] - mat2[jj, kk, :]) < 1E-8): . 注意: if all(abs(mat1[ii, :] - mat2[jj, kk, :]) < 1E-8):我从原始代码中省略了 abs() It seems that by taking the absolute value, the condition < 1E-8 will never be satisfied. 看起来,取绝对值, < 1E-8的条件永远不会满足。

Update:更新:

Here's the redo using the new data added to the original post:这是使用添加到原始帖子的新数据的重做:

# Repeat each row of mat1 for rows in mat2
A = np.repeat(mat1, big * med, 0)
    
# Reshape mat2 to match matrix A
B = mat2.reshape(big*med, 3)
C = np.tile(B, (big, 1))
    
# Subtraction rows 
sub = abs(A - C) < 1E-8
    
# Find values from tiled mat2
values = C[sub.all(axis = 1)]
    
# Get indices on reshaped mat2
indices = np.all(B == values, axis=1)
    
# Reshape mat3
M = mat3.reshape(big * med, small)
    
# Result
M[indices]

output: array([[1., 1., 1., 1., 1.]])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM