Centre all columns of an array I have this working code tested over lots of np.arrays. It is a for-loop that walks through all the values of a np.array (x,y).

For each y-row, it finds the first x-column for which the value is different to zero. Afterward, it finds the last x-column for which value is different to 0.

Then all the columns between first x-column and last x-column are centred.

This is then repeated for all y-rows.
Example:

#Input :
array([[ 0.0,  0.149,  0.064, 0.736,  0.0],
       [ 0.0,  0.0,  0.258,   0.979,  0.618 ],
       [ 0.0,  0.0,  0.0,     0.786,  0.666],
       [ 0.0,  0.0,  0.0,     0.782,  0.954],

 #Output :
array([[ 0.0,  0.149, 0.064, 0.736, 0.0],
       [ 0.0,  0.258, 0.979, 0.618, 0.0],
       [ 0.0,  0.786, 0.666, 0.0,   0.0],
       [ 0.0,  0.782, 0.954, 0.0,   0.0],


Also:


Not all the values between first and last columns are different than zero.

for y in range(len(array)):

    begin = False
    inside = False
    end = False

    for x in range(len(array[0])):


        if (array[y][x] == 0) &amp; (begin == True) &amp; (end == False):
            boundary_two = ( x - 1 )
            inside = False
            end = True

        elif (array[y][x] != 0) &amp; (inside == False):
            boundary_one = x
            begin = True
            inside = True

    y_position.append(y)
    m = np.split(array[y],[boundary_one,boundary_two])
    zeros = len(array[0])-len(m[1])
    array[y] = np.concatenate((np.zeros(zeros//2),m[1],np.zeros(int(np.ceil(zeros/2)))))



Furthermore, I added a variable(count) inside the function (which I erase for the upper code example, to simplify lecture) which count how many empty rows since last non empty rows. When count ==10, we break out of the loop. This is to save time. Once we have +/- 10 empty rows after the non-empty ones, it is sure all other y-rows will be empty as well.

Finally, I must save the value for the last y-row non-empty.

This is my script most time demanding calculation, so I was wondering if there is a way of to improve it, either by making it clearer and/or faster.

Thanks a lot, hope it is clear!
review

comparison

no need to compare against True or False. (begin == True) can be easier expressed as begin and (end == False) as not end. and comparison chaining is done with and, not &amp;(bitwise and)

iteration

In python, it is very seldomly needed to iterate over the indices. Instead of for y in range(len(array)): and for x in range(len(array[0])), you can do

for row in array:
    ...
    for x, element in enumerate(row):
        if element == 0 and begin and not end:


alternative solution

try to vectorise as much as possible. The easiest thing to do is count the zeroes in front and at the back:

def count_zeroes(array):
    return (array.cumsum(axis=1) == 0).sum(axis=1)

zeroes_front = count_zeroes(array)


and then the same for the reverse:

zeroes_back = count_zeroes(test_data[:,::-1])


The amount each row needs to roll is:

roll = (zeroes_front + zeroes_back) //2 - zeroes_front



array([ 0, -1, -2, -2])



and then you apply this roll over each row:

np.array([np.roll(row, r) for row, r in zip(test_data, roll)])



array([[0.   , 0.149, 0.064, 0.736, 0.   ],
       [0.   , 0.258, 0.979, 0.618, 0.   ],
       [0.   , 0.786, 0.666, 0.   , 0.   ],
       [0.   , 0.782, 0.954, 0.   , 0.   ]])



in total:

def centre(array):
    zeroes_front = count_zeroes(array)
    zeroes_back = count_zeroes(array[:,::-1])
    roll = (zeroes_front + zeroes_back) //2 - zeroes_front
    return np.array([np.roll(row, r) for row, r in zip(array, roll)])