Če nalogo "oluščimo" zgodbice, je takšna: imamo seznam števil in zanima nas koliko je števil, ki jim sledi večje število. Števila so podana v datoteki, po eno število na vrstico. Preberimo jih v tabelo.
import numpy as np
= np.array([int(x) for x in open("example.txt")]) globine
numpy
ima tudi nekaj funkcij za branje datotek. Ena od
njih je loadtxt
, ki zna prebrati podatke v točno takšni
obliki (in še kakšni malo bolj zapleteni, tudi).
= np.loadtxt("example.txt", dtype=int) globine
Tako ali drugače dobimo tabelo. Videti je tako.
globine
array([199, 200, 208, 210, 200, 207, 240, 269, 260, 263])
Če bi programirali brez numpy
-ja, bi naredili tole:
= 0
stej for x, y in zip(globine[1:], globine):
if x > y:
+= 1
stej print(stej)
7
Ali pa kar (ker je True
praktično enak 1
in
False
enak 0
):
= 0
stej for x, y in zip(globine[1:], globine):
+= x > y
stej print(stej)
7
Ali pa celo
sum(x > y for x, y in zip(globine[1:], globine))
7
Praktično isto bomo naredili v numpy
-ju. Bistvo
numpy
-ja pa je v tem, da se trudimo, da za nobeno ceno ne
bi napisali zanke. Zanka se mora zgoditi v numpy
-ju.
Namesto seštevanja v Pythonovi zanki, moramo seštevati dve tabeli v
numpyju. Namesto primerjanja v zanki, moramo primerjati v numpyju. V
bistvu nas zanima tole:
1:] > globine globine[
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
/var/folders/f9/lgq5ysmn24j3lkss6zkgmtr00000gn/T/ipykernel_20647/372271466.py in <module>
----> 1 globine[1:] > globine
ValueError: operands could not be broadcast together with shapes (9,) (10,)
Numpy se pritoži, da tabeli nimata enako elementov. Numpy ni zip, popariti mora vse elemente. Zipa ni motilo, da je drugi seznam za en element daljši (zadnjega elementa pač ne primerjamo z nobenih elementom za njim) in ga je preprosto ignoriral. Numpy tega ne more: tabeli, ki ju sešteva, odšteva, množi, primerja ... morata biti enako dolgi. Zadnji element moramo odbiti sami.
1:] > globine[:-1] globine[
array([ True, True, True, False, True, True, True, False, True])
To, odbijanje zadnjega ali prvega elementa je nekaj, kar bomo morali stalno početi (in se bomo pri tem pogosto tudi ušteli za kak element ali dva).
Tako kot prej, v čistem Pythonu, tudi tu vsak True
predstavlja par elementov, pri katerem je bil drugi večji od prvega. In
tako kot prej jih moramo tudi zdaj sešteti, le da ne bomo poklicali
sum
, temveč np.sum
. Sicer bi delal tudi
sum
, a np.sum
je za numpyjeve tabele veliko
hitrejši.
sum(globine[1:] > globine[:-1]) np.
7
Drugi del pravi, da moramo namesto posamičnih globin opazovati vsote po treh zaporednih globin.
Naloge se najprej lotimo naivno, sestavimo seznam vsot trojk. Čisto tako, za vajo.
Sešteti moramo naslednje tri tabele.
-2] globine[:
array([199, 200, 208, 210, 200, 207, 240, 269])
1:-1] globine[
array([200, 208, 210, 200, 207, 240, 269, 260])
2:] globine[
array([208, 210, 200, 207, 240, 269, 260, 263])
Enkrat smo odbili zadnja dva elementa, enkrat prvega in zadnjega, enkrat prva dva.
Te tri torej seštejemo.
= globine[:-2] + globine[1:-1] + globine[2:] vsote
vsote
array([607, 618, 618, 617, 647, 716, 769, 792])
Naprej pa gre tako kot prej.
sum(vsote[1:] > vsote[:-1]) np.
5
Kakšna je pravzaprav razlika med dvema zaporednima trojkama? Kdaj je vsota, recimo, petega, šestega in sedmega elementa večja od vsote četrtega, petega in šestega? Glede na to, da peti in šesti element nastopata v obeh trojkah, bo prva trojka večja od druge, kadar je sedmi element večji od četrtega. Drugi del naloge je torej v bistvu enak prvemu, le da namesto parov zaporednih elementov primerjamo pare, katerih indeksi se razlikujejo za 3.
sum(globine[3:] > globine[:-3]) np.
5
Ta rešitev je seveda boljša od naivne, le o numpyju nas nauči manj. No, nekaj pa le: malo smo utrdili odbijanje elementov. Če odbijemo tri na začetku, moramo v drugem tri na koncu, da bosta spet enako velika.