2016-05-19 1 views
2

У меня есть структура вложенного цикла, чтобы сгенерировать большое количество backtests, изменяя значение 4 переменных oq, aq, lev и val. Идея состоит в том, чтобы выполнить каждую комбинацию переменных ниже в пределах указанных диапазонов.условное вложенное для цикла выполнение кода, даже если условие не выполнено

Без ограничения этот цикл, таким образом, будет выполняться в сумме 5 * 6 * 5 * 5 = 750 раз, что на ~ 5-10 секунд каждый займет несколько часов. Однако существует ограничение, которое состоит в том, что все веса должны составлять ровно 1 (tot_wgt). Добавив оператор if, я надеялся просто отказаться от таких случаев.

if (tot_wgt != 1): 
    continue 

К сожалению, код по-прежнему кажется, выполнить иногда, когда tot_wgt не имеет значения 1. Это, кажется, происходит каждый раз, когда цикл вала завершил цикл (и, предположительно, также происходит, когда каждый из других 3 петли завершили цикл).

Проблема решена: у меня была ошибка с отступом: мне нужно быть на уровне инструкции if. Но см. Отличный ответ на распознавание чисел с плавающей запятой.

mom = 0 
for oq in [0.3, 0.4, 0.5, 0.6, 0.7]: 
    for aq in [0.05, 0.1, 0.15, 0.2, 0.25, 0.3]: 
     for lev in [0.0, 0.05, 0.1, 0.15, 0.2]: 
      for val in [0.0, 0.05, 0.1, 0.15, 0.2]: 

       tot_wgt = oq + aq + lev + val + mom 

       if (tot_wgt != 1): #we only want to backtest where the weights add up to 1. If <1 or >1, simply skip 
        continue 


<MAIN BACKTEST CODE HERE> 

ответ

4

Это связано с ограничениями представления чисел с плавающей запятой в компьютерном оборудовании в качестве базовых 2 (двоичных) фракций. Обратитесь к Floating Point Arithmetic: Issues and Limitations за подробным описанием.

Например, в вашем случае,

>>> 0.7 + 0.2 + 0.0 + 0.1 + 0 
0.9999999999999999 

# more specific 
>>> from decimal import Decimal 
>>> Decimal(0.7 + 0.2 + 0.0 + 0.1 + 0) 
Decimal('0.99999999999999988897769753748434595763683319091796875') 

Как вы можете видеть, это не equvelent к 1. Один простой способ решить это является просто заменить строку if (tot_wgt != 1): с,

if abs(tot_wgt - 1) < 0.0001 : 

Python 3.5 добавляет math.isclose для проверки приблизительного равенства. Для более ранней версии эквивалентная функция выглядит следующим образом.

def isclose(a, b, rel_tol=1e-09, abs_tol=0.0): 
    return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol) 

Используйте numpy.isclose, чтобы проверить, если два массива поэлементно равны в пределах допуска.

# Usage 
numpy.isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False) 

# An example 
>>> import numpy as np 
>>> np.isclose([1e10,1e-7], [1.00001e10,1e-8]) 
array([True, False]) 
+1

Спасибо. Да, я думал, что это тоже может быть проблемой, ваше решение элегантно. – Carl