Python: решение проблемы поиска комбинации, которая удовлетворяет определенному условию - PullRequest
0 голосов
/ 05 февраля 2019

Я столкнулся с проблемой, которую не могу решить, используя обычный метод грубой силы.
Задача - Я пытаюсь найти комбинацию из 50 лет, взятых по 30 без повторений, например,что их среднее значение и коэффициент вариации находятся в определенном диапазоне.Я использую itertools combinations для этого.Но проблема в том, что ни одна из общих комбинаций - 47129212243960, которые слишком долго вычисляются.Есть ли способ сделать это более эффективно?
Набор данных имеет следующий формат:

Yrs       Prs_90      Prs_80      Prs_70

2012  499.934588  521.512345  425.189729
2013  579.063531  477.782099  256.382494
2014  458.415624  456.480642  363.309507

Я вычисляю среднее значение и коэффициент вариации Prs_90 , Prs_80, Prs_70, а затем нахожу комбинацию в соответствии с пороговым значениемкоторый зависит от среднего и коэффициента вариации.
Правка - Коэффициент вариации (CV) = Стандартное отклонение (x) / Среднее (x)
Условие для выбора требуемой комбинации, которая будет выбрана, -

if (mean >= 501 and <= 570) and ((0.13<=CV<=0.17) or(0.23<=CV<=0.27) or(0.23 <=CV <=27)

или

if (mean >= 451 and <= 460) and ((0.13<=CV<=0.17) or(0.23<=CV<=0.27) 
or(0.33 <=CV <=37):

или

if (mean >= 391 and <= 400) and ((0.13<=CV<=0.17) or(0.23<=CV<=0.27) 
or(0.33 <=CV <=37)):

Мне нужна комбинация, соответствующая каждому из указанных выше условий.

Edit- Сначала я переупорядочиваю приведенный выше кадр данных в следующем формате -

             Yrs      Prs_80      Prs_70
Prs_90                                  
579.063531  2013  477.782099  256.382494
477.758138  2044  475.458614  259.228592
492.957830  2036  408.590138  281.921215
541.632294  2042  430.990568  290.163454
565.369062  2024  420.107058  296.545395
409.979527  2027  379.740246  301.086631
347.702470  2052  610.775045  307.756455
460.657276  2016  301.774467  309.311562

, а затем использую следующий подход -

r =30
check1 = 1
check10 = 1
for p in combinations(test4.index,r):
  den = np.mean(p)
  num = np.std(p)
  cv = num/den
  if (den >= 561 and den <= 570 ) :
     if(cv>=0.13 or cv <= 0.17 and check1):
     check1=0
     print("Combination 1 done")

  elif(den>=391 and den <= 400):
     if(cv>=0.13 or cv < 0.17 and check10):
     check10 = 0
     print("Combination 10 done")
if(check1+check10==0)
break

Я принимаю здесь только для2 условия даже тогда. Это выполняется для кроров итерации, поэтому полная обработка комбинаций займет больше времени.
Я использую check1 и check10 в качестве сигнала, так как при получении следующей комбинации я разрываю петлю.

Дополнительная информация -

           Prs_90      Prs_80      Prs_70
count   50.000000   50.000000   50.000000
mean   510.732700  445.366865  386.037076
std    113.773333   84.078209   80.987841
min    347.702470  233.335085  256.382494
25%    427.241363  390.745725  320.812298
50%    469.263029  439.407141  383.430153
75%    573.406731  512.019602  433.199140
max    854.819691  610.775045  644.588971

CV данных составляет 25%.

1 Ответ

0 голосов
/ 05 февраля 2019

Я сказал, что нечто подобное может быть решено как модель MINLP (смешанного целочисленного нелинейного программирования).Позвольте мне попробовать.

Я сгенерировал некоторые случайные данные как:

----     30 PARAMETER p  random data

year1  18.003,    year2  84.483,    year3  55.487,    year4  30.813,    year5  29.929,    year6  23.181
year7  35.633,    year8  85.771,    year9   7.644,    year10 50.521,    year11 99.814,    year12 58.295
year13 99.122,    year14 76.463,    year15 13.939,    year16 64.332,    year17 16.792,    year18 25.758
year19 67.224,    year20 44.100,    year21 36.610,    year22 35.793,    year23 14.018,    year24 15.860
year25 59.322,    year26 83.258,    year27 23.851,    year28 66.908,    year29 77.810,    year30 31.062
year31 11.939,    year32 50.736,    year33 16.857,    year34 87.374,    year35 27.246,    year36 29.296
year37 59.802,    year38 72.549,    year39 63.197,    year40 46.916,    year41 41.917,    year42 12.652
year43 32.107,    year44  5.609,    year45 34.516,    year46 19.028,    year47 64.927,    year48 56.514
year49 77.226,    year50 30.483


----     30 PARAMETER meanbounds  

               lo          up

mean1      10.000      20.000
mean2      30.000      40.000
mean3      50.000      60.000


----     30 PARAMETER cvbounds  

             lo          up

cv1       0.500       0.700
cv2       0.900       0.950


----     30 PARAMETER K                    =       30.000  number to select

Модель MINLP:

enter image description here

В основном модель выполняет три действия:

  1. выбирает 30 точек (через x(i) переменные)
  2. выбирает один интервал для среднего (через xm(k1))
  3. выберите один интервал для CV (через xcv(k2))

Некоторые результаты:

----     74 VARIABLE x.L  select points

year1  1,    year2  1,    year3  1,    year4  1,    year5  1,    year6  1,    year7  1,    year9  1,    year10 1
year12 1,    year16 1,    year17 1,    year18 1,    year20 1,    year21 1,    year22 1,    year23 1,    year24 1
year27 1,    year30 1,    year32 1,    year33 1,    year35 1,    year37 1,    year40 1,    year42 1,    year43 1
year44 1,    year46 1,    year48 1


----     74 VARIABLE mu.L                  =       34.321  mean
            VARIABLE sigma.L               =       18.843  stdev
            VARIABLE cv.L                  =        0.549  coeff of variation

----     74 VARIABLE xm.L  select mean interval

mean2 1


----     74 VARIABLE xcv.L  select CV interval

cv1 1

Я решил это с помощью Baron .По крайней мере, с этим набором данных этот подход, кажется, работает.Поскольку нет цели, это в основном проблема осуществимости.Решатель Constraint Programming также может работать (хотя большинство из них имеют ограниченную поддержку переменных с плавающей запятой).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...