在for循环内设置条件

2024-09-24 02:22:37 发布

您现在位置:Python中文网/ 问答频道 /正文

下面的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]

Tags: dfw1weightsw3w2w4w11w12
2条回答

索赔

此问题可以在25秒内解决,而不是在11小时内解决,如下所示

  1. 使用回溯搜索F11^15或4五百万搜索空间
  2. 回溯提供了一种机制,用于丢弃不满足约束(即权重和约束)的部分搜索空间

代码

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

测试

# 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])

用法

b = BackTrack()
for weights in b.solve(0, []):
    do_something(weights) # current w1, w2, ... w15

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

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

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

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

你需要重新思考并抽象地考虑这个问题,找出一些计算你正在计算的东西的方法。p>

相关问题 更多 >