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) & (begin == True) & (end == False): boundary_two = ( x - 1 ) inside = False end = True elif (array[y][x] != 0) & (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!
-
\$\begingroup\$ Welcome to Code Review! Does the code function correctly? If not, it isn't ready for review (see help center) and the question may be deleted. If you've tested it, I recommend that you edit to add a summary of the testing (ideally as reproducible unit-test code), and update the title to simply state the task accomplished by the code, which is the Code Review standard for titles (suggestion: "Centre all columns of an array"). \$\endgroup\$Toby Speight– Toby Speight2018年10月04日 15:03:13 +00:00Commented Oct 4, 2018 at 15:03
-
\$\begingroup\$ Thanks a lot ! I've changed the title and added the fact that the code is working. \$\endgroup\$spooktober– spooktober2018年10月04日 15:12:47 +00:00Commented Oct 4, 2018 at 15:12
-
1\$\begingroup\$ In your example, why is the second row rearranged so that 0.618 comes first? \$\endgroup\$200_success– 200_success2018年10月04日 17:46:26 +00:00Commented Oct 4, 2018 at 17:46
-
\$\begingroup\$ It isn't suppose to come out like that, i corrected it. Thanks for the question. \$\endgroup\$spooktober– spooktober2018年10月05日 07:17:44 +00:00Commented Oct 5, 2018 at 7:17
1 Answer 1
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 &
(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)])
-
\$\begingroup\$ Wow, I can express how incredibly simple your solution is...Thanks a lot !! I'm taking my time to process all the new functions i didn't knew about. \$\endgroup\$spooktober– spooktober2018年10月08日 15:26:29 +00:00Commented Oct 8, 2018 at 15:26
-
\$\begingroup\$ when used correctly, python can be very elegant \$\endgroup\$Maarten Fabré– Maarten Fabré2018年10月08日 16:13:39 +00:00Commented Oct 8, 2018 at 16:13