I might just write s[s != 0].index[-1]
, e.g.
>>> s = pd.Series([0, 1, 2, 3, 0, 4, 0], index = range(7, 14)) >>> s 7 0 8 1 9 2 10 3 11 0 12 4 13 0 dtype: int64 >>> s[s != 0].index[-1] 12
Originally I thought using nonzero
would make things simpler, but the best I could come up with was
>>> s.index[s.nonzero()[0][-1]]
12
A couple of ways it with generator:
max(i for i in s.index if s[i] != 0) # will work only if index is sorted
and
next(i for i in s.index[::-1] if s[i] != 0)
Through numpy's trip_zeros
:
import numpy as np
np.trim_zeros(s, 'b').index[-1]
Return the integer indices of the elements that are non-zero.,This method is equivalent to calling numpy.nonzero on the series data. For compatibility with NumPy, the return value is the same (a tuple with an array of indices for each dimension), but it will always be a one-item tuple because series only have one dimension.,Indices of elements that are non-zero.,Deprecated since version 0.24.0: Please use .to_numpy().nonzero() as a replacement.
>>> s = pd.Series([0, 3, 0, 4]) >>> s.nonzero() (array([1, 3]), ) >>> s.iloc[s.nonzero()[0]] 1 3 3 4 dtype: int64
>>> s = pd.Series([0, 3, 0, 4], index = ['a', 'b', 'c', 'd']) # same return although index of s is different >>> s.nonzero() (array([1, 3]), ) >>> s.iloc[s.nonzero()[0]] b 3 d 4 dtype: int64
Last Updated : 30 Sep, 2019
Output:
(array([0, 2, 3, 5, 6, 8, 9]), )
0 1
2 12
3 1
5 4
6 22
8 3
9 9
dtype: int64
Returns a tuple of arrays, one for each dimension of a, containing the indices of the non-zero elements in that dimension. The values in a are always tested and returned in row-major, C-style order.,To group the indices by element, rather than dimension, use argwhere, which returns a row for each non-zero element.,Return indices that are non-zero in the flattened version of the input array.,Return the indices of the elements that are non-zero.
>>> x = np.array([ [3, 0, 0], [0, 4, 0], [5, 6, 0] ]) >>> x array([ [3, 0, 0], [0, 4, 0], [5, 6, 0] ]) >>> np.nonzero(x) (array([0, 1, 2, 2]), array([0, 1, 0, 1]))
>>> x[np.nonzero(x)] array([3, 4, 5, 6]) >>> np.transpose(np.nonzero(x)) array([ [0, 0], [1, 1], [2, 0], [2, 1] ])
>>> a = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]) >>> a > 3 array([ [False, False, False], [True, True, True], [True, True, True] ]) >>> np.nonzero(a > 3) (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))
>>> a[np.nonzero(a > 3)]
array([4, 5, 6, 7, 8, 9]) >>>
a[a > 3] # prefer this spelling
array([4, 5, 6, 7, 8, 9])
>>> (a > 3).nonzero()
(array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))
Deprecated since version 0.24.0: Please use .to_numpy().nonzero() as a replacement.,Return the integer indices of the elements that are non-zero.,This method is equivalent to calling numpy.nonzero on the series data. For compatibility with NumPy, the return value is the same (a tuple with an array of indices for each dimension), but it will always be a one-item tuple because series only have one dimension.,Indices of elements that are non-zero.
Examples
>>> s = pd.Series([0, 3, 0, 4]) >>> s.nonzero() (array([1, 3]), ) >>> s.iloc[s.nonzero()[0]] 1 3 3 4 dtype: int64
>>> s = pd.Series([0, 3, 0, 4]) >>> s.nonzero() (array([1, 3]),) >>> s.iloc[s.nonzero()[0]] 1 3 3 4 dtype: int64
>>> s = pd.Series([0, 3, 0, 4], index = ['a', 'b', 'c', 'd']) # same return although index of s is different >>> s.nonzero() (array([1, 3]), ) >>> s.iloc[s.nonzero()[0]] b 3 d 4 dtype: int64
👻 See our latest reviews to choose the best laptop for Machine Learning and Deep learning tasks! , Pandas Series.nonzero() — it is a method with no arguments. As the name suggests, by returning non-zero values ‚Äã‚Äãfrom a series, it returns the index of all non-zero values. The returned series of indexes can be passed to the method iloc () to return all nonzero values ‚Äã‚Äãat those indices. , As shown in the output, the index position of each nonzero element was returned, and the values ‚Äã‚Äãin this positions were returned by the iloc method. , 👻 Read also: what is the best laptop for engineering students in 2022?
Exit:
(array([0, 2, 3, 5, 6, 8, 9]), ) 0 1 2 12 3 1 5 4 6 22 8 3 9 9 dtype: int64
Identify the first & last non-zero elements/indices within a group in numpy,Identify first & last non-zero elements within a group in numpy,Identify first non-zero element within a group in pandas,Identify first non-zero element within group composed of multiple columns in pandas
group = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2]) array = np.array([1, 2, 3, 0, 0, 2, 0, 3, 4, 0, 0, 0, 0, 1]) targt = np.array([1, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1])
STEP 1. Find indices of nonzero items of array
and mark the startings of new groups
nonzero_idx - > [ * 0, 1, 2, /,*/, 5, /,7,8,/, */,/, /,13] (cross out slashes)
marker_idx - > [0, 4, 10]
STEP 2. Find starting and ending indices for each group, use np.ufunc.reduceat
starts - > [0, 5, 13]
ends - > [2, 8, 13]
Now, code:
#STEP 1 nonzero = (array != 0) _, marker_idx = np.unique(group[nonzero], return_index = True) nonzero_idx = np.arange(len(array))[nonzero] #STEP 2 starts = np.minimum.reduceat(nonzero_idx, marker_idx) ends = np.maximum.reduceat(nonzero_idx, marker_idx) #STEP 3 values = array[starts] out = np.zeros_like(array) out[starts] = values #check the case we can 't insert the last negative value if ends[-1] + 1 == len(array): out[ends[: -1] + 1] = -values[: -1] else: out[ends + 1] = -values >>> np.cumsum(out) array([1, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1], dtype = int32)
STEP 1. Find indices of nonzero items of array
and mark the startings of new groups
nonzero_idx - > [ * 0, 1, 2, /,*/, 5, /,7,8,/, */,/, /,13] (cross out slashes)
marker_idx - > [0, 4, 10]
STEP 2. Find starting and ending indices for each group, use np.ufunc.reduceat
starts - > [0, 5, 13]
ends - > [2, 8, 13]
STEP 3. Think of an out
array such that np.cumsum(out)
collapses into target
array. Like so:
[1, 0, 0, -1, 0, 2, 0, 0, 0, -2, 0, 0, 0, 1] - > [1, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1]
1
import numpy as np
import pandas as pd
def foo(s):
chk = np.where(s > 0)[0]
start = min(chk)
end = max(chk)
ans = [True
if (start <= ind <= end)
else False
for ind in range(len(s))
]
return ans
pd.Series(array).groupby(group).transform(
lambda x: x.mask(foo(x), x[x > 0].iloc[0])).to_numpy()
# array([1, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1])
2
def split(val, grp):
inds = np.where(np.append(False, grp[1: ] != grp[: -1]))[0]
return np.array_split(val, inds)
def fill(val):
inds = np.where(val > 0)[0]
start, end = min(inds), max(inds)
val[start: end + 1] = val[start]
return val
np.concatenate([fill(x) for x in split(array, group)])
# array([1, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1])