[Python] Hulp nodig bij optimaliseren code

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • Daiov97
  • Registratie: Augustus 2012
  • Laatst online: 22:57
Voor een project ben ik bezig met Python. Helaas heb ik niet heel veel kennis hierin, waardoor ik bepaalde dingen op een inefficiënte manier doe. Met als gevolg dat mijn code veel te lang aan het draaien is, wat normaal gezien geen probleem is, maar wel als je een bepaalde functie heel vaak aan wil roepen...

Ik heb onderstaande functie gemaakt:

code:
1
2
3
4
5
6
7
8
9
10
11
def CalculateNewFillRate(item, basestock):
    FR = []
    for month in range(12):
        ltdarray = item.LTD[month-1][item.LTD[month][:,0] <= basestock] #only keep values where ltd is lower than basestock
        totalsum = 0
        for n in ltdarray:
            demandarray = item.demand[month-1][item.demand[month][:,0] <= basestock - n[0]] #keep values where part of demand can be fulfilled
            sumofn = np.sum((demandarray[:,0] - basestock + n[0]) * demandarray[:,1]) # get the sum of n
            totalsum += (sumofn + basestock - n[0]) * n[1] #add this to totalsum   
        FR.append(totalsum)
    return FR


Deze code wordt per loop vervolgens zo'n 600 keer aangeroepen, wat +/- 2 sec duurt. Echter is deze loop ook weer onderdeel van een andere loop, waardoor de running time te hoog is om de code te kunnen gebruiken.

Googlen op internet levert mij al op dat nparrays niet bedoeld zijn om over te loopen. En dan helemaal niet als dat een gigantisch grote array is. Het weghalen van de binnenste loop (dmv vectorization) heeft mij al een mooie tijdswinst opgeleverd, maar ik zie niet hoe ik van de buitenste loop af kan komen (en al helemaal niet van de maandloop, maar ik denk dat hier minder tijdwinst in zit).

Ik zie geen oplossing aangezien 'demandarray' veranderd per waarde van n (deze array wordt namelijk kleiner als n[0] groter wordt). Heeft iemand hier toevallig een idee hoe ik dit op kan lossen?

[ Voor 6% gewijzigd door Daiov97 op 30-06-2021 18:26 ]

Alle reacties


Acties:
  • 0 Henk 'm!

  • Brilsmurfffje
  • Registratie: December 2007
  • Niet online

Brilsmurfffje

Parttime Prutser

Begin eerst een met opschrijven wat voor doel je wilt bereiken. Soms ben je helemaal in het begin al van start gegaan met een foute aanpak

Acties:
  • 0 Henk 'm!

  • ValHallASW
  • Registratie: Februari 2003
  • Niet online
Een beschrijving van je datamodel zou ook een hoop helpen -- waar bestaat een 'item' uit, wat is de shape van bv de LTD en demand elementen, etc.


Twee tips op basis van de code zoals je die hier gepost hebt:

In plaats van arrays te filteren kan je ook elementen vervangen met een 'null'-element


Dit heeft als voordeel dat je geen forloop meer nodig hebt door de verschillende 'vorm' van elke rij.

Vergelijk:
code:
1
2
3
4
5
array = np.array([[1,2,3],[2,3,4],[3,4,5]])
sum = 0
for row in array:
  filtered = row[row > 2]  # in eerste iteratie 1 element, daarna 2, ...
  sum += np.sum(filtered)

met
code:
1
2
3
4
array = np.array([[1,2,3],[2,3,4],[3,4,5]])
kopie = array.copy()
kopie[kopie <= 2] = 0  # 0 is het identity/null element voor sommatie. Vergeet niet (zoals ik) je logica om te keren!
sum = np.sum(kopie)



Een forloop over een array kan je in veel gevallen vervangen met hoger-dimensionale arrays



Vergelijk:
code:
1
2
3
4
5
6
array1 = np.array([1,2,3])
array2 = np.array([4,5,6])

sum = 0
for el in array1:
  sum += np.sum(array2 - el)

met
code:
1
2
3
4
array1 = np.array([1,2,3])
array2 = np.array([4,5,6])

sum = np.sum(array2 - el[:, np.newaxis])

[ Voor 9% gewijzigd door ValHallASW op 30-06-2021 20:04 ]


Acties:
  • 0 Henk 'm!

  • Daiov97
  • Registratie: Augustus 2012
  • Laatst online: 22:57
Dank beide. Het was inderdaad handiger geweest als ik een foto van een item had gepost als voorbeeld.

N.a.v. de tips van @ValHallASW heb ik de loop eruit kunnen halen. Echter is de performance verbetering minder dan ik had verwacht. Ik heb bovenstaande code uiteindelijk d.m.v. numba kunnen compilen, waardoor één run ongeveer 0.3 seconde duurt. Met numpy functies kom ik nu op ongeveer 0.7 seconde uit per loop. Wat ik nu inderdaad doe is het maken van een 2D array, waarbij bepaalde waarden naar 0 worden gezet. Zo kan ik vervolgens np.multiply gebruiken voor de gehele array.

Nieuwe code:
code:
1
2
3
4
5
6
7
8
9
10
11
def CalculateNewFillRate2(item, basestock):
    FR = []
    EX, demand, LTD = item.EX, item.demand, item.LTD
    for month in range(12):
        LTDarray = LTD[month][LTD[month][:,0] <= basestock]
        2Darray = demand[month][:,0] - basestock + LTDarray[:,0][:, np.newaxis]
        2Darray [2Darray > 0] = 0
        sumofcolumn = np.sum((np.multiply(2Darray,demand[month][:,1])),axis=1)
        totalsum = np.sum(np.multiply(sumofcolumn + basestock - LTDarray[:,0],LTDarray[:,1]))
        FR.append(totalsum)
    return FR


D.m.v. het compilen wordt al een C#-achtige performance behaald. Dit is dus hetzelfde als wat de np.array bewerkingen doen (blijkbaar zelfs sneller dus)

[ Voor 3% gewijzigd door Daiov97 op 02-07-2021 16:45 ]