Python 在for循环内设置条件

Python 在for循环内设置条件,python,pandas,loops,Python,Pandas,Loops,下面的for循环用于为15 varuabel创建所有可能的权重组合,但是,我只需要总变量=1的组合,但是,循环太大了,它运行了11个小时,仍然没有完成,因此代码可以在循环后执行行,并获得总和=1的组合,有没有办法在循环中设置条件 import pandas as pd, numpy, itertools w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15 = ( list( numpy.arange(0

下面的for循环用于为15 varuabel创建所有可能的权重组合,但是,我只需要总变量=1的组合,但是,循环太大了,它运行了11个小时,仍然没有完成,因此代码可以在循环后执行行,并获得总和=1的组合,有没有办法在循环中设置条件

import pandas as pd, numpy, itertools


w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15 = (
  list(
    numpy.arange(0, 11, 1)/10
  ) for i in range(15)
)
comb_list = [w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15]
weights_df = pd.DataFrame(
  columns = ['w1', 'w2', 'w3', 'w4', 'w5', 'w6', 'w7', 'w8', 'w9', 'w10', 'w11', 'w12', 'w13', 'w14', 'w15']
)

for weights in itertools.product(*comb_list):
    weights_df.loc[len(weights_df)] = weights


weights_df.loc[:,'total_weight'] = (weights_df['w1'] 
  + weights_df['w2'] + weights_df['w3'] 
  + weights_df['w4'] + weights_df['w5']
  + weights_df['w6'] + weights_df['w7']
  + weights_df['w8'] + weights_df['w9'] 
  + weights_df['10'] + weights_df['w11']
  + weights_df['w12'] + weights_df['w13']
  + weights_df['w14'] + weights_df['w15'])
weights_df = weights_df[weights_df['total_weight'] == 1]

共有十五个列表,每个列表包含十一个(0-10个)元素。你得到的是所有这些的笛卡尔积

这是您迭代的11^15项。大约4千5百万。

当然,您可以在for循环中移动测试,但我认为这不足以使这个脚本实用

你也可以把你的循环分解成一个15倍的嵌套循环,每个级别都有一个过滤器;我希望这能在运行时给您带来一个数量级的改进。但我认为这还不够

<>你需要抽象地考虑这个问题,找出一些不太有力的方法来计算你想要计算的任何东西。

< P> <强>索赔<强> < /P> 此问题可以在25秒内解决,而不是在11小时内解决,如下所示

class BackTrack:
  max_n = 15      # Max number of weights (i.e. 15)
  max_sum = 10    # sum of integer weights
  normalization = 0.1  # factor to multiply integer weights to make them between 0 and 1

  def solve(self, sum_ = 0, weights = []):
    """Find weights that sum to 1 by finding weights that sum to 10 then multiply by 0.1
       Integer weights are used during backtracking to avoid issues of rounding errors in computations"""
    if len(weights) > BackTrack.max_n or sum_ > BackTrack.max_sum:
      # No solution since too many weights or sum is too large
      return

    if len(weights) == BackTrack.max_n and sum_ == BackTrack.max_sum:
      # Add path normalized to range 0 to 1 by multiplyfing by
      # normalization constant
      yield [weight*BackTrack.normalization for weight in weights]

    # Check for new solutions
    for weight in range(BackTrack.max_sum + 1):
      if weight + sum_ > BackTrack.max_sum:
        # No more solutions for this or higher weight
        break
      else:
        # Recursively find solutions for this weight
        yield from self.solve(sum_ + weight, weights + [weight])
  • 使用回溯搜索F11^15或4五百万搜索空间
  • 回溯提供了一种机制,用于丢弃不满足约束(即权重和约束)的部分搜索空间
  • 代码

    class BackTrack:
      max_n = 15      # Max number of weights (i.e. 15)
      max_sum = 10    # sum of integer weights
      normalization = 0.1  # factor to multiply integer weights to make them between 0 and 1
    
      def solve(self, sum_ = 0, weights = [], solutions = []):
        """Find weights that sum to 1 by finding weights that sum to 10 then multiply by 0.1
           Integer weights are used during backtracking to avoid issues of rounding errors in computations"""
        if len(weights) > BackTrack.max_n or sum_ > BackTrack.max_sum:
          # Backtrack since no solution since either
          # too many weights or sum of current weights is too large
          return
    
        if len(weights) == BackTrack.max_n and sum_ == BackTrack.max_sum:
          # Found solution
          # Add weights normalized to range 0 to 1 by multiplyfing by
          # normalization constant
          solutions.append([weight*BackTrack.normalization for weight in weights])
          return solutions
    
        # Add additional weights
        for weight in range(BackTrack.max_sum + 1):
          if weight + sum_ > BackTrack.max_sum:
            # No more solutions for this or higher weight
            break
          else:
            # Recursively find solutions for this weight
            self.solve(sum_ + weight, weights + [weight], solutions)
    
        return solutions
    
    b = BackTrack()
    for weights in b.solve(0, []):
        do_something(weights) # current w1, w2, ... w15
    
    测试

    # start timer
    import time
    t0 = time.time()  
    
    # Solve for weigt combinations
    b = BackTrack()
    weights = b.solve(0, [], [])
    
    # Show results
    print('Elapsed Time {:.2f} seconds'.format(time.time() - t0))
    print("Number of Solutions: {:,}".format(len(weights)))
    print('Head of Solutions (first 4): ', *weights[:5], sep = '\n')
    print('Tail of Solutions (last 4): ', *weights[-5:], sep = '\n')
    
    Elapsed Time 23.78 seconds
    Number of Solutions: 1,961,256
    Head of Solutions (first 4): 
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1, 0.9]
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.2, 0.8]
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.30000000000000004, 0.7000000000000001]
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.4, 0.6000000000000001]
    Tail of Solutions (last 4): 
    [0.9, 0.0, 0.0, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    [0.9, 0.0, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    [0.9, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    [0.9, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    
    输出

    # start timer
    import time
    t0 = time.time()  
    
    # Solve for weigt combinations
    b = BackTrack()
    weights = b.solve(0, [], [])
    
    # Show results
    print('Elapsed Time {:.2f} seconds'.format(time.time() - t0))
    print("Number of Solutions: {:,}".format(len(weights)))
    print('Head of Solutions (first 4): ', *weights[:5], sep = '\n')
    print('Tail of Solutions (last 4): ', *weights[-5:], sep = '\n')
    
    Elapsed Time 23.78 seconds
    Number of Solutions: 1,961,256
    Head of Solutions (first 4): 
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1, 0.9]
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.2, 0.8]
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.30000000000000004, 0.7000000000000001]
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.4, 0.6000000000000001]
    Tail of Solutions (last 4): 
    [0.9, 0.0, 0.0, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    [0.9, 0.0, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    [0.9, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    [0.9, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    
    发电机版本

    在这种情况下,我们为权重创建了一个生成器,它消除了存储所有1.9M权重向量的必要性,如下所示

    class BackTrack:
      max_n = 15      # Max number of weights (i.e. 15)
      max_sum = 10    # sum of integer weights
      normalization = 0.1  # factor to multiply integer weights to make them between 0 and 1
    
      def solve(self, sum_ = 0, weights = []):
        """Find weights that sum to 1 by finding weights that sum to 10 then multiply by 0.1
           Integer weights are used during backtracking to avoid issues of rounding errors in computations"""
        if len(weights) > BackTrack.max_n or sum_ > BackTrack.max_sum:
          # No solution since too many weights or sum is too large
          return
    
        if len(weights) == BackTrack.max_n and sum_ == BackTrack.max_sum:
          # Add path normalized to range 0 to 1 by multiplyfing by
          # normalization constant
          yield [weight*BackTrack.normalization for weight in weights]
    
        # Check for new solutions
        for weight in range(BackTrack.max_sum + 1):
          if weight + sum_ > BackTrack.max_sum:
            # No more solutions for this or higher weight
            break
          else:
            # Recursively find solutions for this weight
            yield from self.solve(sum_ + weight, weights + [weight])
    
    用法

    class BackTrack:
      max_n = 15      # Max number of weights (i.e. 15)
      max_sum = 10    # sum of integer weights
      normalization = 0.1  # factor to multiply integer weights to make them between 0 and 1
    
      def solve(self, sum_ = 0, weights = [], solutions = []):
        """Find weights that sum to 1 by finding weights that sum to 10 then multiply by 0.1
           Integer weights are used during backtracking to avoid issues of rounding errors in computations"""
        if len(weights) > BackTrack.max_n or sum_ > BackTrack.max_sum:
          # Backtrack since no solution since either
          # too many weights or sum of current weights is too large
          return
    
        if len(weights) == BackTrack.max_n and sum_ == BackTrack.max_sum:
          # Found solution
          # Add weights normalized to range 0 to 1 by multiplyfing by
          # normalization constant
          solutions.append([weight*BackTrack.normalization for weight in weights])
          return solutions
    
        # Add additional weights
        for weight in range(BackTrack.max_sum + 1):
          if weight + sum_ > BackTrack.max_sum:
            # No more solutions for this or higher weight
            break
          else:
            # Recursively find solutions for this weight
            self.solve(sum_ + weight, weights + [weight], solutions)
    
        return solutions
    
    b = BackTrack()
    for weights in b.solve(0, []):
        do_something(weights) # current w1, w2, ... w15
    

    这看起来像一个XY问题。我认为如果你仔细解释你试图解决的首要问题,而不是关于for循环的细节,你会得到更多的回应。而且,这听起来像是一个N因子问题(
    15!=1.3万亿
    ),这可以解释为什么它已经运行了11个小时。@mohammadanbar--我的答案说明了如何通过使用更好的搜索方法而不是暴力,在几秒钟而不是几小时内找到你的体重(即,您当前的for循环方法覆盖了所有可能性)。这有帮助吗?@DarryIG,谢谢您的帮助,不幸的是,这并不是我所需要的,基本上以下是主要思想:对于itertools.product(*comb_list)中的权重:if sum(weights)==1:weights_df.loc[len(weights_df)]=权重,因此权重的组合将是一个数据帧,每个W1、W2……及其可能性,但代码需要永远才能完成