numpy group rows from large array

If the final order of the rows is not important:

# sort by first and second column
a = utl[np.lexsort((utl[:,1], utl[:,0]))]

# get positions of group change
# as we want the max, we take the last row per group
_, idx = np.unique(a[:,0], return_index=True)
idx2 = (idx-1)%a.shape[0]  # or idx2 = np.r_[idx[1:]-1, [a.shape[0]-1]]

# split
a[idx2]

output:

array([[21, 0.02],
       [26, 0.04],
       [34, 0.09]])
solution for the min
a = utl[np.lexsort((utl[:,1], utl[:,0]))]
_, idx = np.unique(a[:,0], return_index=True)
a[idx]

If you use np.lexsort, you can get the maximum by index:

sort_idx = np.lexsort(utl.T[::-1])

The differences in the sorted first column are going to tell you which index to grab from the second:

max_idx = np.r_[np.flatnonzero(np.diff(utl[idx, 0])), len(idx) - 1]
min_idx = np.r_[0, np.flatnonzero(np.diff(utl[idx, 0])) + 1]

The results can be extracted immediately:

minima = utl[idx[min_idx], 1]
maxima = utl[idx[max_idx], 1]