In [81]: array1 = np.array([
...: ['*0.70*', '21.59', '4.37', '21.70'],
...: ['2.15', '21.42', '5.63', '22.33'],
...: ['*8.00*', '21.17', '5.11', '22.40'],
...: ['2.36', '22.88', '*2.54*', '*20.95*'],
...: ['2.07', '22.64', '6.68', '22.26']
...: ])
The char test returns a boolean array:
In [84]: mask = np.char.endswith(array1,"*")
In [85]: mask
Out[85]:
array([[ True, False, False, False],
[False, False, False, False],
[ True, False, False, False],
[False, False, True, True],
[False, False, False, False]])
np.nonzero (aka np.where) finds the coordinates of the True values, one array per dimension:
In [86]: np.nonzero(mask)
Out[86]: (array([0, 2, 3, 3]), array([0, 0, 2, 3]))
If you want to delete the rows, the first array can be used (duplicate 3 apparently doesn't bother delete):
In [88]: np.delete(array1, np.nonzero(mask)[0], 0)
Out[88]:
array([['2.15', '21.42', '5.63', '22.33'],
['2.07', '22.64', '6.68', '22.26']], dtype='<U7')
But we can also find rows with any True with:
In [89]: mask.any(axis=1)
Out[89]: array([ True, False, True, True, False])
and use that to select those rows (boolean array indexing)
In [91]: array1[mask.any(axis=1)]
Out[91]:
array([['*0.70*', '21.59', '4.37', '21.70'],
['*8.00*', '21.17', '5.11', '22.40'],
['2.36', '22.88', '*2.54*', '*20.95*']], dtype='<U7')
or select their not:
In [92]: array1[~mask.any(axis=1)]
Out[92]:
array([['2.15', '21.42', '5.63', '22.33'],
['2.07', '22.64', '6.68', '22.26']], dtype='<U7')
np.nonzero(Out[89]) is (array([0, 2, 3]),), the desired delete rows.
Other answers have used the Python list version of transpose; numpy's own transpose works as well:
In [93]: np.argwhere(mask)
Out[93]:
array([[0, 0],
[2, 0],
[3, 2],
[3, 3]])
In [94]: np.transpose(np.nonzero(mask))
Out[94]:
array([[0, 0],
[2, 0],
[3, 2],
[3, 3]])
For the purpose of deleting rows this transpose isn't any more useful than the where.