Próbuję zoptymalizować funkcję celu, która ma wiele zmiennych wejściowych (od 24 do 30). Zmienne te są próbkami trzech różnych zmiennych statystycznych, a wartości funkcji celu są wartościami prawdopodobieństwa testu t-Studenta. Funkcja błędu reprezentuje błąd (suma kwadratów różnic) między pożądanymi a rzeczywistymi prawdopodobieństwami testu t. Mogę zaakceptować rozwiązania, w których błąd jest mniejszy niż 1e-8, dla wszystkich trzech testów t.jak zminimalizować funkcję z dyskretnymi wartościami zmiennych w scipy
Używałem scipy.optimize.fmin
i działało świetnie. Istnieje wiele rozwiązań, w których funkcja docelowa stała się równa zero.
Problem polega na tym, że muszę znaleźć rozwiązanie, w którym zmienne mają wartość od 0 do 10,0 i są liczbami całkowitymi lub nie zawierają więcej niż jednej części ułamkowej. Przykłady poprawnych wartości to 0 10 3 5.5 6.8
. Przykłady nieprawidłowych wartości: -3 2.23 30
lub 0.16666667
.
Zdaję sobie sprawę, że istnieje przynajmniej jedno rozwiązanie, ponieważ wartości docelowe pochodzą z rzeczywistych zmierzonych danych. Pierwotne dane zostały utracone, a moim zadaniem jest je znaleźć. Ale nie wiem jak. Korzystanie z wersji próbnej/błędu nie jest opcją, ponieważ istnieje około 100 możliwych wartości dla każdej zmiennej, a biorąc pod uwagę liczbę zmiennych, liczba możliwych przypadków wynosi 100 ** 30, która jest zbyt duża. Używanie fmin jest świetne, ale nie działa z dyskretnymi wartościami.
Czy istnieje sposób rozwiązania tego problemu? Nie stanowi to problemu, jeśli potrzebuję uruchomić program przez wiele godzin, aby znaleźć rozwiązanie. Ale potrzebuję znaleźć rozwiązania dla około 10 wartości docelowych w ciągu kilku dni, a ja nie mam nowych pomysłów.
Oto przykład MWE:
import math
import numpy
import scipy.optimize
import scipy.stats
import sys
def log(s):
sys.stdout.write(str(s))
sys.stdout.flush()
# List of target T values: TAB, TCA, TCB
TARGETS = numpy.array([
[0.05456834, 0.01510358, 0.15223353 ], # task 1 to solve
[0.15891875, 0.0083665, 0.00040262 ], # task 2 to solve
])
MAX_ERR = 1e-10 # Maximum error in T values
NMIN,NMAX = 8,10 # Number of samples for T probes. Inclusive.
def fsq(x, t, n):
"""Returns the differences between the target and the actual values."""
a,b,c = x[0:n],x[n:2*n],x[2*n:3*n]
results = numpy.array([
scipy.stats.ttest_rel(a,b)[1], # ab
scipy.stats.ttest_rel(c,a)[1], # ca
scipy.stats.ttest_rel(c,b)[1] # cb
])
# Sum of squares of diffs
return (results - t)
def f(x, t, n):
"""This is the target function that needs to be minimized."""
return (fsq(x,t,n)**2).sum()
def main():
for tidx,t in enumerate(TARGETS):
print "============================================="
print "Target %d/%d"%(tidx+1,len(TARGETS))
for n in range(NMIN,NMAX+1):
log(" => n=%s "%n)
successful = False
tries = 0
factor = 0.1
while not successful:
x0 = numpy.random.random(3*n) * factor
x = scipy.optimize.fmin(f,x0, [t,n], xtol=MAX_ERR, ftol=MAX_ERR)
diffs = fsq(x,t,n)
successful = (numpy.abs(diffs)<MAX_ERR).all()
if successful:
log(" OK, error=[%s,%s,%s]\n"%(diffs[0],diffs[1],diffs[2]))
print " SOLUTION FOUND "
print x
else:
tries += 1
log(" FAILED, tries=%d\n"%tries)
print diffs
factor += 0.1
if tries>5:
print "!!!!!!!!!!!! GIVING UP !!!!!!!!!!!"
break
if __name__ == "__main__":
main()
Opcja 'scipy.optimize.fmin' wykorzystuje algorytm Nelder-Mead, realizacja scipy tego jest w funkcji' _minimize_neldermead' w pliku 'optimize.py'. Można wziąć kopię tej funkcji i przepisać go zaokrąglić zmiany do zmiennych ('' X ... z szybkiej kontroli funkcji) do wartości chcesz (między 0 i 10 z jedną dziesiętną), gdy funkcja zmienia je. (Sukces nie jest gwarantowany) –
Zgodnie z twoim pomysłem, najlepsze, co mogłem zrobić, to różnica 1e-5 dla każdej wartości testu t. Potrzebuję trochę lepiej: 1e-8. Wciąż działa program w trybie próbnym. Może znaleźć lepsze rozwiązanie. – nagylzs