Compound assignment operators in Python's NumPy library
Ben,

The following modification to your code is a more accurate reflection of my larger problem:



    from timeit import timeit
    import numpy

    # Dimensions
    ROWS = 10000000
    SAMPLES = 10000
    COLS = 4

    # Number of times to run timeit
    TEST_COUNT = 100 

    # Matrices
    a = numpy.zeros((ROWS, COLS), dtype='uint32')
    b = numpy.zeros((ROWS, COLS), dtype='uint32')
    c = numpy.zeros((ROWS, COLS), dtype='uint32')

    # Indices
    i = numpy.random.random_integers(0, ROWS - 1, SAMPLES)
    j = numpy.random.random_integers(0, COLS - 1, SAMPLES)

    # Fancy
    def fancy():
        a[i,j] += 1
    print "Fancy:", timeit("fancy()", setup="from __main__ import fancy", number=TEST_COUNT)

    # Loop
    def loop():
        for k in xrange(SAMPLES):
            b[i[k],j[k]] += 1
    print "Loop:", timeit("loop()", setup="from __main__ import loop", number=TEST_COUNT)

    # Flat
    def flat():
        flatIndices = i*COLS + j
        sums = numpy.bincount(flatIndices)
        c.flat[:len(sums)] += sums

    print "Flat:", timeit("flat()", setup="from __main__ import flat", number=TEST_COUNT)

    # Check that for_loop and custom are equivalent
    print "Equivalent:", (c == b).all()



With the exception that there are probably few samples that are actually repeated in this version. Let's ignore that difference for now. On my machine, your code gave the following timings:



    Fancy: 0.109203100204
    Loop: 7.37937998772
    Flat: 126.571173906
    Equivalent: True



This slowdown is largely attributable to the large sparse array output by bincount().