生成具有指定边界的数字矩阵的算法

时间:2017-12-11 13:37:46

标签: python algorithm numpy optimization

我正在尝试生成一个包含7行和4列的数字矩阵。每行必须总和为100,每列必须在最小和最大范围(下面指定)之间具有均匀分布(如果允许)。

目标:

       C1      C2    C3    C4   sum   range 
 1     low                      100    ^
 2     ..                              |  
 3     ..                              |
 4     ..                              | 
 5     ..                              |
 6     ..                              |
 7     high                            _

c1_high = 98
c1_low = 75
c2_high = 15
c2_low = 6
c3_high = 8
c3_low = 2
c4_low = 0.05
c4_high =0.5

除此之外,我需要每行的扩展尽可能线性,尽管用二阶多项式拟合数据的线就足够了(r ^ 2值> 0.98)。

我目前正在尝试使用以下sudocode执行此操作:

  1. 在c1,c2,c3和c4的范围之间生成随机数。
  2. 重复7次
  3. 检查每个生成的c1值与1-7之间的数字范围之间的相关性。例如:
  4. enter image description here

    1. 对c2,c3和c4重复步骤3。

    2. 第3步和第4步成功时中断循环

    3. 事实证明,就所需的迭代次数而言,这是非常繁重的,因此,永远不会达到解决方案。

      是否有更有效的方法来实现此解决方案?

      到目前为止:

      import pandas as pd
      import numpy as np
      from sklearn.utils import shuffle
      
      c1_high = 98
      c1_low = 75
      c2_high = 15
      c2_low = 6
      c3_high = 8
      c3_low = 2
      c4_low = 0.05
      c4_high =0.5
      
      def matrix_gen(): #generates matrix within min and max values
          container =[]
          d={}
          offset = np.linspace(0.05,1,9)
          c1= np.linspace(c1_low, c1_high, 7)
          c2= np.linspace(c2_low, c2_high, 7)
          c3= np.linspace(c3_low, c3_high, 7)
          c4= np.linspace(c4_low, c4_high, 7)
      
          for i in np.arange(7):
              d["row{0}".format(i)]=[item[i] for item in [c1,c2,c3,c4]]
      
          df =pd.DataFrame(d)
          df.loc[4,:] = df.iloc[0,:][::-1].values
          df1 = df.drop(0)
          df1.loc[5,:] = df1.sum(axis=0)
          new_name = df1.index[-1]
          df1 = df1.rename(index={new_name: 'sum'})
          return df1
      
      m = matrix_gen()
      print(m)
      

      out:

             row0        row1        row2     row3        row4       row5  row6
      1      6.00    7.500000    9.000000   10.500   12.000000  13.500000  15.0
      2      2.00    3.000000    4.000000    5.000    6.000000   7.000000   8.0
      3      0.05    0.125000    0.200000    0.275    0.350000   0.425000   0.5
      4     98.00   94.166667   90.333333   86.500   82.666667  78.833333  75.0
      sum  106.05  104.791667  103.533333  102.275  101.016667  99.758333  98.5
      

      下一个功能:

      def shuf():  # attempts at shuffling the values around such that the 'sum' row is as close to 100 as possible. 
          df = matrix_gen()
          df1 = df[1:4]
          count =0
          while True:
              df1 = shuffle(df1)
              df1.loc[5,:] = df1.sum(axis=0)
              for i in df1.loc[5].values:
                  if 98<= i <=100:
                      print('solution')
                      return df1
                  else:
                      count+=1
                      print(count)
                      continue
      
      opt = shuf()
      print(opt)
      

      下一个函数需要对每个数字应用偏差,以提供每行等于100的总和。优化应包括最小化偏差。

2 个答案:

答案 0 :(得分:3)

我认为一种有趣的方法是使用优化模型。

有序值

让x(i,j)成为您想要填充的矩阵。然后我们有:

sum(j, x(i,j)) = 100   ∀i
L(j) ≤ x(i,j) ≤ U(j)   ∀i,j
x(i,j) = x(i-1,j) + step(j) + deviation(i,j)
   special cases:
     x(1,j) = L(j) + deviation(1,j)
     and x(m,j) = U(j) + deviation(m,j)
step(j) ≥ 0
minimize sum((i,j), deviation(i,j)^2 )

这是二次规划问题。有可能是绝对偏差而不是平方偏差。在那种情况下,你有一个LP。

可以改进模型以最小化平方相对误差。

这与所谓的矩阵平衡(经济建模中经常使用的统计技术)有点相关。

无序值

在上面我假设必须订购价值。现在我明白事实并非如此。我调整了模型来处理如下。首先是对结果的概述。

输入数据为:

----     17 PARAMETER LO  

c1 80.000,    c2  5.000,    c3  0.500,    c4  0.050


----     17 PARAMETER UP  

c1 94.000,    c2 14.000,    c3  5.000,    c4  0.500

警告:请注意,海报已更改此数据。我的答案是在更改之前使用原始的LO和UP值。

该模型分三步运行:

(1)填充完美有序的矩阵,而不遵守行和约束。这可以在模型外部完成。我简单地生成了:

----     53 PARAMETER init  initial matrix

            c1          c2          c3          c4      rowsum

r1      80.000       5.000       0.500       0.050      85.550
r2      82.333       6.500       1.250       0.125      90.208
r3      84.667       8.000       2.000       0.200      94.867
r4      87.000       9.500       2.750       0.275      99.525
r5      89.333      11.000       3.500       0.350     104.183
r6      91.667      12.500       4.250       0.425     108.842
r7      94.000      14.000       5.000       0.500     113.500

即。从lo(j)up(j),步数相同。

(2)第二步是置换列中的值,以实现与行总和紧密匹配的解决方案。这给出了:

----     53 VARIABLE y.L  after permutation

            c1          c2          c3          c4      rowsum

r1      94.000       5.000       0.500       0.125      99.625
r2      82.333      12.500       4.250       0.500      99.583
r3      89.333       8.000       2.000       0.200      99.533
r4      87.000       9.500       2.750       0.275      99.525
r5      84.667      11.000       3.500       0.350      99.517
r6      91.667       6.500       1.250       0.050      99.467
r7      80.000      14.000       5.000       0.425      99.425

这已经非常接近并保持“完美”的传播。

(3)通过添加偏差来稍微改变值,使得行总和正好为100.最小化平方相对偏差的总和。这给出了:

----     53 VARIABLE x.L  final values

            c1          c2          c3          c4      rowsum

r1      94.374       5.001       0.500       0.125     100.000
r2      82.747      12.503       4.250       0.500     100.000
r3      89.796       8.004       2.000       0.200     100.000
r4      87.469       9.506       2.750       0.275     100.000
r5      85.142      11.007       3.501       0.350     100.000
r6      92.189       6.510       1.251       0.050     100.000
r7      80.561      14.012       5.002       0.425     100.000


----     53 VARIABLE d.L  deviations

            c1          c2          c3          c4

r1       0.374       0.001 1.459087E-5 1.459087E-7
r2       0.414       0.003 9.542419E-5 9.542419E-7
r3       0.462       0.004 2.579521E-4 2.579521E-6
r4       0.469       0.006 4.685327E-4 4.685327E-6
r5       0.475       0.007 7.297223E-4 7.297223E-6
r6       0.522       0.010       0.001 1.123123E-5
r7       0.561       0.012       0.002 1.587126E-5

步骤(2)和(3)必须在优化模型中:它们必须同时执行才能获得经过验证的最佳解决方案。

数学模型可能如下所示:

enter image description here

该模型使用像Cplex或Gurobi这样的求解器在几秒钟内解决了经过验证的全局最优性。

我认为这是非常可爱的模特(好吧,这真的很讨厌,我知道)。置换用置换矩阵P(二进制值)建模。这使得模型成为MIQP(混合整数二次规划)模型。它可以很容易地线性化:在目标中使用绝对值而不是方块。经过适当的重新制定后,我们最终得到了一个线性MIP模型。有很多软件可以解决这个问题。这包括可从Python调用的库和包。

注意:我可能不应该在目标中除以init(i,j),而是用init矩阵中的列平均值除以y(i,j)。除以<script type="text/javascript"> $(document).on('click', '#reg_form_sub', function(event) { var error_message_lgn = $("#reg_frame").contents().text(); $('#reg_error').text(error_message_lgn); }); </script> 将是最好的,但这会导致另一种非线性。

答案 1 :(得分:1)

你的数字足够小,无法采用智能蛮力方法。

我使用两种方法来量化和最小化与“干净”等距值(linspace(low, high, 7))的偏差。 "abserr"表示平方差,"relerr"表示平方误差除以平方清洁值。我最后还检查了corrcoefs,但我从未见过99.8%以下的任何东西

以下代码首先找到具有最小错误的 clean 值的随机数。这只需几秒钟,因为我们使用以下技巧:

  • 将4列分成两对
  • 每对有7个! 相对安排,即使在平方时也是可管理的数字(每对一个因素)
  • 计算这些(7!)^ 2 shuffle并对
  • 求和
  • 不必遍历对之间的所有相对混洗,我们观察到如果两组对的总和以相反的顺序排列,则总误差最小化,这对于"abserr"和{{1}是正确的}

最后修正这些值以使行总和为100.这里我们再次使用均匀分布时最小化求和误差的事实。

下面的代码包含两个版本,一个版本"relerr",在最小化solve和修正版本relerr时包含很小的不准确性。他们经常找到不同的解决方案,但在100多个随机问题中,只有一个导致improved_solve的误差略小。

回答一些例子:

OP的例子:

improved_solve

将某些colums按升序降序排序的示例不是最佳的:

                ((75, 98), (6, 15), (2, 8), (0.05, 0.5))

solve relerr                            improved_solve relerr                  
table:                                  table:                                 
76.14213 15.22843  8.12183  0.50761     76.14213 15.22843  8.12183  0.50761    
79.02431 13.53270  7.01696  0.42603     79.02431 13.53270  7.01696  0.42603    
81.83468 11.87923  5.93961  0.34648     81.83468 11.87923  5.93961  0.34648    
84.57590 10.26644  4.88878  0.26888     84.57590 10.26644  4.88878  0.26888    
87.25048  8.69285  3.86349  0.19317     87.25048  8.69285  3.86349  0.19317    
89.86083  7.15706  2.86282  0.11928     89.86083  7.15706  2.86282  0.11928    
92.40924  5.65771  1.88590  0.04715     92.40924  5.65771  1.88590  0.04715    
avgerr:                                 avgerr:                                
 0.03239                                 0.03239                               
corrcoefs:                              corrcoefs:                             
 0.99977  0.99977  0.99977  0.99977      0.99977  0.99977  0.99977  0.99977 

请注意,解算器找到不同的解决方案,但错误是相同的。

                ((11, 41), (4, 34), (37, 49), (0.01, 23.99))

这是solve relerr improved_solve relerr table: table: 10.89217 18.81374 46.53926 23.75483 11.00037 24.00080 49.00163 15.99720 26.00087 9.00030 49.00163 15.99720 16.00107 19.00127 45.00300 19.99467 31.00207 4.00027 45.00300 19.99467 25.74512 13.86276 36.63729 23.75483 16.00000 29.00000 43.00000 12.00000 35.99880 8.99970 46.99843 8.00307 20.99860 33.99773 40.99727 4.00640 41.00000 4.00000 43.00000 12.00000 40.99863 13.99953 36.99877 8.00307 20.99860 33.99773 40.99727 4.00640 36.35996 24.23998 39.38996 0.01010 31.30997 29.28997 39.38996 0.01010 avgerr: avgerr: 0.00529 0.00529 corrcoefs: corrcoefs: 0.99993 0.99994 0.99876 0.99997 0.99989 0.99994 0.99877 0.99997 实际击败遗产improved_solve

的问题
solve

代码:

                ((36.787862883725872, 43.967159949544317),
                 (40.522239654303483, 47.625869880574164),
                 (19.760537036548321, 49.183056694462799),
                 (45.701873101046154, 48.051424087501672))

solve relerr                            improved_solve relerr                  
table:                                  table:                                 
21.36407 23.53276 28.56241 26.54076     20.25226 26.21874 27.07599 26.45301    
22.33545 24.52391 26.03695 27.10370     21.53733 26.33278 25.10656 27.02333    
23.33149 25.54022 23.44736 27.68093     22.90176 26.45386 23.01550 27.62888    
24.35314 26.58266 20.79119 28.27301     24.35314 26.58266 20.79119 28.27301    
25.40141 27.65226 18.06583 28.88050     25.90005 26.71994 18.42047 28.95953    
26.47734 28.75009 15.26854 29.50403     27.55225 26.86656 15.88840 29.69279    
27.58205 29.87728 12.39644 30.14424     29.32086 27.02351 13.17793 30.47771    
avgerr:                                 avgerr:                                
 0.39677                                 0.39630                               
corrcoefs:                              corrcoefs:                             
 0.99975  0.99975  0.99975  0.99975      0.99847  0.99847  0.99847  0.99847