Komme i gang med NumPy og SciPy

Sat 22 March 2014

I denne posten skal jeg skrive noen korte setninger om hva NumPy / SciPy er, og hvordan du kan komme igang med det. Planen er at det skal komme flere poster på dette temaet etterhvert.

Hva er NumPy?

NumPy er en python utvidelse / bibliotek som gir tilgang til matriser og multidimensjonelle tabeller. Biblioteket gir deg også tilgang til funksjoner for å utføre lineær algebra, fourier transjormasjoner og generering av pseudotilfeldige tall.

NumPy bruker Linear Algebra PACage (LAPACK) biblioteket for å implementere funksjonaliteten som er tilgjengelig. Dersom du ikke har dette biblioteket installert fra før følger det med en versjon når du installerer NumPy. LAPACK biblioteket er mye brukt innenfor lineær algebra, blant annet av programmene Matlab, R, Maple og Octave.

  • NumPy er opensource, og vært i utvikling siden 2006.
  • Store deler av NumPy er skrevet i C som gjør at det er raskere en vanlig Python.

Du kan finne installasjonsfiler for NumPy her: http://sourceforge.net/projects/numpy/files/NumPy/

, men som jeg skal vise etterhvert er det veldig vanlig å installere NumPy som en del av en større “Scientific Computing” pakke. Du vil da installere NumPy som en del av en samling andre relaterte verktøy.

Hva er SciPy?

SciPy er et bibliotek som inneholder funksjoner, algoritmer og verktøy for manipulering av NumPy objekter. Der hvor NumPy er begrenset til numeriske operasjoner får man med SciPy en større “Scientific computing” verktøykasse.

SciPy er også et utviklingsmiljø, som inneholder blant annet SciPy og NumPy bibliotekene, i tillegg til ipython, matplotlib, pandas med mer. Jeg forholder meg til utviklingsmiljøet SciPy, og ikke bare biblioteket.

SciPy bruker de multidimensjonelle tabellene fra NumPy som datastruktur, og implementerer en egen generisk variant av de forskjellige metodene (lineær algebra, fourier transjormasjoner og generering av pseudorandom tall) som vi også har i NumPy. I tillegg er det mange metoder i SciPy som ikke finnes i NumPy.

Eksempler på fagfelt som kan ha nytte av å bruke SciPy

  • lineær algebra
  • signalprosessering
  • datainnsamling
  • beregeningsorientert geometri

Du kan finne installasjonsfiler for SciPy her: http://sourceforge.net/projects/scipy/files/scipy/

, men også for SciPy vil jeg anbefale at man installerer hele samlingen av programmer og verktøy via en distribusjon.

All in one installasjon

Som jeg nevnt over anbefaler jeg å installere numpy og scipy via en distribusjon. De fleste distribusjoner er "last ned og kjør installer”, og så er du igang. Her er link til tre varianter som har installasjonsfiler for Mac, Linux og Windows plattformen.

  • Anaconda: http://continuum.io/downloads.html
  • Entought: https://www.enthought.com/downloads/
  • Algorete Loopy: http://algorete.org

Du finner flere all-in-one scipy varianter på: http://www.scipy.org/install.html

Vis meg noe kode!

Om du har lest første del av teksten så vet du nå hva numpy / scipy dreier seg om, samt hvordan du skal gå frem for å få installert det.

{codecitation style="brush: python;"}

# -*- coding: utf-8 -*-

# ~/anaconda/lib/python2.7/site-packages/spyderlib/scientific_startup.py

import numpy as np

class Numpyrunner(object):

def add(self, x, y):

number_types = (int, long, float, complex)

if isinstance(x, number_types) and isinstance(y, number_types):

return x+y

else:

raise ValueError

def pythonsum(self, n):

a = range(n)

b = range(n)

c = []

for i in range(len(a)):

a[i] = i ** 2

b[i] = i ** 2

c.append(a[i] + b[i])

print c

return c

def numpysum(self, n):

a = np.arange(n) ** 2

b = np.arange(n) ** 2

c = a + b

print c

return c.tolist()

I koden over utfører vi vektoraddisjon uten, og med, NumPy. Vi skriver også ut resultatet i begge tilfellene. Det jeg har lyst å bruke kodesnutten over til er å kontrollere to ting:

  • At begge metodene gir samme resultat.
  • At den ene metoden er mer effektiv (raskere) en den andre.

{codecitation style="brush: python;"}

### Testing goes here ###

from datetime import datetime

import unittest

from numpyrunner import Numpyrunner

class NumpyTestClass(unittest.TestCase):

def setUp(self):

self.numper = Numpyrunner()

def test_numpyrunner_add_method_return_correct_result(self):

result = self.numper.add(2, 2)

self.assertEqual(4, result)

def test_numpyrunner_add_method_return_error_if_argument_not_numbers(self):

self.assertRaises(ValueError, self.numper.add, 'two', 'three')

def test_numpyrunner_pythonsum_return_correct_result(self):

result = self.numper.pythonsum(4)

self.assertEqual([0, 2, 8, 18], result)

def test_numpyrunner_numpysum_return_correct_result(self):

result = self.numper.numpysum(4)

self.assertEqual([0, 2, 8, 18], result)

def test_numpyrunner_sum_equal(self):

res1 = self.numper.pythonsum(100)

res2 = self.numper.numpysum(100)

self.assertEqual(res1, res2)

def test_numpyrunner_time_differ(self):

start = datetime.now()

res1 = self.numper.pythonsum(10000)

delta1 = datetime.now() - start

print "\nElapsed time in ms with pythonsum: ", delta1.microseconds

start = datetime.now()

res2 = self.numper.numpysum(10000)

delta2 = datetime.now() - start

print "Elapsed time in ms with numpysum: ", delta2.microseconds

self.assertGreater(delta1, delta2)

def main():

unittest.main()

#We can run our test by issuing: python numpyrunner_test.py

#If we have nosetests available we can issue: nosetests numpyrunner_test.py -sv

if __name__ == "__main__":

main()

Jeg velger å gjøre testene mine i form av unittester.Du kan lese mer om unittester i posten Introduksjon til testdreven programmering med python.

På forhånd regner jeg ut forventet resultat når n=4 ([0, 2, 8, 18]), og kjører så summeringen i begge metodene med n=4, og kontrollerer resultatet opp mot forventet resultat.

Det neste jeg gjør er å sjekke at begge metodene gir samme svar. Her regner jeg ikke ut noe på forhånd, men sjekker at begge metodene returnerer samme svar for samme verdi (n=100) inn.

Til slutt sjekker jeg tiden det tar for begge metodene beregne et svar for en viss input verdi (n=1000). Som nevnt tidligere i posten så går jeg utifra at NumPy er raskere en vanlig Python, og legger derfor assertGreater for å verifisere denne påstanden.

$ python numpyrunner_test.py
.....
Elapsed time in ms with pythonsum: 5870
Elapsed time in ms with numpysum: 253
.
----------------------------------------------------------------------
Ran 6 tests in 0.008s

OK

For de som ikke er kjent med unittesting så har vi altså kjørt alle de seks testene vi hadde definert, og alle var ok. Vi har altså verifisert alle punktene vi ønsket å teste.

  • Begge metodene gir riktig svar for n=4
  • Begge metodene gir samme svar for n=100
  • Tiden det tar å summere med vanlig Python er lenger en om vi bruker NumPy

Som en ekstra bonus har vi også fått ut hvor stor forskjellen i tid faktisk er (5870 - 253) = 5597 ms.

Oppsummering

Du har nå fått installert NumPy og Scipy, samt kjørt noe kode sånn at du faktisk ser at det fungerer. Dette er en god start, og forhåpentligvis får vi gjort mer etterhvert.

Vi har nå i praksis skaffet oss en tabell som er mye mer effektiv en standard Python tabeller. Dette vil gi oss en fordel i alle situasjoner der vi bruker tabeller.

  • sortering
  • søk
  • matriseoperasjoner
  • bildebehandling
  • + + +

Jeg anbefaler også å ta en titt på matplotlib for for plotting i 2-dimensjoner, og mayavi for plotting i 3-dimensjoner.

Referanser

http://en.wikipedia.org/wiki/NumPy

http://en.wikipedia.org/wiki/SciPy

http://www.scipy.org

http://en.wikipedia.org/wiki/LAPACK

Comments