Laskuoperaatiot NumPy-taulukoilla

Luodaan ensin uusi taulukko (yksiulotteinen vektori):

import numpy as np

v1 = np.arange(100, 1001, 100)
# v1 on array([ 100,  200,  300,  400,  500,  600,  700,  800,  900, 1000])

NumPy-taulukoiden ja yksittäisten lukuarvojen laskuoperaatiot onnistuvat suoraviivaisesti. NumPy suorittaa laskuoperaation jokaiselle alkiolle:

v2 = v1 + 1    # array([ 101,  201,  301,  401,  501,  601,  701,  801,  901, 1001])
v3 = v1 * 2    # array([ 200,  400,  600,  800, 1000, 1200, 1400, 1600, 1800, 2000])
v4 = v1 / 100  # array([  1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.])
v42 = 100 / v1 # array([ 1.,  0.5,  0.33333333, 0.25,  0.2, 0.16666667, 0.14285714, 0.125, 0.11111111, 0.1]) 

NumPy-taulukoita voi myos lisätä, kertoa ja jakaa keskenään. Operaatiot tehdaan alkioittain, joten taulukoiden tulee olla samankokoisia!

v5 = v2 + v2  # array([ 202,  402,  602,  802, 1002, 1202, 1402, 1602, 1802, 2002])
v6 = v4 * v4  # array([   1.,    4.,    9.,   16.,   25.,   36.,   49.,   64.,   81.,  100.])
v7 = v3 / v1  # array([ 2.,  2.,  2.,  2.,  2.,  2.,  2.,  2.,  2.,  2.])

Seuraavassa esimerkissä matriisin M sarakkeiden määrä (4) täsmää vektorin a pituuden (4) kanssa. Jokainen rivivektori kerrotaan alkioittain vektorilla a:

M = np.array([[1, 2, 3, 4],
              [5, 6, 7, 8],
              [9, 10, 11, 12]])
a = np.array([1, 2, 3, 4])
tulo = M * a
# Ensimmäinen rivi on siis [1*1, 2*2, 3*3, 4*4]
# array([[ 1,  4,  9, 16],
#        [ 5, 12, 21, 32],
#        [ 9, 20, 33, 48]])

Huomaa, että esimerkin kertolasku M * a on aivan eri asia kuin oikea matriisitulo! Siitä lisää seuraavassa luvussa.

Laskutoimitukset ilman silmukoita

Tarkastellaan esimerkin avulla, kuinka NumPy-taulukoiden kanssa toimitaan listoihin verrattuna. Aiemmin olemme oppineet, kuinka kahdesta listasta lasketaan tuloksia kolmanteen:

massat      = [2.2,    4.1,   5.6,    1.2,     6.7]
moolimassat = [18.015, 58.44, 74.55, 81.408, 144.645]
ainemaarat = []
for massa, moolimassa in zip(massat, moolimassat):
    ainemaarat.append(massa / moolimassa)

NumPyllä for-silmukkaa ei tarvita:

import numpy as np
massat      = np.array([2.2,    4.1,   5.6,    1.2,     6.7])
moolimassat = np.array([18.015, 58.44, 74.55, 81.408, 144.645])
ainemaarat_np = massat / moolimassat

NumPy jakaa siis taulukon massat jokaisen alkion taulukon moolimassat vastaavalla alkiolla ja lopputulos on uusi taulukko ainemaarat.

Molemmissa tapauksissa lasketut ainemäärät ovat samat. Mutta Numpyn tapa on merkittävästi nopeampi, varsinkin kun kyseessä on vähänkin isompi datamäärä. NumPyn lähestymistapaa kutsutaan vektoroinniksi.

Laajempi esimerkki

Toteutetaan funktio ainemaara NumPy-taulukoiden avulla:

import numpy as np

def ainemaara(m, M):
    # m, M: massa (g) ja moolimassa (g/mol)
    # Kukin parametri voi olla joko NumPy-taulukko tai yksittäinen luku
    # Oletetaan, että kaikki parametrit ovat kelvollisia lukuarvoja
    # Paluuarvo: ainemäärä(t)
    # Jos yksikin parametri on NumPy-taulukko, paluuarvo on NumPy-taulukko 
    return m / M

# Luodaan kolmen alkiota sisältävät taulukot massoista ja moolimassoista
massat = np.array([3.2, 0.5, 2.2])
moolimassat = np.array([58.44, 42.394, 120.921])
                      # NaCl   LiCl    RbCl
# Lasketaan ja tulostetaan ainemäärät. Funktio palauttaa taulukon.
n1 = ainemaara(massat, moolimassat)
print(n1)

# Funktio toimii myös yksittäisillä lukuarvoilla
# Tässä tapauksessa funktio palauttaa yksittäisen liukuluvun
n2 = ainemaara(3.2, 58.44)
print(n2)

# Funktio toimii myös jos toinen parametri on yksittäinen luku ja toinen taulukko
# Tässä tapauksessa funktio palauttaa taulukon
n3 = ainemaara(3.2, moolimassat)
print(n3)

tulostaa

[0.05475702 0.01179412 0.0181937 ]
0.05475701574264203
[0.05475702 0.07548238 0.02646356]

Tehtävä 4.4.1