zoukankan      html  css  js  c++  java
  • numpyarrays

    numpy-arrays

    Arrays

    Arrays in numpy

    • have elements all of the same type and occupy the same amount of storage, an element can be composed of other simple types,
    • have a fixed size (cannot grow like lists),
    • have a shape specified with a tuple, the tuple gives the size of each dimension,
    • are indexed by integers.

    A numpy array is very similar to arrays in static languages like C , Fortran, and Java. Arrays in numpy are multi-dimensional. Operation are arrays are, in general, faster than lists. Why?

    Python meets APL.

    Creating arrays

    Arrays can be created with python sequences or initialized with constant values of 0 or 1, or uninitialized. Some of the array element types are byte, int, float, complex, uint8, uint16, uint64, int8, int16, int32, int64, float32, float64, float96, complex64, complex128, and complex192.

    >>> from numpy import *
    >>> zeros( (12), dtype=int8 )
    array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int8)
    >>> zeros( (2,6), dtype=int16 )
    array([[0, 0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0, 0]], dtype=int16)
    >>> ones( (6,2), dtype=int32 )
    array([[1, 1],
           [1, 1],
           [1, 1],
           [1, 1],
           [1, 1],
           [1, 1]])
    >>> ones( (2,2,3), dtype=int64 )
    array([[[1, 1, 1],
            [1, 1, 1]],
    
           [[1, 1, 1],
            [1, 1, 1]]], dtype=int64)
    >>> a = ones( (2,3,2) )
    >>> a.dtype # type of each element
    dtype('float64')
    >>> a.ndim  # number of dimension
    3
    >>> a.shape # tuple of dimension sizes
    (2, 3, 2)
    >>> a.size # total number of elements
    12
    >>> a.itemsize # number of bytes of storage per element
    8
    >>> array( [ [1,2,3], [4,5,6] ] )
    array([[1, 2, 3],
           [4, 5, 6]])
    >>> a = _
    >>> a.dtype
    dtype('int32')
    >>> a.shape
    (2, 3)
    >>> array( range(7), float )
    array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.])
    >>> array( [ [ int(i != j) for j in xrange(3)] for i in xrange(4)] )
    array([[0, 1, 1],
           [1, 0, 1],
           [1, 1, 0],
           [1, 1, 1]])
    >>> _.shape
    (4, 3)
    >>> empty( (2,3), dtype=int16) # uninitialized, what advantage
    array([[  344, 20318, -4920],
           [ 2644,    16,     0]], dtype=int16)
    >>> 
    

    Reshaping arrays

    Arrays in numpy can be reshaped. The reshaped array must be the same size. Why?

    >>> from numpy import *
    >>> a = array( range(12) ) # equivalent to arange( 12, dtype=int)
    >>> a
    array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
    >>> a.shape 
    (12,)
    >>> b = a.reshape(2, 6) # b still refers to a's memory
    >>> a.shape
    (12,)
    >>> b.shape
    (2, 6)
    >>> a[6] = 106 # access 7th element
    >>> b # changes in a are reflected in b
    array([[  0,   1,   2,   3,   4,   5],
           [106,   7,   8,   9,  10,  11]])
    >>> a
    array([  0,   1,   2,   3,   4,   5, 106,   7,   8,   9,  10,  11])
    >>> b[1,0] = 6 # changes in b are reflected in a
    >>> b
    array([[ 0,  1,  2,  3,  4,  5],
           [ 6,  7,  8,  9, 10, 11]])
    >>> a
    array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
    >>> c = b.transpose() # swaps the indices order
    >>> c.shape
    (6, 2)
    >>> b[1,4]
    10
    >>> c[4,1]
    10
    >>> 
    

    Indexing and slicing arrays

    Arrays are indexed with comma separated list of indices. Unlike list, slices do not copy the array, but provide another view into the same data.

    >>> from numpy import *
    >>> t = array( range(24), uint8 ) # unsigned 8 bit integer
    >>> t 
    array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
           17, 18, 19, 20, 21, 22, 23], dtype=uint8)
    >>> t = t.reshape(2,3,4)
    >>> t
    array([[[ 0,  1,  2,  3],
            [ 4,  5,  6,  7],
            [ 8,  9, 10, 11]],
    
           [[12, 13, 14, 15],
            [16, 17, 18, 19],
            [20, 21, 22, 23]]], dtype=uint8)
    >>> t[0,0,0] # index = i*(3*4) + j*4 + k
    0
    >>> t[1,1,1]
    17
    >>> t[1,2,3] # the last index advances serially
    23
    >>> # the transpose reverse the order of the indices
    >>> s = t.transpose()
    >>> s.shape
    (4, 3, 2)
    >>> s[3,2,1] # index i + j*4 + k*(3*4)
    23
    >>> s[0,1,0]
    4
    >>> s[0,0,1] # the first index advances serially
    12
    >>> t1 = t[1,2] # partial indices return slices
    >>> t1
    array([20, 21, 22, 23], dtype=uint8)
    >>> t1.shape
    (4,)
    >>> t1[0] = 100 # in numpy a slice is similar to a reshape
    >>> t           # t1 references the same array
    array([[[  0,   1,   2,   3],
            [  4,   5,   6,   7],
            [  8,   9,  10,  11]],
    
           [[ 12,  13,  14,  15],
            [ 16,  17,  18,  19],
            [100,  21,  22,  23]]], dtype=uint8)
    >>> t = array( range(24), uint8 ) ; t = t.reshape(2,3,4) # reset
    >>> t[0,1]
    array([4, 5, 6, 7], dtype=uint8)
    >>> t[0,1] = 200 # assignment to slices changes all elements
    >>> t
    array([[[  0,   1,   2,   3],
            [200, 200, 200, 200],
            [  8,   9,  10,  11]],
    
           [[ 12,  13,  14,  15],
            [ 16,  17,  18,  19],
            [ 20,  21,  22,  23]]], dtype=uint8)
    >>> 
    

    Multi-dimensional indexing

    More than one dimension can be indexed.

    >>> from numpy import *
    >>> z = zeros((5,5),int); z # 5 x 5 integers
    array([[0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0]])
    >>> z[0] = 1; z # first row
    array([[1, 1, 1, 1, 1],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0]])
    >>> z[:,0] = 2; z # first column
    array([[2, 1, 1, 1, 1],
           [2, 0, 0, 0, 0],
           [2, 0, 0, 0, 0],
           [2, 0, 0, 0, 0],
           [2, 0, 0, 0, 0]])
    >>> z[2:4,2:5] = 3; z # (2,3) block
    array([[2, 1, 1, 1, 1],
           [2, 0, 0, 0, 0],
           [2, 0, 3, 3, 3],
           [2, 0, 3, 3, 3],
           [2, 0, 0, 0, 0]])
    >>> z[:,-1] = 4; z # last column
    array([[2, 1, 1, 1, 4],
           [2, 0, 0, 0, 4],
           [2, 0, 3, 3, 4],
           [2, 0, 3, 3, 4],
           [2, 0, 0, 0, 4]])
    >>> z[-1,:] = 5; z # last row
    array([[2, 1, 1, 1, 4],
           [2, 0, 0, 0, 4],
           [2, 0, 3, 3, 4],
           [2, 0, 3, 3, 4],
           [5, 5, 5, 5, 5]])
    >>> 
    

    arithmetic, vector and matrix operation

    The standard math operators can be used with numpy arrays. Matrix operations are also defined.

    >>> from numpy import *
    >>> i = identity( 3, int16 )
    >>> i
    array([[1, 0, 0],
           [0, 1, 0],
           [0, 0, 1]], dtype=int16)
    >>> i + i # add element to element
    array([[2, 0, 0],
           [0, 2, 0],
           [0, 0, 2]], dtype=int16)
    >>> i + 4 # add a scalar to every entry
    array([[5, 4, 4],
           [4, 5, 4],
           [4, 4, 5]], dtype=int16)
    >>> a = array( range(1,10), int16 ) # equiv to arange(1,10,dtype=int16):w
    >>> a = a.reshape(3,3)
    >>> i * a # element to element
    array([[1, 0, 0],
           [0, 5, 0],
           [0, 0, 9]], dtype=int16)
    >>> x = array( [1,2,3], int32 )
    >>> x
    array([1, 2, 3])
    >>> y = array( [ [4], [5], [6] ], int32 )
    >>> y
    array([[4],
           [5],
           [6]])
    >>> x + y
    array([[5, 6, 7],
           [6, 7, 8],
           [7, 8, 9]])
    >>> array([4]) + array([1,2,3]) # one element with three
    array([5, 6, 7])
    >>> # 1 and 2d arrays can be turned into matrices with mat()
    >>> # matrices redefine * to be dot
    >>> mx = mat(x)
    >>> mx.shape
    (1, 3)
    >>> my = mat(y)
    >>> my.shape
    (3, 1)
    >>> mx * my
    matrix([[32]])
    >>> my * mx
    matrix([[ 4,  8, 12],
            [ 5, 10, 15],
            [ 6, 12, 18]])
    >>> 
    

    Relational operators

    Relational operators are also defined for numpy arrays. An array of booleans is returned.

    >>> from numpy import *
    >>> a = array([3,6,8,9])
    >>> a == 6
    array([False,  True, False, False], dtype=bool)
    >>> a >= 7
    array([False, False,  True,  True], dtype=bool)
    >>> a < 5
    array([ True, False, False, False], dtype=bool)
    >>> # count all the even numbers
    >>> sum( (a%2) == 0 )
    2
    >>> b = array([2,6,7,10])
    >>> a == b
    array([False,  True, False, False], dtype=bool)
    >>> a < b
    array([False, False, False,  True], dtype=bool)
    >>> # any is true if any value is true
    >>> any( a == 3 )
    True
    >>> any( a == 10 )
    False
    >>> # all is true if all values are true
    >>> a == a
    array([ True,  True,  True,  True], dtype=bool)
    >>> all( a == a )
    True
    >>> all( a != b )
    False
    >>> 
    

    Indexing with boolean arrays

    In addition to slices, a numpy array can be indexed with an equivalently shaped boolean array (i.e., their shape are the same).

    >>> from numpy import *
    >>> a = arange(1, 13).reshape(3,4); a
    array([[ 1,  2,  3,  4],
           [ 5,  6,  7,  8],
           [ 9, 10, 11, 12]])
    >>> i1 = (a % 2) == 1; i1 # odd entries
    array([[ True, False,  True, False],
           [ True, False,  True, False],
           [ True, False,  True, False]], dtype=bool)
    >>> a[ i1 ] # select all the odd entries
    array([ 1,  3,  5,  7,  9, 11])
    >>> i2 = (a >= 1) & (a < 4) ; i2 # and
    array([[ True,  True,  True, False],
           [False, False, False, False],
           [False, False, False, False]], dtype=bool)
    >>> a[ i2 ] # values greater than or equal to 1 and less than 4
    array([1, 2, 3])
    >>> 
    

    Math functions

    Most of the math functions can be used with numpy arrays. These functions are actually redefined. Some of the redefined math functions are: arccos, arcsin, arctan, arctan2, ceil, cos, cosh, degrees, exp, fabs, floor, fmod, frexp, hypot, ldexp, log, log10, modf, pow, radians, sin, sinh, sqrt, tan, and tanh.

    >>> from numpy import *
    >>> t = linspace(0, pi, 7) # 7 values linearly between 0 and pi
    >>> sin(t)
    array([  0.00000000e+00,   5.00000000e-01,   8.66025404e-01,
             1.00000000e+00,   8.66025404e-01,   5.00000000e-01,
             1.22460635e-16])
    >>> arcsin( sin( t ) )
    array([  0.00000000e+00,   5.23598776e-01,   1.04719755e+00,
             1.57079633e+00,   1.04719755e+00,   5.23598776e-01,
             1.22460635e-16])
    >>> floor( t )
    array([ 0.,  0.,  1.,  1.,  2.,  2.,  3.])
    >>> log( t + 1 ) # adding 1 avoids log(0)
    array([ 0.        ,  0.42107515,  0.71647181,  0.94421571,  1.12959244,
            1.28591969,  1.42108041])
    >>> 
    

    array to scalar operators

    numpy also defines operators that reduce the number of elements. These operators are: max, mean, min, std, sum, var.

    >>> from numpy import *
    >>> s = random.standard_normal( 10 ) # mu = 0.0 sigma = 1.0
    >>> s.shape
    (10,)
    >>> s
    array([ 0.65711932, -1.19741536,  1.51470124,  0.60134355,  1.44631555,
            1.25936877, -1.347354  ,  0.33819449,  0.35765847,  0.84350667])
    >>> s.max() # all elements
    1.51470124183
    >>> s.min()
    -1.34735399976
    >>> s.sum()  # sum of all elements
    4.47343871645
    >>> s.prod() # product of all elements
    0.179456818521
    >>> s.mean()
    0.447343871645
    >>> s.std() # square root of variance
    0.946962388091
    >>> s.var() # variance 
    0.896737764459
    >>> 
    

    The operator can also select an axis (direction) for grouping the elements to be operated on.

    >>> from numpy import *
    >>> a = array( [[4, -9, 5, 7], [100, -100, 50, 21], [20, 40, 0, 11]] )
    >>> a
    array([[   4,   -9,    5,    7],
           [ 100, -100,   50,   21],
           [  20,   40,    0,   11]])
    >>> a.max()
    100
    >>> a.min()
    -100
    >>> a.sum()
    149
    >>> a.min(0) # along the columns, varies last index
    array([   4, -100,    0,    7])
    >>> a.max(0) # along the columns 
    array([100,  40,  50,  21])
    >>> a.sum(0) # along the columns
    array([124, -69,  55,  39])
    >>> a.min(1) # along the rows, varies first index
    array([  -9, -100,    0])
    >>> a.max(1) # along the rows
    array([  7, 100,  40])
    >>> a.sum(1) # along the rows
    array([ 7, 71, 71])
    >>> 
    

    polynomials

    Polynomials are supported by numpy. Some examples are:

    >>> from numpy import *
    >>> p1 = poly1d([2.0,1.0]) # 2*x + 1, using coefficients
    >>> print p1
     
    2 x + 1
    >>> # using the polynomials roots
    >>> p1a = poly1d([-0.5],r=1) # p1(-0.5) = 0
    >>> print p1a
     
    1 x + 0.5
    >>> # quadratic with roots (x-5)(x-3)
    >>> p2 = poly1d( [5.0, 3.0], r=1 )
    >>> print p2
       2
    1 x - 8 x + 15
    >>> # polynomials can be multiplied
    >>> p3 = poly1d([1.0,-5]) * poly1d([1.0,3.0])
    >>> print p3
       2
    1 x - 2 x - 15
    >>> # or added
    >>> poly1d([1.0,-5]) + poly1d([1.0,3.0])
    poly1d([ 2., -2.])
    >>> # or subtracted
    >>> poly1d([3.0,1.0,-5]) - poly1d([1.0,3.0])
    poly1d([ 3.,  0., -8.])
    >>> # or division with remainder
    >>> quot, rem =  poly1d([3.0,1.0,-5]) /  poly1d([1.0,3.0])
    >>> print quot
     
    3 x - 8
    >>> print rem
     
    19
    >>> # polynomials can be evaluated
    >>> p3(-3)
    0.0
    >>> p3(5)
    0.0
    >>> p3(1)
    -16.0
    >>> # the polynomials roots are given by
    >>> p3.r
    array([ 5., -3.])
    >>> # its coefficients
    >>> p3.c
    array([  1.,  -2., -15.])
    >>> # its order
    >>> p3.o
    2
    >>> # the first derivative
    >>> print p3.deriv()
     
    2 x - 2
    >>> print p3.deriv(1)
     
    2 x - 2
    >>> # the second derivative
    >>> print p3.deriv(2)
     
    2
    >>> 
    

    Course record

    The students records for a course is stored in the following csv file.

    course.csv

    Name, Assignments, Midterm1, Midterm2, Final
    A Student, 80, 65, 72, 74 
    B Student, 75, 52, 62, 64
    C Student, 100, 70, 80, 80
    D Student, 94, 45, 65, 55
    

    The weights for the term work, midterm 1, midterm 2, and the final is 10, 20, 20, and 50.

    Course report

    A report giving statistics on each work product, and the student's course grade is generated by:

    course_report.py

    #!/usr/bin/env python
    from numpy import *
    import csv
    
    # get head and names
    f = file( 'course.csv' )
    reader = csv.reader( f )
    headings = reader.next()
    # get student names
    students = []
    for row in reader :
        students.append( row[0] )
    f.close()
    
    # get workproducts, skipping name column
    f = file( 'course.csv' )
    wps = loadtxt( f, delimiter=",",
                    usecols=(1,2,3,4), skiprows=1 )
    f.close()
    
    # value of each workproduct item
    value = array( [10., 20., 20., 50.] )
    # report final mark
    print 'Course mark'
    marks = [] # save the marks
    for i, name in enumerate( students ) :
        mark = dot( value, wps[i]/100.0 )
        marks.append( mark )
        print "%-20s: %5.1f" % (name, mark)
    
    marks = array( marks ) # convert to array
    
    print "\n"*4
    print 'Statistics'
    # report on statistics of each workproduct
    wp_names = headings[1:]
    for i, w in enumerate( wp_names ) :
        print w.strip()
        print '    minimum %6.2f' %  wps[:,i].min()
        print '    maximum %6.2f' %  wps[:,i].max()
        print '       mean %6.2f' %  wps[:,i].mean()
        print '        std %6.2f' %  wps[:,i].std()
    
    # generated histogram of As, Bs, Cs, Ds, Fs
    bins = array([0.0, 49.5, 54.5, 64.5, 79.5, 100.0] ) # F,D,C,B,A
    N,bins = histogram(marks,bins)
    
    N = list(N) # convert to list
    N.reverse()
    N.pop( 0 ) # discard overflow, XXX could check
    for letter,n in zip( "ABCDF", N) :
        print letter, n
    

    The produced report is:

    Command:
    python course_report.py
    
    Output:
    Course mark
    A Student           :  72.4
    B Student           :  62.3
    C Student           :  80.0
    D Student           :  58.9
    
    
    
    
    
    Statistics
    Assignments
        minimum  75.00
        maximum 100.00
           mean  87.25
            std  10.13
    Midterm1
        minimum  45.00
        maximum  70.00
           mean  58.00
            std   9.97
    Midterm2
        minimum  62.00
        maximum  80.00
           mean  69.75
            std   6.94
    Final
        minimum  55.00
        maximum  80.00
           mean  68.25
            std   9.55
    A 1
    B 1
    C 2
    D 0
    F 0
    

    Conway's game of life

    The games consists of an infinite board composed of a grid of squares. Each square can contain a zero or a one. Each square has eight neighbours, the next square connected either horizontally, vertically, or on a diagonal. Give a board configuration, the next configuration is determined by:

    • A square with a 1 and fewer than two neighbours with a 1 is set to 0.
    • A square with a 1 and more than three neighbours with a 1 is set to 0.
    • A square with a 1 and two or three neighbours with a 1, remains set to 0.
    • A square with a 0, and exactly three neighbours with a 1 is set to a 0.

    Conway's game of life in numpy

    Conway's game can be easily implemented with numpy's array operations. A bounded implementation (i.e., the board is not infinite) where the borders are always zero is realized by:

    simple_life.py

    #!/usr/bin/env python
    from numpy import *
    
    # compute next generation of conway's game of life
    def next_generation( current, next ) :
        next[:,:] = 0 # zero out next board
        # bound examination area
        bend0 = (current.shape[0]-3)+1
        bend1 = (current.shape[1]-3)+1
        for i in xrange( bend0 ) :
            for j in xrange( bend1 ) :
                neighbours = sum( current[i:i+3, j:j+3] )
                if current[i+1, j+1] == 1 :
                    neighbours -= 1 # do not count yourself
                    if 2 <= neighbours <= 3 :
                        next[i+1, j+1] = 1
                else:
                    if neighbours == 3 :
                        next[i+1,j+1] = 1
    
    board = zeros( (5,5), uint8)
    next_board = zeros_like( board ) # same shape
    
    # create inital configuration
    board[2,1:4] = 1 # 3 squares 
    
    for i in xrange(4) :
        next_generation( board, next_board )
        board, next_board = next_board, board # swap boards
        print board[1:-1,1:-1]
    

    Four generation of this configuration yeilds:

    Command:
    python simple_life.py
    
    Output:
    [[0 1 0]
     [0 1 0]
     [0 1 0]]
    [[0 0 0]
     [1 1 1]
     [0 0 0]]
    [[0 1 0]
     [0 1 0]
     [0 1 0]]
    [[0 0 0]
     [1 1 1]
     [0 0 0]]
    

    Game of life with user input

    An input string of ones and zeros can be used to initialize the board. This version is identical to the previous version with the exception of the command line arguments.

    life.py

    #!/usr/bin/env python
    from numpy import *
    import sys
    import math
    
    # compute next generation of conway's game of life
    def next_generation( current, next ) :
        next[:,:] = 0 # zero out next board
        # bound examination area
        bend0 = (current.shape[0]-3)+1
        bend1 = (current.shape[1]-3)+1
        for i in xrange( bend0 ) :
            for j in xrange( bend1 ) :
                neighbours = sum( current[i:i+3, j:j+3] )
                if current[i+1, j+1] == 1 :
                    neighbours -= 1 # do not count yourself
                    if 2 <= neighbours <= 3 :
                        next[i+1, j+1] = 1
                else:
                    if neighbours == 3 :
                        next[i+1,j+1] = 1
    
    if len(sys.argv) != 3 :
        print "usage:", sys.argv[0], "init-board generations"
        sys.exit( 1 )
    
    init = sys.argv[1]
    generations = int( sys.argv[2] )
    
    board_sz = math.ceil( math.sqrt(len(init)) ) 
    
    # board_sz+2 includes the border of zeros
    board = zeros( (board_sz+2,board_sz+2), uint8)
    next_board = zeros_like( board ) # same shape
    
    # fill the board
    i = 0
    j = 0
    for index,ch in enumerate(init) :
        if ch == '1' :
            board[i+1,j+1] = 1
        j = (j+1) % board_sz
        if ((index+1) % board_sz) == 0 : i += 1
    
    for gen in xrange(generations) :
        next_generation( board, next_board )
        board, next_board = next_board, board # swap boards
        print board[1:-1,1:-1] # do not print the border
    

    Solving 2 unknowns with 2 linear equations

    >>> from numpy import *
    >>> from numpy.linalg import solve
    >>> 
    >>> # 1 * x0 - 2 * x1 = 1
    >>> # 2 * x0 - 6 * x1 = -2
    >>> a = array( [[1,-2], [2,-6]] )
    >>> b = array( [1, -2 ] )
    >>> x = solve( a, b ); x
    array([ 5.,  2.])
    >>> dot( a, x ) # check solution
    array([ 1., -2.])
    >>> 
    

    Solving 2 unknowns with 2 linear equations (2)

    >>> from numpy import *
    >>> from numpy.linalg import solve
    >>> 
    >>> # 1 * x0 - 2 * x1 = 1
    >>> # 2 * x0 - 4 * x1 = 2
    >>> # any problems with the above equations
    >>> a = array( [[1,-2], [2,-4]] )
    >>> b = array( [1, 2 ] )
    >>> x = solve( a, b )
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
      File "/usr/lib/python2.5/site-packages/numpy/linalg/linalg.py", line 184, in solve
        raise LinAlgError, 'Singular matrix'
    LinAlgError: Singular matrix
    >>> 
    

    Solving 3 unknowns with 3 linear equations

    >>> from numpy import *
    >>> from numpy.linalg import solve
    >>> from numpy.linalg import inv
    >>> 
    >>> # 1 * x0 - 2 * x1 + 5 * x2 = 1
    >>> # 2 * x0 - 6 * x1 - 10 *x2 = -2
    >>> #-4 * x0 + 1 * x1 + 3 * x2 = 3
    >>> a = array( [[1, -2, 5], [2,-6,-10], [-4,1,3] ] )
    >>> b = array( [1, -2, 3 ] )
    >>> x = solve( a, b ); x
    array([-0.64516129, -0.25806452,  0.22580645])
    >>> dot( a, x ) # check solution
    array([ 1., -2.,  3.])
    >>> 
    >>> # a * x = b
    >>> # inv(a) * a * x = inv(a) * b
    >>> # I * x = inv(a) * b
    >>> # x = inv(a) * b
    >>> x = dot( inv(a), b ); x
    array([-0.64516129, -0.25806452,  0.22580645])
    >>> # the identity
    >>> dot( inv(a), a)
    array([[  1.00000000e+00,   5.55111512e-17,   2.77555756e-17],
           [ -2.77555756e-17,   1.00000000e+00,   1.24900090e-16],
           [  6.93889390e-18,  -1.90819582e-17,   1.00000000e+00]])
    >>> dot( a, inv(a))
    array([[  1.00000000e+00,   5.55111512e-17,   1.56125113e-17],
           [ -2.77555756e-17,   1.00000000e+00,   5.20417043e-17],
           [  1.38777878e-17,   1.38777878e-17,   1.00000000e+00]])
    >>> 
    

    2D line segment intersection

    Many geometric problems are solved using vector notation. Intesection of lines can be solved with:

    lines.py

    #
    # line segment intersection using vectors
    # see Computer Graphics by F.S. Hill
    #
    from numpy import *
    def perp( a ) :
        b = empty_like(a)
        b[0] = -a[1]
        b[1] = a[0]
        return b
    
    # line segment a given by endpoints a1, a2
    # line segment b given by endpoints b1, b2
    # return 
    def seg_intersect(a1,a2, b1,b2) :
        da = a2-a1
        db = b2-b1
        dp = a1-b1
        dap = perp(da)
        denom = dot( dap, db)
        num = dot( dap, dp )
        return (num / denom)*db + b1
    
    p1 = array( [0.0, 0.0] )
    p2 = array( [1.0, 0.0] )
    
    p3 = array( [4.0, -5.0] )
    p4 = array( [4.0, 2.0] )
    
    print seg_intersect( p1,p2, p3,p4)
    
    p1 = array( [2.0, 2.0] )
    p2 = array( [4.0, 3.0] )
    
    p3 = array( [6.0, 0.0] )
    p4 = array( [6.0, 3.0] )
    
    print seg_intersect( p1,p2, p3,p4)
    

    Its sample execution is:

    Command:
    python lines.py
    
    Output:
    [ 4.  0.]
    [ 6.  4.]
    

    Points on circle "without" sin/cos

    All the points around a circle can be generated with matrix operations. Multiplication is usually cheaper than calculationg sin or cos.

    circle.py

    from numpy import *
    import math
    
    # sin/cos just once
    a = math.cos( math.radians(-30.0) )
    b = math.sin( math.radians(-30.0) )
    
    # rotation matrix, 30 degrees clockwise
    R = mat( [[a, -b], [b, a]] )
    v = mat( [1,0] )   # unit vector along x-axis
    
    print "Repeated rotations by 30"
    # rotate (1,0) by 30 degree increments
    for i in xrange(12) :
        nv = v * R
        vx,vy = v.T  # transpose
        x = math.cos( math.radians(30.0 * i ) )
        y = math.sin( math.radians(30.0 * i ) )
        print "%12.9f %12.9f -- %12.9f %12.9f" % (vx,vy, x,y)
        v = nv
    print
    
    print "Rotation by multiples of 30"
    # rotate (1,0) by 30, 60, 90, ...
    for i in xrange(12) :
        r = v * pow(R,i)
        vx,vy = r.T  # transpose
        x = math.cos( math.radians(30.0 * i ) )
        y = math.sin( math.radians(30.0 * i ) )
        print "%12.9f %12.9f -- %12.9f %12.9f" % (vx,vy, x,y)
    

    The points are:

    Command:
    python circle.py
    
    Output:
    Repeated rotations by 30
     1.000000000  0.000000000 --  1.000000000  0.000000000
     0.866025404  0.500000000 --  0.866025404  0.500000000
     0.500000000  0.866025404 --  0.500000000  0.866025404
     0.000000000  1.000000000 --  0.000000000  1.000000000
    -0.500000000  0.866025404 -- -0.500000000  0.866025404
    -0.866025404  0.500000000 -- -0.866025404  0.500000000
    -1.000000000  0.000000000 -- -1.000000000  0.000000000
    -0.866025404 -0.500000000 -- -0.866025404 -0.500000000
    -0.500000000 -0.866025404 -- -0.500000000 -0.866025404
    -0.000000000 -1.000000000 -- -0.000000000 -1.000000000
     0.500000000 -0.866025404 --  0.500000000 -0.866025404
     0.866025404 -0.500000000 --  0.866025404 -0.500000000
    
    Rotation by multiples of 30
     1.000000000 -0.000000000 --  1.000000000  0.000000000
     0.866025404  0.500000000 --  0.866025404  0.500000000
     0.500000000  0.866025404 --  0.500000000  0.866025404
     0.000000000  1.000000000 --  0.000000000  1.000000000
    -0.500000000  0.866025404 -- -0.500000000  0.866025404
    -0.866025404  0.500000000 -- -0.866025404  0.500000000
    -1.000000000  0.000000000 -- -1.000000000  0.000000000
    -0.866025404 -0.500000000 -- -0.866025404 -0.500000000
    -0.500000000 -0.866025404 -- -0.500000000 -0.866025404
    -0.000000000 -1.000000000 -- -0.000000000 -1.000000000
     0.500000000 -0.866025404 --  0.500000000 -0.866025404
     0.866025404 -0.500000000 --  0.866025404 -0.500000000
  • 相关阅读:
    【转】VC 线程间通信的三种方式
    【转】MFC对话框和控件
    美国政府、部门构成及其运作
    贝叶斯推理(Bayes Reasoning)、独立与因式分解
    贝叶斯推理(Bayes Reasoning)、独立与因式分解
    机器学习:利用卷积神经网络实现图像风格迁移 (三)
    TBB、OpenCV混合编程
    VS编译环境中TBB配置和C++中lambda表达式
    概率图模型(PGM) —— 贝叶斯网络(Bayesian Network)
    概率图模型(PGM) —— 贝叶斯网络(Bayesian Network)
  • 原文地址:https://www.cnblogs.com/lexus/p/2808454.html
Copyright © 2011-2022 走看看